Diff
Added: freeswitch/trunk/libs/freetdm/.gitignore (0 => 17141)
--- freeswitch/trunk/libs/freetdm/.gitignore (rev 0)
+++ freeswitch/trunk/libs/freetdm/.gitignore 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,13 @@
+*.o
+*.lo
+*.so
+*.a
+*.orig
+*.rej
+*.log
+
+Makefile
+config.*
+configure
+libtool
+aclocal.m4
Added: freeswitch/trunk/libs/freetdm/.update (0 => 17141)
--- freeswitch/trunk/libs/freetdm/.update (rev 0)
+++ freeswitch/trunk/libs/freetdm/.update 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1 @@
+Fri Oct 3 17:54:41 EDT 2008
Added: freeswitch/trunk/libs/freetdm/AUTHORS ( => )
Added: freeswitch/trunk/libs/freetdm/ChangeLog
===================================================================
Added: freeswitch/trunk/libs/freetdm/Makefile.am (0 => 17141)
--- freeswitch/trunk/libs/freetdm/Makefile.am (rev 0)
+++ freeswitch/trunk/libs/freetdm/Makefile.am 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,276 @@
+# Copyright (c) 2007, Anthony Minessale II
+# 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.
+
+PREFIX = $(prefix)
+SRC = src
+
+moddir = @modinstdir@
+libdir = @libdir@
+library_includedir = $(PREFIX)/include
+
+INCS = -I$(FT_SRCDIR)/$(SRC)/include -I$(FT_SRCDIR)/$(SRC)/isdn/include
+if HAVE_SCTP
+INCS += -I$(FT_SRCDIR)/$(SRC)/ftmod/ftmod_sangoma_boost
+endif
+MY_CFLAGS = $(INCS) $(FTDM_CFLAGS) -DFTDM_CONFIG_DIR=\"@confdir@\" -DFTDM_MOD_DIR=\"$(moddir)\" @COMP_VENDOR_CFLAGS@ @DEFS@
+COMPILE = $(CC) $(MY_CFLAGS) $(INCS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(COMPILE)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CC) $(MY_CFLAGS) $(LDFLAGS) -o $@
+
+
+#
+# GNU pkgconfig file
+#
+EXTRA_DIST = freetdm.pc.in
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = freetdm.pc
+
+
+#
+# libfreetdm
+#
+libfreetdm_la_SOURCES = \
+$(SRC)/hashtable.c \
+$(SRC)/hashtable_itr.c \
+$(SRC)/ftdm_io.c \
+$(SRC)/ftdm_queue.c \
+$(SRC)/ftdm_config.c \
+$(SRC)/ftdm_callerid.c \
+$(SRC)/fsk.c \
+$(SRC)/uart.c \
+$(SRC)/g711.c \
+$(SRC)/libteletone_detect.c \
+$(SRC)/libteletone_generate.c \
+$(SRC)/ftdm_buffer.c \
+$(SRC)/ftdm_threadmutex.c \
+$(SRC)/ftdm_dso.c
+
+library_include_HEADERS = \
+$(SRC)/include/fsk.h \
+$(SRC)/include/g711.h \
+$(SRC)/include/hashtable.h \
+$(SRC)/include/hashtable_itr.h \
+$(SRC)/include/hashtable_private.h \
+$(SRC)/include/libteletone_detect.h \
+$(SRC)/include/libteletone_generate.h \
+$(SRC)/include/libteletone.h \
+$(SRC)/include/freetdm.h \
+$(SRC)/include/sangoma_tdm_api.h \
+$(SRC)/include/uart.h \
+$(SRC)/include/ftdm_buffer.h \
+$(SRC)/include/ftdm_config.h \
+$(SRC)/include/ftdm_threadmutex.h \
+$(SRC)/include/ftdm_dso.h \
+$(SRC)/include/ftdm_types.h
+
+lib_LTLIBRARIES = libfreetdm.la
+libfreetdm_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+libfreetdm_la_LDFLAGS = -version-info 1:0:0 $(AM_LDFLAGS)
+libfreetdm_la_LIBADD = $(LIBS)
+
+MYLIB = libfreetdm.la
+
+core: libfreetdm.la
+core-install: install-libLTLIBRARIES
+
+#
+# tools & test programs
+#
+noinst_PROGRAMS = testtones detect_tones detect_dtmf testisdn testpri testr2 testanalog testapp testcid
+if HAVE_SCTP
+noinst_PROGRAMS += testboost
+endif
+noinst_PROGRAMS += testsangomaboost
+
+testapp_SOURCES = $(SRC)/testapp.c
+testapp_LDADD = libfreetdm.la
+testapp_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testcid_SOURCES = $(SRC)/testcid.c
+testcid_LDADD = libfreetdm.la
+testcid_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testtones_SOURCES = $(SRC)/testtones.c
+testtones_LDADD = libfreetdm.la
+testtones_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+
+detect_tones_SOURCES = $(SRC)/detect_tones.c
+detect_tones_LDADD = libfreetdm.la
+detect_tones_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+
+detect_dtmf_SOURCES = $(SRC)/detect_dtmf.c
+detect_dtmf_LDADD = libfreetdm.la
+detect_dtmf_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testisdn_SOURCES = $(SRC)/testisdn.c
+testisdn_LDADD = libfreetdm.la
+testisdn_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testpri_SOURCES = $(SRC)/testpri.c
+testpri_LDADD = libfreetdm.la
+testpri_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testr2_SOURCES = $(SRC)/testr2.c
+testr2_LDADD = libfreetdm.la
+testr2_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+
+if HAVE_SCTP
+testboost_SOURCES = $(SRC)/testboost.c
+testboost_LDADD = libfreetdm.la
+testboost_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+endif
+
+testsangomaboost_SOURCES = $(SRC)/testsangomaboost.c
+testsangomaboost_LDADD = libfreetdm.la
+testsangomaboost_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testanalog_SOURCES = $(SRC)/testanalog.c
+testanalog_LDADD = libfreetdm.la
+testanalog_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+
+#
+# ftmod modules
+#
+mod_LTLIBRARIES = ftmod_zt.la ftmod_skel.la ftmod_isdn.la ftmod_analog.la ftmod_analog_em.la
+
+
+if HAVE_SCTP
+mod_LTLIBRARIES += ftmod_sangoma_boost.la
+endif
+
+if LIBSANGOMA
+mod_LTLIBRARIES += ftmod_wanpipe.la
+endif
+
+if LIBPRI
+mod_LTLIBRARIES += ftmod_libpri.la
+endif
+
+if OPENR2
+mod_LTLIBRARIES += ftmod_r2.la
+endif
+
+ftmod_zt_la_SOURCES = $(SRC)/ftmod/ftmod_zt/ftmod_zt.c
+ftmod_zt_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+ftmod_zt_la_LDFLAGS = -module -avoid-version
+ftmod_zt_la_LIBADD = $(MYLIB)
+
+ftmod_skel_la_SOURCES = $(SRC)/ftmod/ftmod_skel/ftmod_skel.c
+ftmod_skel_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+ftmod_skel_la_LDFLAGS = -module -avoid-version
+ftmod_skel_la_LIBADD = $(MYLIB)
+
+if LIBSANGOMA
+ftmod_wanpipe_la_SOURCES = $(SRC)/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
+ftmod_wanpipe_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) -D__LINUX__ -I/usr/include/wanpipe
+ftmod_wanpipe_la_LDFLAGS = -module -avoid-version -lsangoma
+ftmod_wanpipe_la_LIBADD = $(MYLIB)
+endif
+
+ftmod_isdn_la_SOURCES = \
+$(SRC)/isdn/EuroISDNStateNT.c \
+$(SRC)/isdn/EuroISDNStateTE.c \
+$(SRC)/isdn/mfifo.c \
+$(SRC)/isdn/Q921.c \
+$(SRC)/isdn/Q931api.c \
+$(SRC)/isdn/Q931.c \
+$(SRC)/isdn/Q931ie.c \
+$(SRC)/isdn/Q931mes.c \
+$(SRC)/isdn/Q931StateNT.c \
+$(SRC)/isdn/Q931StateTE.c \
+$(SRC)/isdn/nationalmes.c \
+$(SRC)/isdn/nationalStateNT.c \
+$(SRC)/isdn/nationalStateTE.c \
+$(SRC)/isdn/DMSmes.c \
+$(SRC)/isdn/DMSStateNT.c \
+$(SRC)/isdn/DMSStateTE.c \
+$(SRC)/isdn/5ESSmes.c \
+$(SRC)/isdn/5ESSStateNT.c \
+$(SRC)/isdn/5ESSStateTE.c \
+$(SRC)/isdn/Q932mes.c \
+$(SRC)/ftmod/ftmod_isdn/ftmod_isdn.c
+
+ftmod_isdn_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) -D_GNU_SOURCE
+ftmod_isdn_la_LDFLAGS = $(PCAP_LIB_FLAGS) -module -avoid-version
+ftmod_isdn_la_LIBADD = $(MYLIB)
+
+ftmod_analog_la_SOURCES = $(SRC)/ftmod/ftmod_analog/ftmod_analog.c
+ftmod_analog_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+ftmod_analog_la_LDFLAGS = -module -avoid-version
+ftmod_analog_la_LIBADD = $(MYLIB)
+
+ftmod_analog_em_la_SOURCES = $(SRC)/ftmod/ftmod_analog_em/ftmod_analog_em.c
+ftmod_analog_em_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+ftmod_analog_em_la_LDFLAGS = -module -avoid-version
+ftmod_analog_em_la_LIBADD = $(MYLIB)
+
+if HAVE_SCTP
+ftmod_sangoma_boost_la_SOURCES = $(SRC)/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c $(SRC)/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c
+ftmod_sangoma_boost_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+ftmod_sangoma_boost_la_LDFLAGS = -module -avoid-version
+ftmod_sangoma_boost_la_LIBADD = $(MYLIB)
+endif
+
+if LIBPRI
+ftmod_libpri_la_SOURCES = $(SRC)/ftmod/ftmod_libpri/ftmod_libpri.c $(SRC)/ftmod/ftmod_libpri/lpwrap_pri.c
+ftmod_libpri_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+ftmod_libpri_la_LDFLAGS = -module -avoid-version -lpri
+ftmod_libpri_la_LIBADD = $(MYLIB)
+endif
+
+if OPENR2
+ftmod_r2_la_SOURCES = $(SRC)/ftmod/ftmod_r2/ftmod_r2.c
+ftmod_r2_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+ftmod_r2_la_LDFLAGS = -module -avoid-version -lopenr2
+ftmod_r2_la_LIBADD = $(MYLIB)
+endif
+
+
+dox doxygen:
+ cd docs && doxygen $(FT_SRCDIR)/docs/Doxygen.conf
+
+mod_freetdm/mod_freetdm.$(DYNAMIC_LIB_EXTEN): $(MYLIB) mod_freetdm/mod_freetdm.c
+ cd mod_freetdm && make
+
+mod_freetdm: mod_freetdm/mod_freetdm.$(DYNAMIC_LIB_EXTEN)
+
+mod_freetdm-install: mod_freetdm
+ cd mod_freetdm && make install
+
+mod_freetdm-clean:
+ @if [ -f mod_freetdm/mod_freetdm.$(DYNAMIC_LIB_EXTEN) ] ; then cd mod_freetdm && make clean ; fi
+
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(PREFIX)
+ $(mkinstalldirs) $(DESTDIR)@confdir@
+ @[ -f "$(DESTDIR)@confdir@/freetdm.conf" ] || ( cp conf/*.conf $(DESTDIR)@confdir@)
+ @echo OpenFTDM Installed
Added: freeswitch/trunk/libs/freetdm/NEWS ( => )
Added: freeswitch/trunk/libs/freetdm/README
===================================================================
--- freeswitch/trunk/libs/freetdm/README (rev 0)
+++ freeswitch/trunk/libs/freetdm/README 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3 @@
+FREETDM (WORK IN PROGRESS)
+
+*shrug*
Added: freeswitch/trunk/libs/freetdm/TODO (0 => 17141)
--- freeswitch/trunk/libs/freetdm/TODO (rev 0)
+++ freeswitch/trunk/libs/freetdm/TODO 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,9 @@
+== Interface inconsistency ==
+- enum_id member of ftdm_event_t is inconsistent. Most of the time is just for OOB events, the only other
+ type of event as of now is FTDM_EVENT_DTMF and is not using the enum_id member. I think we can get rid
+ of the FTDM_EVENT_DTMF and create ftdm_dtmf_event_t type instead of reusing ftdm_event_t
+ then ftdm_event_t would be renamed to ftdm_oob_event_t and the enum_id renamed to type, then ftdm_span_next_event()
+ will only return OOB events
+
+- query span hw status (connected/disconnected) on startup
+
Added: freeswitch/trunk/libs/freetdm/acinclude.m4 (0 => 17141)
--- freeswitch/trunk/libs/freetdm/acinclude.m4 (rev 0)
+++ freeswitch/trunk/libs/freetdm/acinclude.m4 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1 @@
+m4_include([build/libpcap.m4])
Added: freeswitch/trunk/libs/freetdm/bootstrap (0 => 17141)
--- freeswitch/trunk/libs/freetdm/bootstrap (rev 0)
+++ freeswitch/trunk/libs/freetdm/bootstrap 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,6 @@
+#!/bin/bash
+autoheader
+libtoolize --force --copy
+aclocal
+automake -f --copy --add-missing
+autoconf
Property changes on: freeswitch/trunk/libs/freetdm/bootstrap
___________________________________________________________________
Name: svn:executable
+ *
Added: freeswitch/trunk/libs/freetdm/build/libpcap.m4 (0 => 17141)
--- freeswitch/trunk/libs/freetdm/build/libpcap.m4 (rev 0)
+++ freeswitch/trunk/libs/freetdm/build/libpcap.m4 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,144 @@
+dnl libpcap.m4--PCAP libraries and includes
+dnl Derrick Brashear
+dnl from KTH krb and Arla
+dnl $Id: libpcap.m4,v 1.4 2006/01/20 20:21:09 snsimon Exp $
+
+AC_DEFUN([PCAP_INC_WHERE1], [
+ac_cv_found_pcap_inc=no
+if test -f "$1/pcap.h" ; then
+ ac_cv_found_pcap_inc=yes
+fi
+])
+
+AC_DEFUN([PCAP_INC_WHERE], [
+ for i in $1; do
+ AC_MSG_CHECKING(for pcap header in $i)
+ PCAP_INC_WHERE1($i)
+ if test "$ac_cv_found_pcap_inc" = "yes"; then
+ ac_cv_pcap_where_inc=$i
+ AC_MSG_RESULT(found)
+ break
+ else
+ AC_MSG_RESULT(no found)
+ fi
+ done
+])
+
+AC_DEFUN([PCAP_LIB_WHERE1], [
+saved_LIBS=$LIBS
+LIBS="$saved_LIBS -L$1 -lpcap"
+AC_TRY_LINK(,
+[pcap_lookupdev("");],
+[ac_cv_found_pcap_lib=yes],
+ac_cv_found_pcap_lib=no)
+LIBS=$saved_LIBS
+])
+
+AC_DEFUN([TEST_LIBPATH], [
+changequote(<<, >>)
+define(<<AC_CV_FOUND>>, translit(ac_cv_found_$2_lib, <<- *>>, <<__p>>))
+changequote([, ])
+if test "$AC_CV_FOUND" = "yes"; then
+ if test \! -r "$1/lib$2.a" -a \! -r "$1/lib$2.so" -a \! -r "$1/lib$2.sl" -a \! -r "$1/lib$2.dylib"; then
+ AC_CV_FOUND=no
+ fi
+fi
+])
+
+
+AC_DEFUN([PCAP_LIB_WHERE], [
+ for i in $1; do
+ AC_MSG_CHECKING(for pcap library in $i)
+ PCAP_LIB_WHERE1($i)
+ TEST_LIBPATH($i, pcap)
+ if test "$ac_cv_found_pcap_lib" = "yes" ; then
+ ac_cv_pcap_where_lib=$i
+ AC_MSG_RESULT(found)
+ break
+ else
+ AC_MSG_RESULT(no found)
+ fi
+ done
+])
+
+AC_DEFUN([FIND_LIB_SUBDIR],
+[dnl
+AC_ARG_WITH([lib-subdir], AC_HELP_STRING([--with-lib-subdir=DIR],[Find libraries in DIR instead of lib]))
+AC_CHECK_SIZEOF(long)
+AC_CACHE_CHECK([what directory libraries are found in], [ac_cv_cmu_lib_subdir],
+[test "X$with_lib_subdir" = "Xyes" && with_lib_subdir=
+test "X$with_lib_subdir" = "Xno" && with_lib_subdir=
+ if test "X$with_lib_subdir" = "X" ; then
+ ac_cv_cmu_lib_subdir=lib
+ if test $ac_cv_sizeof_long -eq 4 ; then
+ test -d /usr/lib32 && ac_cv_cmu_lib_subdir=lib32
+ test -r /usr/lib/libpcap.so && ac_cv_cmu_lib_subdir=lib
+ fi
+ if test $ac_cv_sizeof_long -eq 8 ; then
+ test -d /usr/lib64 && ac_cv_cmu_lib_subdir=lib64
+ fi
+ else
+ ac_cv_cmu_lib_subdir=$with_lib_subdir
+ fi])
+ AC_SUBST(LIB_SUBDIR, $ac_cv_cmu_lib_subdir)
+ ])
+
+
+AC_DEFUN([AX_LIB_PCAP], [
+AC_REQUIRE([FIND_LIB_SUBDIR])
+AC_ARG_WITH(pcap,
+ [ --with-pcap=PREFIX Compile with PCAP support],
+ [if test "X$with_pcap" = "X"; then
+ with_pcap=yes
+ fi])
+AC_ARG_WITH(pcap-lib,
+ [ --with-pcap-lib=dir use pcap libraries in dir],
+ [if test "$withval" = "yes" -o "$withval" = "no"; then
+ AC_MSG_ERROR([No argument for --with-pcap-lib])
+ fi])
+AC_ARG_WITH(pcap-include,
+ [ --with-pcap-include=dir use pcap headers in dir],
+ [if test "$withval" = "yes" -o "$withval" = "no"; then
+ AC_MSG_ERROR([No argument for --with-pcap-include])
+ fi])
+
+ if test "X$with_pcap" != "X"; then
+ if test "$with_pcap" != "yes"; then
+ ac_cv_pcap_where_lib=$with_pcap
+ ac_cv_pcap_where_inc=$with_pcap/include
+ fi
+ fi
+
+ if test "X$with_pcap_lib" != "X"; then
+ ac_cv_pcap_where_lib=$with_pcap_lib
+ fi
+ if test "X$ac_cv_pcap_where_lib" = "X"; then
+ PCAP_LIB_WHERE(/usr/$LIB_SUBDIR /usr/local/$LIB_SUBDIR)
+ fi
+
+ if test "X$with_pcap_include" != "X"; then
+ ac_cv_pcap_where_inc=$with_pcap_include
+ fi
+ if test "X$ac_cv_pcap_where_inc" = "X"; then
+ PCAP_INC_WHERE(/usr/ng/include /usr/include /usr/local/include)
+ fi
+
+ AC_MSG_CHECKING(whether to include pcap)
+ if test "X$ac_cv_pcap_where_lib" != "X" -a "X$ac_cv_pcap_where_inc" != "X"; then
+ ac_cv_found_pcap=yes
+ AC_MSG_RESULT(yes)
+ PCAP_INC_DIR=$ac_cv_pcap_where_inc
+ PCAP_LIB_DIR=$ac_cv_pcap_where_lib
+ PCAP_INC_FLAGS="-I${PCAP_INC_DIR}"
+ PCAP_LIB_FLAGS="-L${PCAP_LIB_DIR} -lpcap"
+ AC_SUBST(PCAP_INC_DIR)
+ AC_SUBST(PCAP_LIB_DIR)
+ AC_SUBST(PCAP_INC_FLAGS)
+ AC_SUBST(PCAP_LIB_FLAGS)
+ AC_DEFINE([HAVE_LIBPCAP],[1],[libpcap])
+ else
+ ac_cv_found_pcap=no
+ AC_MSG_RESULT(no)
+ fi
+ ])
+
Added: freeswitch/trunk/libs/freetdm/conf/freetdm.conf (0 => 17141)
--- freeswitch/trunk/libs/freetdm/conf/freetdm.conf (rev 0)
+++ freeswitch/trunk/libs/freetdm/conf/freetdm.conf 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,19 @@
+[span wanpipe]
+name => FreeTDM
+number => 1
+fxs-channel => 1:3-4
+
+[span wanpipe]
+fxo-channel => 1:1-2
+
+[span zt]
+name => FreeTDM
+number => 2
+fxs-channel => 1
+
+[span zt]
+name => FreeTDM
+number => 2
+fxo-channel => 3
+
+
Added: freeswitch/trunk/libs/freetdm/conf/freetdm.conf.xml (0 => 17141)
--- freeswitch/trunk/libs/freetdm/conf/freetdm.conf.xml (rev 0)
+++ freeswitch/trunk/libs/freetdm/conf/freetdm.conf.xml 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,45 @@
+<configuration name="freetdm.conf" description="FreeTDM Configuration">
+ <settings>
+ <param name="debug" value="0"/>
+ <!--<param name="hold-music" value="$${moh_uri}"/>-->
+ <!--<param name="enable-analog-option" value="call-swap"/>-->
+ <!--<param name="enable-analog-option" value="3-way"/>-->
+ </settings>
+ <pri_spans>
+ <span name="PRI_1">
+ <!-- Log Levels: none, alert, crit, err, warning, notice, info, debug -->
+ <param name="q921loglevel" value="alert"/>
+ <param name="q931loglevel" value="alert"/>
+ <param name="mode" value="user"/>
+ <param name="dialect" value="5ess"/>
+ <param name="dialplan" value="XML"/>
+ <param name="context" value="default"/>
+ </span>
+ <span name="PRI_2">
+ <param name="q921loglevel" value="alert"/>
+ <param name="q931loglevel" value="alert"/>
+ <param name="mode" value="user"/>
+ <param name="dialect" value="5ess"/>
+ <param name="dialplan" value="XML"/>
+ <param name="context" value="default"/>
+ </span>
+ </pri_spans>
+ <!-- one entry here per openzap span -->
+ <analog_spans>
+ <span id="1">
+ <!--<param name="hold-music" value="$${moh_uri}"/>-->
+ <!--<param name="enable-analog-option" value="call-swap"/>-->
+ <!--<param name="enable-analog-option" value="3-way"/>-->
+ <param name="tonegroup" value="us"/>
+ <param name="digit-timeout" value="2000"/>
+ <param name="max-digits" value="11"/>
+ <param name="dialplan" value="XML"/>
+ <param name="context" value="default"/>
+ <param name="enable-callerid" value="true"/>
+ <!-- regex to stop dialing when it matches -->
+ <!--<param name="dial-regex" value="5555"/>-->
+ <!-- regex to stop dialing when it does not match -->
+ <!--<param name="fail-dial-regex" value="^5"/>-->
+ </span>
+ </analog_spans>
+</configuration>
Added: freeswitch/trunk/libs/freetdm/conf/m3ua.conf (0 => 17141)
--- freeswitch/trunk/libs/freetdm/conf/m3ua.conf (rev 0)
+++ freeswitch/trunk/libs/freetdm/conf/m3ua.conf 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,38 @@
+;M3UA SS7 Links Config
+;
+;ss7box-m3ua_mode => true
+;local_sctp_ip => localhost
+;local sctp_port => 30000
+;remote_sctp_ip => localhost
+;remote_sctp_port => 30001
+;opc => 0-0-0
+;dpc => 0-0-0
+
+
+; AP Specific Stuff. This will likely move later.
+
+; CNAM Gateways
+cnam1_dpc => 0-0-0
+cnam1_ssn => 253
+cnam2_dpc => 0-0-0
+cnam2_ssn => 253
+cnam3_dpc => 0-0-0
+cnam3_ssn => 253
+
+;LNP Gateways
+lnp1_dpc => 0-0-0
+lnp1_ssn => 253
+lnp2_dpc => 0-0-0
+lnp2_ssn => 253
+lnp3_dpc => 0-0-0
+lnp3_ssn => 253
+
+;LNP Gateways
+sms8001_dpc => 0-0-0
+sms8001_ssn => 253
+sms8002_dpc => 0-0-0
+sms8002_ssn => 253
+sms8003_dpc => 0-0-0
+sms8003_ssn => 253
+
+
Added: freeswitch/trunk/libs/freetdm/conf/pika.conf (0 => 17141)
--- freeswitch/trunk/libs/freetdm/conf/pika.conf (rev 0)
+++ freeswitch/trunk/libs/freetdm/conf/pika.conf 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,41 @@
+; each category is a config profile
+; to apply the profile append it to a channel def in
+; openzap.conf with @<profile_name>
+; e.g.
+; [span pika]
+; name => pika
+; number => pika
+; fxs-channel => 1:0:1-12@default
+
+[default]
+; region is na or eu
+;region => na
+;rx-gain => 0.00
+;rx-agc-enabled => false
+;rx-agc-targetPower => -15.00
+;rx-agc-minGain => -6.00
+;rx-agc-maxGain => 18.00
+;rx-agc-attackRate => 170
+;rx-agc-decayRate => 750
+;rx-agc-speechThreshold => -36.00
+;rx-vad-enabled => false
+;rx-vad-activationThreshold => -40.00
+;rx-vad-activationDebounceTime => 72
+;rx-vad-deactivationThreshold => -40.00
+;rx-vad-deactivationDebounceTime => 984
+;rx-vad-preSpeechBufferSize => 240
+;tx-gain => 0.00
+;tx-agc-enabled => true
+;tx-agc-targetPower => -15.00
+;tx-agc-minGain => -6.00
+;tx-agc-maxGain => 18.00
+;tx-agc-attackRate => 170
+;tx-agc-decayRate => 750
+;tx-agc-speechThreshold => -36.00
+;ec-enabled => false
+;ec-doubleTalkerThreshold => -6.00
+;ec-speechPresentThreshold => -40.00
+;ec-echoSuppressionThreshold => -18.00
+;ec-echoSuppressionEnabled => true
+;ec-comfortNoiseEnabled => true
+;ec-adaptationModeEnabled => true
Added: freeswitch/trunk/libs/freetdm/conf/tones.conf (0 => 17141)
--- freeswitch/trunk/libs/freetdm/conf/tones.conf (rev 0)
+++ freeswitch/trunk/libs/freetdm/conf/tones.conf 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,63 @@
+[us]
+generate-dial => v=-7;%(1000,0,350,440)
+detect-dial => 350,440
+
+generate-ring => v=-7;%(2000,4000,440,480)
+detect-ring => 440,480
+
+generate-busy => v=-7;%(500,500,480,620)
+detect-busy => 480,620
+
+generate-attn => v=0;%(100,100,1400,2060,2450,2600)
+detect-attn => 1400,2060,2450,2600
+
+generate-callwaiting-sas => v=0;%(300,0,440)
+detect-callwaiting-sas => 440
+
+generate-callwaiting-cas => v=0;%(80,0,2750,2130)
+detect-callwaiting-cas => 2750,2130
+
+detect-fail1 => 913.8
+detect-fail2 => 1370.6
+detect-fail3 => 1776.7
+
+
+[sg]
+generate-dial => v=-7;%(1000,0,425)
+detect-dial => 425
+
+generate-ring => v=-7;%(2000,4000,425)
+detect-ring => 425
+
+generate-busy => v=-7;%(750,750,425)
+detect-busy => 425
+
+generate-attn => v=0;%(100,100,1400,2060,2450,2600)
+detect-attn => 1400,2060,2450,2600
+
+generate-callwaiting-sas => v=0;%(300,0,440)
+detect-callwaiting-sas => 440
+
+generate-callwaiting-cas => v=0;%(80,0,2750,2130)
+detect-callwaiting-cas => 2750,2130
+
+detect-fail1 => 913.8
+detect-fail2 => 1370.6
+detect-fail3 => 1776.7
+
+[ru]
+generate-dial => v=-7;%(1000,425)
+detect-dial => 0
+generate-ring => v=-7;%(800,5000,425,0)
+detect-ring => 425,0
+generate-busy => v=-7;%(350,350,425,0)
+detect-busy => 425,0
+generate-attn => v=0;%(100,100,1400,2060,2450,2600)
+detect-attn => 1400,2060,2450,2600
+generate-callwaiting-sas => v=0;%(300,0,440)
+detect-callwaiting-sas => 440,480
+generate-callwaiting-cas => v=0;%(80,0,2750,2130)
+detect-callwaiting-cas => 2750,2130
+detect-fail1 => 913.8
+detect-fail2 => 1370.6
+detect-fail3 => 1776.7
Added: freeswitch/trunk/libs/freetdm/conf/wanpipe.conf (0 => 17141)
--- freeswitch/trunk/libs/freetdm/conf/wanpipe.conf (rev 0)
+++ freeswitch/trunk/libs/freetdm/conf/wanpipe.conf 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,4 @@
+[defaults]
+codec_ms => 20
+wink_ms => 150
+flash_ms => 750
Added: freeswitch/trunk/libs/freetdm/conf/zt.conf (0 => 17141)
--- freeswitch/trunk/libs/freetdm/conf/zt.conf (rev 0)
+++ freeswitch/trunk/libs/freetdm/conf/zt.conf 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,8 @@
+[defaults]
+codec_ms => 20
+wink_ms => 150
+flash_ms => 750
+echo_cancel_level => 64
+rxgain => 0.0
+txgain => 0.0
+
Added: freeswitch/trunk/libs/freetdm/configure.ac (0 => 17141)
--- freeswitch/trunk/libs/freetdm/configure.ac (rev 0)
+++ freeswitch/trunk/libs/freetdm/configure.ac 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,181 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.59)
+AC_INIT([freetdm],[pre-alpha],[bugs@freeswitch.org])
+AC_CONFIG_SRCDIR([src/ftdm_io.c])
+
+AC_CONFIG_AUX_DIR(build)
+AM_INIT_AUTOMAKE(libfreetdm,0.1)
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_MAKE_SET
+AM_PROG_CC_C_O
+
+AC_PREFIX_DEFAULT(/usr/local/freetdm)
+# AC_PREFIX_DEFAULT does not get expanded until too late so we need to do this to use prefix in this script
+if test "x$prefix" = "xNONE" ; then
+ prefix='/usr/local/freetdm'
+fi
+
+# Absolute source/build directory
+FT_SRCDIR=`(cd $srcdir && pwd)`
+ft_builddir=`pwd`
+AC_SUBST(FT_SRCDIR)
+AC_SUBST(ft_builddir)
+
+if test "$sysconfdir" = "\${prefix}/etc" ; then
+ confdir="$prefix/conf"
+else
+ confdir="$sysconfdir"
+fi
+
+AC_SUBST(confdir)
+
+#override some default libtool behavior and invoke AC_PROG_LIBTOOL (see http://lists.gnu.org/archive/html/libtool/2007-03/msg00000.html)
+m4_defun([_LT_AC_LANG_F77_CONFIG], [:])
+m4_defun([_LT_AC_LANG_GCJ_CONFIG], [:])
+m4_defun([_LT_AC_LANG_RC_CONFIG], [:])
+#AM_PROG_CC_C_O
+AC_PROG_LIBTOOL
+AC_PROG_INSTALL
+
+# Check for com;iler type
+AC_DEFUN([AX_COMPILER_VENDOR],
+[
+AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor,
+ [ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=unknown
+ # note: don't check for GCC first, since some other compilers define __GNUC__
+ for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do
+ vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")"
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[
+#if !($vencpp)
+ thisisanerror;
+#endif
+])], [ax_cv_]_AC_LANG_ABBREV[_compiler_vendor=`echo $ventest | cut -d: -f1`; break])
+ done
+ ])
+])
+AC_ARG_ENABLE([enable_64], [AS_HELP_STRING([--enable-64], [Enable 64bit compilation])], [enable_64="$enableval"], [enable_64="no"])
+
+AX_COMPILER_VENDOR
+
+case "${ax_cv_c_compiler_vendor}" in
+gnu)
+ COMP_VENDOR_CFLAGS="-ffast-math -Wall -Werror -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -O0"
+ ;;
+sun)
+ COMP_VENDOR_CFLAGS="-xc99=all -mt -xCC -D__FUNCTION__=__func__ -xvpara"
+ if test "$enable_64" = "yes" ; then
+ COMP_VENDOR_CFLAGS="-m64 $COMP_VENDOR_CFLAGS"
+ fi
+ ;;
+*)
+ COMP_VENDOR_CFLAGS="-std=c99 -Wall -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes"
+ ;;
+esac
+
+
+#set SOLINK variable based on compiler and host
+if test "x${ax_cv_c_compiler_vendor}" = "xsun" ; then
+ SOLINK="-Bdynamic -dy -G"
+elif test "x${ax_cv_c_compiler_vendor}" = "xgnu" ; then
+ case "$host" in
+ *darwin*)
+ SOLINK="-dynamic -bundle -force-flat-namespace"
+ ;;
+ *-solaris2*)
+ SOLINK="-shared -Xlinker"
+ ;;
+ *)
+ SOLINK="-shared -Xlinker -x"
+ ;;
+ esac
+else
+ AC_ERROR([Please update configure.in with SOLINK values for your compiler])
+fi
+
+# set DYNAMIC_LIB_EXTEN
+# we should really be using libtool so we don't need to do this
+case "$host" in
+ *cygwin* | *mingw*)
+ DYNAMIC_LIB_EXTEN="dll"
+ ;;
+ *)
+ DYNAMIC_LIB_EXTEN="so"
+ ;;
+esac
+
+AC_SUBST(SOLINK)
+AC_SUBST(DYNAMIC_LIB_EXTEN)
+
+AC_CHECK_LIB([dl], [dlopen])
+AC_CHECK_LIB([pthread], [pthread_create])
+AC_CHECK_LIB([m], [cos])
+AX_LIB_PCAP
+
+AC_CHECK_HEADERS([netinet/sctp.h netdb.h sys/select.h])
+AM_CONDITIONAL([HAVE_SCTP],[test "${ac_cv_header_netinet_sctp_h}" = "yes"])
+
+AC_CHECK_FUNC([gethostbyname_r],
+ [], [AC_CHECK_LIB([nsl], [gethostbyname_r])]
+)
+if test "$ac_cv_func_gethostbyname_r" = "yes" -o "$ac_cv_lib_nsl_gethostbyname_r" = "yes" ; then
+
+AC_MSG_CHECKING([whether gethostbyname_r requires five arguments])
+
+ac_cv_func_gethostbyname_r_five_args="no"
+
+AC_TRY_COMPILE([#include <netdb.h>],
+ [char *name;
+ struct hostent *he, *res;
+ char buffer[2048];
+ int buflen = 2048;
+ (void)gethostbyname_r(name, he, buffer, buflen, &res)],
+ [ac_cv_func_gethostbyname_r_five_args="yes"
+ AC_DEFINE([HAVE_GETHOSTBYNAME_R_FIVE], [1], [gethostbyname_r has five arguments])]
+)
+
+ AC_MSG_RESULT([$ac_cv_func_gethostbyname_r_five_args])
+ AC_DEFINE([HAVE_GETHOSTBYNAME_R],[1],[threadsafe gethostbyname])
+fi
+
+# Enable debugging
+AC_ARG_ENABLE(debug,
+[AC_HELP_STRING([--enable-debug],[build with debug information])],[enable_debug="$enableval"],[enable_debug="yes"])
+
+if test "${enable_debug}" = "yes"; then
+ AC_DEFINE([DEBUG],[],[Enable extra debugging.])
+
+ if test "x${ax_cv_c_compiler_vendor}" = "xgnu" ; then
+ COMP_VENDOR_CFLAGS="$COMP_VENDOR_CFLAGS -g -ggdb"
+ fi
+fi
+
+# Where to install the modules
+AC_ARG_WITH([modinstdir],
+ [AS_HELP_STRING([--with-modinstdir=DIR], [Install modules into this location (default: $prefix/mod)])], [modinstdir="$withval"], [modinstdir="${prefix}/mod"])
+
+AC_SUBST(modinstdir)
+
+
+# libpri?
+AC_ARG_WITH([libpri],
+ [AS_HELP_STRING([--with-libpri], [Install ftmod_libpri])], [enable_libpri="yes"], [enable_libpri="no"])
+AC_SUBST(enable_libpri)
+
+AC_CHECK_LIB([sangoma], [sangoma_span_chan_toif], [have_libsangoma="yes"])
+AM_CONDITIONAL([LIBSANGOMA],[test "${have_libsangoma}" = "yes"])
+
+AM_CONDITIONAL([LIBPRI],[test "${enable_libpri}" = "yes"])
+
+AC_CHECK_LIB([openr2], [openr2_context_set_io_type], [have_openr2="yes"])
+AM_CONDITIONAL([OPENR2],[test "${have_openr2}" = "yes"])
+
+COMP_VENDOR_CFLAGS="$COMP_VENDOR_CFLAGS"
+AC_SUBST(COMP_VENDOR_CFLAGS)
+AC_CONFIG_FILES([Makefile
+ freetdm.pc
+ mod_freetdm/Makefile])
+AC_OUTPUT
Added: freeswitch/trunk/libs/freetdm/configure.gnu (0 => 17141)
--- freeswitch/trunk/libs/freetdm/configure.gnu (rev 0)
+++ freeswitch/trunk/libs/freetdm/configure.gnu 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3 @@
+#! /bin/sh
+./configure "$@" --with-pic
+
Added: freeswitch/trunk/libs/freetdm/cyginstall.sh (0 => 17141)
--- freeswitch/trunk/libs/freetdm/cyginstall.sh (rev 0)
+++ freeswitch/trunk/libs/freetdm/cyginstall.sh 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,11 @@
+#!/bin/bash
+# this script must be run from openzap root dir and it is assuming
+# FreeSWITCH is trunk is located at ../../
+fsdir=../..
+set -x
+cp Debug/*.dll $fsdir/Debug/
+cp Debug/mod/*.dll $fsdir/Debug/mod/
+cp Debug/*.pdb $fsdir/Debug/
+echo "FRIENDLY REMINDER: RECOMPILE ftmod_wanpipe WHENEVER YOU INSTALL NEW DRIVERS"
+set +x
+
Added: freeswitch/trunk/libs/freetdm/docs/Doxygen.conf (0 => 17141)
--- freeswitch/trunk/libs/freetdm/docs/Doxygen.conf (rev 0)
+++ freeswitch/trunk/libs/freetdm/docs/Doxygen.conf 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,277 @@
+# Doxyfile 1.4.6
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = OpenZAP
+PROJECT_NUMBER =
+OUTPUT_DIRECTORY = .
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = YES
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = NO
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+DISTRIBUTE_GROUP_DOC = NO
+SUBGROUPING = YES
+IGNORE_PREFIX = zap_ ZAP_ Q921 Q931
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = YES
+EXTRACT_STATIC = YES
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = YES
+HIDE_UNDOC_MEMBERS = YES
+HIDE_UNDOC_CLASSES = YES
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = NO
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = YES
+FILE_VERSION_FILTER =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = ../src ../src/include \
+ ../src/isdn ../src/isdn/include \
+ ../mod_openzap ../ \
+ ../src/ozmod \
+ ../src/ozmod/ozmod_analog \
+ ../src/ozmod/ozmod_analog_em \
+ ../src/ozmod/ozmod_isdn \
+ ../src/ozmod/ozmod_pika \
+ ../src/ozmod/ozmod_skel \
+ ../src/ozmod/ozmod_ss7_boost \
+ ../src/ozmod/ozmod_wanpipe \
+ ../src/ozmod/ozmod_zt
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.d \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.idl \
+ *.odl \
+ *.cs \
+ *.php \
+ *.php3 \
+ *.inc \
+ *.m \
+ *.mm \
+ *.dox \
+ *.py
+RECURSIVE = NO
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = YES
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+USE_HTAGS = YES
+VERBATIM_HEADERS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 1
+IGNORE_PREFIX = zap_
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE = freeswitch.chm
+HHC_LOCATION =
+GENERATE_CHI = YES
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = YES
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = YES
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = NO
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS = *.h
+PREDEFINED = ZAP_DECLARE(x)=x \
+ APR_DECLARE(x)=x \
+ ZAP_MOD_DECLARE(x)=x \
+ DoxyDefine(x)=x
+
+EXPAND_AS_DEFINED = NO
+SKIP_FUNCTION_MACROS = NO
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = YES
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = YES
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = YES
+TEMPLATE_RELATIONS = YES
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = YES
+DOT_IMAGE_FORMAT = jpg
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 1000
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
Added: freeswitch/trunk/libs/freetdm/freetdm.2008.sln (0 => 17141)
--- freeswitch/trunk/libs/freetdm/freetdm.2008.sln (rev 0)
+++ freeswitch/trunk/libs/freetdm/freetdm.2008.sln 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,112 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "freetdm", "msvc\freetdm.2008.vcproj", "{93B8812C-3EC4-4F78-8970-FFBFC99E167D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testanalog", "msvc\testanalog\testanalog.2008.vcproj", "{BB833648-BAFF-4BE2-94DB-F8BB043C588C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testisdn", "msvc\testisdn\testisdn.2008.vcproj", "{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_freetdm", "mod_freetdm\mod_freetdm.2008.vcproj", "{FE3540C5-3303-46E0-A69E-D92F775687F1}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_analog", "src\ftmod\ftmod_analog\ftmod_analog.2008.vcproj", "{37C94798-6E33-4B4F-8EE0-C72A7DC91157}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_analog_em", "src\ftmod\ftmod_analog_em\ftmod_analog_em.2008.vcproj", "{B3F49375-2834-4937-9D8C-4AC2EC911010}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_isdn", "src\ftmod\ftmod_isdn\ftmod_isdn.2008.vcproj", "{729344A5-D5E9-434D-8EE8-AF8C6C795D15}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_pika", "src\ftmod\ftmod_pika\ftmod_pika.2008.vcproj", "{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_wanpipe", "src\ftmod\ftmod_wanpipe\ftmod_wanpipe.2008.vcproj", "{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_sangoma_boost", "src\ftmod\ftmod_sangoma_boost\ftmod_sangoma_boost.2008.vcproj", "{D021EF2A-460D-4827-A0F7-41FDECF46F1B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testboost", "msvc\testboost\testboost.2008.vcproj", "{2B1BAF36-0241-43E7-B865-A8338AD48E2E}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testsangomaboost", "msvc\testboost\testsangomaboost.2008.vcproj", "{0DA69C18-4FA1-4E8C-89CE-12498637C5BE}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.Build.0 = Debug|Win32
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.ActiveCfg = Release|Win32
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.Build.0 = Release|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.Build.0 = Debug|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.ActiveCfg = Release|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.Build.0 = Release|Win32
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.Build.0 = Debug|Win32
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.ActiveCfg = Release|Win32
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.Build.0 = Release|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.Build.0 = Debug|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.ActiveCfg = Release|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.Build.0 = Release|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.ActiveCfg = Debug|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.Build.0 = Debug|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.ActiveCfg = Release|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.Build.0 = Release|Win32
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|Win32.Build.0 = Debug|Win32
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|Win32.ActiveCfg = Release|Win32
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|Win32.Build.0 = Release|Win32
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.ActiveCfg = Debug|Win32
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.Build.0 = Debug|Win32
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.ActiveCfg = Release|Win32
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.Build.0 = Release|Win32
+ {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Release|Win32.ActiveCfg = Release|Win32
+ {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|Win32.ActiveCfg = Release|Win32
+ {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|Win32.Build.0 = Debug|Win32
+ {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|Win32.ActiveCfg = Release|Win32
+ {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|Win32.Build.0 = Release|Win32
+ {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|Win32.Build.0 = Debug|Win32
+ {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|Win32.ActiveCfg = Release|Win32
+ {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|Win32.Build.0 = Release|Win32
+ {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|Win32.Build.0 = Debug|Win32
+ {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|Win32.ActiveCfg = Release|Win32
+ {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
Added: freeswitch/trunk/libs/freetdm/freetdm.pc.in (0 => 17141)
--- freeswitch/trunk/libs/freetdm/freetdm.pc.in (rev 0)
+++ freeswitch/trunk/libs/freetdm/freetdm.pc.in 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,17 @@
+#
+# OpenZAP pkg-config file
+#
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: OpenZAP
+Description:
+Version: @PACKAGE_VERSION@
+URL: http://www.openzap.org/
+Requires:
+Conflicts:
+Libs: -L${libdir} -lopenzap
+Libs.private: -lm
+Cflags: -I${includedir}
Added: freeswitch/trunk/libs/freetdm/mod_freetdm/Makefile.in (0 => 17141)
--- freeswitch/trunk/libs/freetdm/mod_freetdm/Makefile.in (rev 0)
+++ freeswitch/trunk/libs/freetdm/mod_freetdm/Makefile.in 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,23 @@
+FT_CFLAGS=@CFLAGS@ @COMP_VENDOR_CFLAGS@ @DEFS@
+
+BASE=../../..
+FT_DIR=..
+VERBOSE=1
+FTLA=$(FT_DIR)/libfreetdm.la
+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
+
+local_depend: $(FTLA)
+
+$(FTLA): $(FT_DIR)/.update
+ cd $(FT_DIR) && $(MAKE)
+
+local_install:
+ cd $(FT_DIR) && $(MAKE) install
+ [ -f $(DESTDIR)@confdir@/autoload_configs/freetdm.conf.xml ] || cp -f $(FT_DIR)/conf/freetdm.conf.xml $(DESTDIR)@confdir@/autoload_configs
+
+local_clean:
+ cd $(FT_DIR) && $(MAKE) clean
+
+
Added: freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,369 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="mod_freetdm"
+ ProjectGUID="{FE3540C5-3303-46E0-A69E-D92F775687F1}"
+ RootNamespace="mod_freetdm"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="FreeSwitchCore.lib"
+ OutputFile="$(SolutionDir)$(OutDir)/mod/mod_freetdm.dll"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=""../../../w32/Library/$(OutDir)""
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+ SubSystem="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ ImportLibrary="$(OutDir)/mod_freetdm.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="FreeSwitchCore.lib"
+ OutputFile="$(SolutionDir)$(OutDir)/mod/mod_freetdm.dll"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories=""../../../w32/Library/$(OutDir)""
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ LinkTimeCodeGeneration="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ ImportLibrary="$(OutDir)/mod_freetdm.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="FreeSwitchCore.lib"
+ OutputFile="$(SolutionDir)$(OutDir)/mod/mod_freetdm.dll"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=""../../../w32/Library/$(OutDir)""
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+ SubSystem="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ ImportLibrary="$(OutDir)/mod_freetdm.lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="FreeSwitchCore.lib"
+ OutputFile="$(SolutionDir)$(OutDir)/mod/mod_freetdm.dll"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories=""../../../w32/Library/$(OutDir)""
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ LinkTimeCodeGeneration="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ ImportLibrary="$(OutDir)/mod_freetdm.lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\mod_freetdm.c"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3193 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mftilla 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.mftilla.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 <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Moises Silva <moy@sangoma.com>
+ *
+ *
+ * mod_freetdm.c -- FreeTDM Endpoint Module
+ *
+ */
+#include <switch.h>
+#include "freetdm.h"
+
+#ifndef __FUNCTION__
+#define __FUNCTION__ __SWITCH_FUNC__
+#endif
+
+#define FREETDM_VAR_PREFIX "freetdm_"
+#define FREETDM_VAR_PREFIX_LEN 8
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_freetdm_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_freetdm_shutdown);
+SWITCH_MODULE_DEFINITION(mod_freetdm, mod_freetdm_load, mod_freetdm_shutdown, NULL);
+
+switch_endpoint_interface_t *freetdm_endpoint_interface;
+
+static switch_memory_pool_t *module_pool = NULL;
+
+typedef enum {
+ ANALOG_OPTION_NONE = 0,
+ ANALOG_OPTION_3WAY = (1 << 0),
+ ANALOG_OPTION_CALL_SWAP = (1 << 1)
+} analog_option_t;
+
+struct span_config {
+ ftdm_span_t *span;
+ char dialplan[80];
+ char context[80];
+ char dial_regex[256];
+ char fail_dial_regex[256];
+ char hold_music[256];
+ char type[256];
+ analog_option_t analog_options;
+};
+
+static struct span_config SPAN_CONFIG[FTDM_MAX_SPANS_INTERFACE] = {{0}};
+
+typedef enum {
+ TFLAG_IO = (1 << 0),
+ TFLAG_DTMF = (1 << 1),
+ TFLAG_CODEC = (1 << 2),
+ TFLAG_BREAK = (1 << 3),
+ TFLAG_HOLD = (1 << 4),
+ TFLAG_DEAD = (1 << 5)
+} TFLAGS;
+
+static struct {
+ int debug;
+ char *dialplan;
+ char *codec_string;
+ char *codec_order[SWITCH_MAX_CODECS];
+ int codec_order_last;
+ char *codec_rates_string;
+ char *codec_rates[SWITCH_MAX_CODECS];
+ int codec_rates_last;
+ unsigned int flags;
+ int fd;
+ int calls;
+ char hold_music[256];
+ switch_mutex_t *mutex;
+ analog_option_t analog_options;
+} globals;
+
+struct private_object {
+ unsigned int flags;
+ switch_codec_t read_codec;
+ switch_codec_t write_codec;
+ switch_frame_t read_frame;
+ unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
+ switch_frame_t cng_frame;
+ unsigned char cng_databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
+ switch_core_session_t *session;
+ switch_caller_profile_t *caller_profile;
+ unsigned int codec;
+ unsigned int codecs;
+ unsigned short samprate;
+ switch_mutex_t *mutex;
+ switch_mutex_t *flag_mutex;
+ ftdm_channel_t *ftdmchan;
+ uint32_t wr_error;
+};
+
+typedef struct private_object private_t;
+
+
+static switch_status_t channel_on_init(switch_core_session_t *session);
+static switch_status_t channel_on_hangup(switch_core_session_t *session);
+static switch_status_t channel_on_destroy(switch_core_session_t *session);
+static switch_status_t channel_on_routing(switch_core_session_t *session);
+static switch_status_t channel_on_exchange_media(switch_core_session_t *session);
+static switch_status_t channel_on_soft_execute(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_kill_channel(switch_core_session_t *session, int sig);
+ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session_t **sp);
+void dump_chan(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream);
+void dump_chan_xml(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream);
+
+static switch_core_session_t *ftdm_channel_get_session(ftdm_channel_t *channel, int32_t id)
+{
+ switch_core_session_t *session = NULL;
+
+ if (id > FTDM_MAX_TOKENS) {
+ return NULL;
+ }
+
+ if (!zstr(channel->tokens[id])) {
+ if (!(session = switch_core_session_locate(channel->tokens[id]))) {
+ ftdm_channel_clear_token(channel, channel->tokens[id]);
+ }
+ }
+
+ return session;
+}
+
+static const char *ftdm_channel_get_uuid(ftdm_channel_t *channel, int32_t id)
+{
+ if (id > FTDM_MAX_TOKENS) {
+ return NULL;
+ }
+
+ if (!zstr(channel->tokens[id])) {
+ return channel->tokens[id];
+ }
+ return NULL;
+}
+
+static void stop_hold(switch_core_session_t *session_a, const char *uuid)
+{
+ switch_core_session_t *session;
+ switch_channel_t *channel, *channel_a;
+ ;
+
+ if (!uuid) {
+ return;
+ }
+
+ if ((session = switch_core_session_locate(uuid))) {
+ channel = switch_core_session_get_channel(session);
+
+ if (switch_channel_test_flag(channel, CF_HOLD)) {
+ channel_a = switch_core_session_get_channel(session_a);
+ switch_ivr_unhold(session);
+ switch_channel_clear_flag(channel_a, CF_SUSPEND);
+ switch_channel_clear_flag(channel_a, CF_HOLD);
+ } else {
+ switch_channel_stop_broadcast(channel);
+ switch_channel_wait_for_flag(channel, CF_BROADCAST, SWITCH_FALSE, 2000, NULL);
+ }
+
+ switch_core_session_rwunlock(session);
+ }
+}
+
+static void start_hold(ftdm_channel_t *ftdmchan, switch_core_session_t *session_a, const char *uuid, const char *stream)
+{
+ switch_core_session_t *session;
+ switch_channel_t *channel, *channel_a;
+
+ if (!uuid) {
+ return;
+ }
+
+
+ if ((session = switch_core_session_locate(uuid))) {
+ channel = switch_core_session_get_channel(session);
+ if (zstr(stream)) {
+ if (!strcasecmp(globals.hold_music, "indicate_hold")) {
+ stream = "indicate_hold";
+ }
+ if (!strcasecmp(SPAN_CONFIG[ftdmchan->span->span_id].hold_music, "indicate_hold")) {
+ stream = "indicate_hold";
+ }
+ }
+
+ if (zstr(stream)) {
+ stream = switch_channel_get_variable(channel, SWITCH_HOLD_MUSIC_VARIABLE);
+ }
+
+ if (zstr(stream)) {
+ stream = SPAN_CONFIG[ftdmchan->span->span_id].hold_music;
+ }
+
+ if (zstr(stream)) {
+ stream = globals.hold_music;
+ }
+
+
+ if (zstr(stream) && !(stream = switch_channel_get_variable(channel, SWITCH_HOLD_MUSIC_VARIABLE))) {
+ stream = globals.hold_music;
+ }
+
+ if (!zstr(stream)) {
+ if (!strcasecmp(stream, "indicate_hold")) {
+ channel_a = switch_core_session_get_channel(session_a);
+ switch_ivr_hold_uuid(uuid, NULL, 0);
+ switch_channel_set_flag(channel_a, CF_SUSPEND);
+ switch_channel_set_flag(channel_a, CF_HOLD);
+ } else {
+ switch_ivr_broadcast(switch_core_session_get_uuid(session), stream, SMF_ECHO_ALEG | SMF_LOOP);
+ }
+ }
+
+ switch_core_session_rwunlock(session);
+ }
+}
+
+
+static void cycle_foreground(ftdm_channel_t *ftdmchan, int flash, const char *bcast) {
+ uint32_t i = 0;
+ switch_core_session_t *session;
+ switch_channel_t *channel;
+ private_t *tech_pvt;
+
+
+ for (i = 0; i < ftdmchan->token_count; i++) {
+ if ((session = ftdm_channel_get_session(ftdmchan, i))) {
+ const char *buuid;
+ tech_pvt = switch_core_session_get_private(session);
+ channel = switch_core_session_get_channel(session);
+ buuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
+
+
+ if (ftdmchan->token_count == 1 && flash) {
+ if (switch_test_flag(tech_pvt, TFLAG_HOLD)) {
+ stop_hold(session, buuid);
+ switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+ } else {
+ start_hold(ftdmchan, session, buuid, bcast);
+ switch_set_flag_locked(tech_pvt, TFLAG_HOLD);
+ }
+ } else if (i) {
+ start_hold(ftdmchan, session, buuid, bcast);
+ switch_set_flag_locked(tech_pvt, TFLAG_HOLD);
+ } else {
+ stop_hold(session, buuid);
+ switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+ if (!switch_channel_test_flag(channel, CF_ANSWERED)) {
+ switch_channel_mark_answered(channel);
+ }
+ }
+ switch_core_session_rwunlock(session);
+ }
+ }
+}
+
+
+
+
+static switch_status_t tech_init(private_t *tech_pvt, switch_core_session_t *session, ftdm_channel_t *ftdmchan)
+{
+ const char *dname = NULL;
+ uint32_t interval = 0, srate = 8000;
+ ftdm_codec_t codec;
+
+ tech_pvt->ftdmchan = ftdmchan;
+ tech_pvt->read_frame.data = tech_pvt->databuf;
+ tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf);
+ tech_pvt->cng_frame.data = tech_pvt->cng_databuf;
+ tech_pvt->cng_frame.buflen = sizeof(tech_pvt->cng_databuf);
+ tech_pvt->cng_frame.flags = SFF_CNG;
+ tech_pvt->cng_frame.codec = &tech_pvt->read_codec;
+ memset(tech_pvt->cng_frame.data, 255, tech_pvt->cng_frame.buflen);
+ switch_mutex_init(&tech_pvt->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+ switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+ switch_core_session_set_private(session, tech_pvt);
+ tech_pvt->session = session;
+
+ if (FTDM_SUCCESS != ftdm_channel_command(ftdmchan, 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(ftdmchan, FTDM_COMMAND_GET_CODEC, &codec)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to retrieve channel codec.\n");
+ return SWITCH_STATUS_GENERR;
+ }
+
+ switch(codec) {
+ case FTDM_CODEC_ULAW:
+ {
+ dname = "PCMU";
+ }
+ break;
+ case FTDM_CODEC_ALAW:
+ {
+ dname = "PCMA";
+ }
+ break;
+ case FTDM_CODEC_SLIN:
+ {
+ dname = "L16";
+ }
+ break;
+ default:
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid codec value retrieved from channel, codec value: %d\n", codec);
+ return SWITCH_STATUS_GENERR;
+ }
+ }
+
+
+ if (switch_core_codec_init(&tech_pvt->read_codec,
+ dname,
+ NULL,
+ srate,
+ 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");
+ return SWITCH_STATUS_GENERR;
+ } else {
+ if (switch_core_codec_init(&tech_pvt->write_codec,
+ dname,
+ NULL,
+ srate,
+ 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);
+ return SWITCH_STATUS_GENERR;
+ }
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set codec %s %dms\n", dname, interval);
+ switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec);
+ switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec);
+ switch_set_flag_locked(tech_pvt, TFLAG_CODEC);
+ tech_pvt->read_frame.codec = &tech_pvt->read_codec;
+ switch_set_flag_locked(tech_pvt, TFLAG_IO);
+
+ return SWITCH_STATUS_SUCCESS;
+
+}
+
+static switch_status_t channel_on_init(switch_core_session_t *session)
+{
+ switch_channel_t *channel;
+ private_t *tech_pvt = NULL;
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ /* Move channel's state machine to ROUTING */
+ switch_channel_set_state(channel, CS_ROUTING);
+ switch_mutex_lock(globals.mutex);
+ globals.calls++;
+ switch_mutex_unlock(globals.mutex);
+
+ ftdm_channel_init(tech_pvt->ftdmchan);
+
+ //switch_channel_set_flag(channel, CF_ACCEPT_CNG);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_routing(switch_core_session_t *session)
+{
+ switch_channel_t *channel = NULL;
+ private_t *tech_pvt = NULL;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n", switch_channel_get_name(channel));
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_execute(switch_core_session_t *session)
+{
+
+ switch_channel_t *channel = NULL;
+ private_t *tech_pvt = NULL;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL EXECUTE\n", switch_channel_get_name(channel));
+
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_destroy(switch_core_session_t *session)
+{
+ private_t *tech_pvt = NULL;
+
+ if ((tech_pvt = switch_core_session_get_private(session))) {
+
+ if (tech_pvt->read_codec.implementation) {
+ switch_core_codec_destroy(&tech_pvt->read_codec);
+ }
+
+ if (tech_pvt->write_codec.implementation) {
+ switch_core_codec_destroy(&tech_pvt->write_codec);
+ }
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_hangup(switch_core_session_t *session)
+{
+ switch_channel_t *channel = NULL;
+ private_t *tech_pvt = NULL;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ if (!tech_pvt->ftdmchan) {
+ goto end;
+ }
+
+ ftdm_channel_clear_token(tech_pvt->ftdmchan, switch_core_session_get_uuid(session));
+
+ switch (tech_pvt->ftdmchan->type) {
+ case FTDM_CHAN_TYPE_FXO:
+ case FTDM_CHAN_TYPE_EM:
+ case FTDM_CHAN_TYPE_CAS:
+ {
+ ftdm_set_state_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ break;
+ case FTDM_CHAN_TYPE_FXS:
+ {
+ if (tech_pvt->ftdmchan->state != FTDM_CHANNEL_STATE_BUSY && tech_pvt->ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) {
+ if (tech_pvt->ftdmchan->token_count) {
+ cycle_foreground(tech_pvt->ftdmchan, 0, NULL);
+ } else {
+ ftdm_set_state_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ }
+ }
+ break;
+ case FTDM_CHAN_TYPE_B:
+ {
+ if (tech_pvt->ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) {
+ if (tech_pvt->ftdmchan->state != FTDM_CHANNEL_STATE_TERMINATING) {
+ tech_pvt->ftdmchan->caller_data.hangup_cause = switch_channel_get_cause_q850(channel);
+ if (tech_pvt->ftdmchan->caller_data.hangup_cause < 1 || tech_pvt->ftdmchan->caller_data.hangup_cause > 127) {
+ tech_pvt->ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER;
+ }
+ }
+ ftdm_set_state_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ }
+ break;
+ default:
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Unhandled channel type %d for channel %s\n", tech_pvt->ftdmchan->type,
+ switch_channel_get_name(channel));
+ }
+ break;
+ }
+
+ end:
+
+ switch_clear_flag_locked(tech_pvt, TFLAG_IO);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel));
+ switch_mutex_lock(globals.mutex);
+ globals.calls--;
+ if (globals.calls < 0) {
+ globals.calls = 0;
+ }
+ switch_mutex_unlock(globals.mutex);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig)
+{
+ switch_channel_t *channel = NULL;
+ private_t *tech_pvt = NULL;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ switch (sig) {
+ case SWITCH_SIG_KILL:
+ switch_clear_flag_locked(tech_pvt, TFLAG_IO);
+ switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+ break;
+ case SWITCH_SIG_BREAK:
+ switch_set_flag_locked(tech_pvt, TFLAG_BREAK);
+ break;
+ default:
+ break;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_exchange_media(switch_core_session_t *session)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CHANNEL EXCHANGE_MEDIA\n");
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_soft_execute(switch_core_session_t *session)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CHANNEL SOFT_EXECUTE\n");
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf)
+{
+ private_t *tech_pvt = NULL;
+ char tmp[2] = "";
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ switch_channel_hangup(switch_core_session_get_channel(session), SWITCH_CAUSE_LOSE_RACE);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ tmp[0] = dtmf->digit;
+ ftdm_channel_command(tech_pvt->ftdmchan, FTDM_COMMAND_SEND_DTMF, tmp);
+
+ 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)
+{
+ switch_channel_t *channel = NULL;
+ private_t *tech_pvt = NULL;
+ ftdm_size_t len;
+ ftdm_wait_flag_t wflags = FTDM_READ;
+ char dtmf[128] = "";
+ ftdm_status_t status;
+ int total_to;
+ int chunk, do_break = 0;
+
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ /* Digium Cards sometimes timeout several times in a row here.
+ Yes, we support digium cards, ain't we nice.......
+ 6 double length intervals should compensate */
+ chunk = tech_pvt->ftdmchan->effective_interval * 2;
+ total_to = chunk * 6;
+
+ top:
+
+ if (switch_channel_test_flag(channel, CF_SUSPEND)) {
+ do_break = 1;
+ }
+
+ if (switch_test_flag(tech_pvt, TFLAG_BREAK)) {
+ switch_clear_flag_locked(tech_pvt, TFLAG_BREAK);
+ do_break = 1;
+ }
+
+ if (switch_test_flag(tech_pvt, TFLAG_HOLD) || do_break) {
+ switch_yield(tech_pvt->ftdmchan->effective_interval * 1000);
+ tech_pvt->cng_frame.datalen = tech_pvt->ftdmchan->packet_len;
+ tech_pvt->cng_frame.samples = tech_pvt->cng_frame.datalen;
+ tech_pvt->cng_frame.flags = SFF_CNG;
+ *frame = &tech_pvt->cng_frame;
+ if (tech_pvt->ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+ tech_pvt->cng_frame.samples /= 2;
+ }
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
+ goto fail;
+ }
+
+ wflags = FTDM_READ;
+ status = ftdm_channel_wait(tech_pvt->ftdmchan, &wflags, chunk);
+
+ if (status == FTDM_FAIL) {
+ goto fail;
+ }
+
+ if (status == FTDM_TIMEOUT) {
+ if (!switch_test_flag(tech_pvt, TFLAG_HOLD)) {
+ total_to -= chunk;
+ if (total_to <= 0) {
+ goto fail;
+ }
+ }
+
+ goto top;
+ }
+
+ if (!(wflags & FTDM_READ)) {
+ goto fail;
+ }
+
+ len = tech_pvt->read_frame.buflen;
+ if (ftdm_channel_read(tech_pvt->ftdmchan, tech_pvt->read_frame.data, &len) != FTDM_SUCCESS) {
+ goto fail;
+ }
+
+ *frame = &tech_pvt->read_frame;
+ tech_pvt->read_frame.datalen = (uint32_t)len;
+ tech_pvt->read_frame.samples = tech_pvt->read_frame.datalen;
+
+ if (tech_pvt->ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+ tech_pvt->read_frame.samples /= 2;
+ }
+
+ while (ftdm_channel_dequeue_dtmf(tech_pvt->ftdmchan, dtmf, sizeof(dtmf))) {
+ switch_dtmf_t _dtmf = { 0, SWITCH_DEFAULT_DTMF_DURATION };
+ char *p;
+ for (p = dtmf; p && *p; p++) {
+ if (is_dtmf(*p)) {
+ _dtmf.digit = *p;
+ ftdm_log(FTDM_LOG_DEBUG, "queue DTMF [%c]\n", *p);
+ switch_channel_queue_dtmf(channel, &_dtmf);
+ }
+ }
+ }
+ return SWITCH_STATUS_SUCCESS;
+
+ fail:
+ switch_clear_flag_locked(tech_pvt, TFLAG_IO);
+ 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)
+{
+ switch_channel_t *channel = NULL;
+ private_t *tech_pvt = NULL;
+ ftdm_size_t len;
+ unsigned char data[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0};
+ ftdm_wait_flag_t wflags = FTDM_WRITE;
+ ftdm_status_t status;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ if (!tech_pvt->ftdmchan) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (switch_test_flag(tech_pvt, TFLAG_HOLD)) {
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
+ goto fail;
+ }
+
+ 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;
+ status = ftdm_channel_wait(tech_pvt->ftdmchan, &wflags, tech_pvt->ftdmchan->effective_interval * 10);
+
+ if (!(wflags & FTDM_WRITE)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Dropping frame! (write not ready)\n");
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ len = frame->datalen;
+ if (ftdm_channel_write(tech_pvt->ftdmchan, frame->data, frame->buflen, &len) != FTDM_SUCCESS) {
+ if (++tech_pvt->wr_error > 10) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "too many I/O write errors!\n");
+ goto fail;
+ }
+ } else {
+ tech_pvt->wr_error = 0;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+
+ fail:
+
+ switch_clear_flag_locked(tech_pvt, TFLAG_IO);
+ return SWITCH_STATUS_GENERR;
+
+}
+
+static switch_status_t channel_receive_message_cas(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+ switch_channel_t *channel;
+ private_t *tech_pvt;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ tech_pvt = (private_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ ftdm_log(FTDM_LOG_DEBUG, "Got Freeswitch message in R2 channel %d [%d]\n", tech_pvt->ftdmchan->physical_chan_id,
+ msg->message_id);
+
+ switch (msg->message_id) {
+ case SWITCH_MESSAGE_INDICATE_RINGING:
+ {
+ if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_PROGRESS);
+ } else {
+ ftdm_set_state_locked_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+ }
+ }
+ break;
+ case SWITCH_MESSAGE_INDICATE_PROGRESS:
+ {
+ if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_PROGRESS);
+ ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_MEDIA);
+ } else {
+ ftdm_set_state_locked_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+ ftdm_set_state_locked_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+ }
+ }
+ break;
+ case SWITCH_MESSAGE_INDICATE_ANSWER:
+ {
+ if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_ANSWERED);
+ } else {
+ /* lets make the ftmod_r2 module life easier by moving thru each
+ * state waiting for completion, clumsy, but does the job
+ */
+ if (tech_pvt->ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
+ ftdm_set_state_locked_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+ }
+ if (tech_pvt->ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
+ ftdm_set_state_locked_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+ }
+ ftdm_set_state_locked_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_UP);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message_b(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+ switch_channel_t *channel;
+ private_t *tech_pvt;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ tech_pvt = (private_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (tech_pvt->ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
+ ftdm_mutex_unlock(tech_pvt->ftdmchan->mutex);
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ switch (msg->message_id) {
+ case SWITCH_MESSAGE_INDICATE_RINGING:
+ {
+ if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ ftdm_set_flag(tech_pvt->ftdmchan, FTDM_CHANNEL_PROGRESS);
+ } else {
+ ftdm_set_state_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+ }
+ }
+ break;
+ case SWITCH_MESSAGE_INDICATE_PROGRESS:
+ {
+ if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ ftdm_set_flag(tech_pvt->ftdmchan, FTDM_CHANNEL_PROGRESS);
+ ftdm_set_flag(tech_pvt->ftdmchan, FTDM_CHANNEL_MEDIA);
+ } else {
+ /* Don't skip messages in the ISDN call setup
+ * TODO: make the isdn stack smart enough to handle that itself
+ * until then, this is here for safety...
+ */
+ if (tech_pvt->ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
+ ftdm_set_state_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+ }
+ ftdm_set_state_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+ }
+ }
+ break;
+ case SWITCH_MESSAGE_INDICATE_ANSWER:
+ {
+ if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ ftdm_set_flag(tech_pvt->ftdmchan, FTDM_CHANNEL_ANSWERED);
+ } else {
+ /* Don't skip messages in the ISDN call setup
+ * TODO: make the isdn stack smart enough to handle that itself
+ * until then, this is here for safety...
+ */
+ if (tech_pvt->ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
+ ftdm_set_state_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+ }
+ if (tech_pvt->ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
+ ftdm_set_state_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+ }
+ ftdm_set_state_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_UP);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message_fxo(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+ switch_channel_t *channel;
+ private_t *tech_pvt;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ tech_pvt = (private_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ switch (msg->message_id) {
+ case SWITCH_MESSAGE_INDICATE_PROGRESS:
+ case SWITCH_MESSAGE_INDICATE_ANSWER:
+ if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_ANSWERED);
+ ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_PROGRESS);
+ ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_MEDIA);
+ } else {
+ ftdm_set_state_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_UP);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message_fxs(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+ switch_channel_t *channel;
+ private_t *tech_pvt;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ tech_pvt = (private_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ switch (msg->message_id) {
+ case SWITCH_MESSAGE_INDICATE_PROGRESS:
+ case SWITCH_MESSAGE_INDICATE_ANSWER:
+ if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_ANSWERED);
+ ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_PROGRESS);
+ ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_MEDIA);
+ ftdm_set_state_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_UP);
+ switch_channel_mark_answered(channel);
+ }
+ break;
+ case SWITCH_MESSAGE_INDICATE_RINGING:
+ if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
+
+ if (!switch_channel_test_flag(channel, CF_ANSWERED) &&
+ !switch_channel_test_flag(channel, CF_EARLY_MEDIA) &&
+ !switch_channel_test_flag(channel, CF_RING_READY)
+ ) {
+ ftdm_set_state_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_RING);
+ switch_channel_mark_ring_ready(channel);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+ private_t *tech_pvt;
+ switch_status_t status;
+ switch_channel_t *channel;
+ const char *var;
+ ftdm_channel_t *ftdmchan = NULL;
+
+ tech_pvt = (private_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ channel = switch_core_session_get_channel(session);
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (!(ftdmchan = tech_pvt->ftdmchan)) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ ftdm_mutex_lock(ftdmchan->mutex);
+
+ if (!tech_pvt->ftdmchan) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+ status = SWITCH_STATUS_FALSE;
+ goto end;
+ }
+
+ switch (msg->message_id) {
+ case SWITCH_MESSAGE_INDICATE_PROGRESS:
+ case SWITCH_MESSAGE_INDICATE_ANSWER:
+ if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ if ((var = switch_channel_get_variable(channel, "freetdm_pre_buffer_size"))) {
+ int tmp = atoi(var);
+ if (tmp > -1) {
+ ftdm_channel_command(tech_pvt->ftdmchan, FTDM_COMMAND_SET_PRE_BUFFER_SIZE, &tmp);
+ }
+ }
+ }
+ break;
+ case SWITCH_MESSAGE_INDICATE_UUID_CHANGE:
+ {
+ ftdm_channel_replace_token(tech_pvt->ftdmchan, msg->string_array_arg[0], msg->string_array_arg[1]);
+ }
+ break;
+ default:
+ break;
+ }
+
+ switch (tech_pvt->ftdmchan->type) {
+ case FTDM_CHAN_TYPE_FXS:
+ case FTDM_CHAN_TYPE_EM:
+ status = channel_receive_message_fxs(session, msg);
+ break;
+ case FTDM_CHAN_TYPE_FXO:
+ status = channel_receive_message_fxo(session, msg);
+ break;
+ case FTDM_CHAN_TYPE_B:
+ status = channel_receive_message_b(session, msg);
+ break;
+ case FTDM_CHAN_TYPE_CAS:
+ status = channel_receive_message_cas(session, msg);
+ break;
+ default:
+ status = SWITCH_STATUS_FALSE;
+ break;
+ }
+
+ end:
+
+ ftdm_mutex_unlock(ftdmchan->mutex);
+
+ return status;
+
+}
+
+switch_state_handler_table_t freetdm_state_handlers = {
+ /*.on_init */ channel_on_init,
+ /*.on_routing */ channel_on_routing,
+ /*.on_execute */ channel_on_execute,
+ /*.on_hangup */ channel_on_hangup,
+ /*.on_exchange_media */ channel_on_exchange_media,
+ /*.on_soft_execute */ channel_on_soft_execute,
+ /*.on_consume_media */ NULL,
+ /*.on_hibernate */ NULL,
+ /*.on_reset */ NULL,
+ /*.on_park*/ NULL,
+ /*.on_reporting*/ NULL,
+ /*.on_destroy*/ channel_on_destroy
+
+};
+
+switch_io_routines_t freetdm_io_routines = {
+ /*.outgoing_channel */ channel_outgoing_channel,
+ /*.read_frame */ channel_read_frame,
+ /*.write_frame */ channel_write_frame,
+ /*.kill_channel */ channel_kill_channel,
+ /*.send_dtmf */ channel_send_dtmf,
+ /*.receive_message*/ channel_receive_message
+};
+
+/* Make sure when you have 2 sessions in the same scope that you pass the appropriate one to the routines
+that allocate memory or you will have 1 channel with memory allocated from another channel's pool!
+*/
+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 *dest = NULL;
+ char *data = NULL;
+ int span_id = -1, group_id = -1,chan_id = 0;
+ ftdm_channel_t *ftdmchan = NULL;
+ switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ char name[128];
+ ftdm_status_t status;
+ int direction = FTDM_TOP_DOWN;
+ ftdm_caller_data_t caller_data = {{ 0 }};
+ char *span_name = NULL;
+ switch_event_header_t *h;
+ char *argv[3];
+ int argc = 0;
+ const char *var;
+ const char *dest_num = NULL, *callerid_num = NULL;
+
+ if (!outbound_profile) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing caller profile\n");
+ return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ }
+
+ if (zstr(outbound_profile->destination_number)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid dial string\n");
+ return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ }
+
+
+ data = switch_core_strdup(outbound_profile->pool, outbound_profile->destination_number);
+
+ if (!zstr(outbound_profile->destination_number)) {
+ dest_num = switch_sanitize_number(switch_core_strdup(outbound_profile->pool, outbound_profile->destination_number));
+ }
+
+ if (!zstr(outbound_profile->caller_id_number)) {
+ callerid_num = switch_sanitize_number(switch_core_strdup(outbound_profile->pool, outbound_profile->caller_id_number));
+ }
+
+ if (!zstr(callerid_num) && !strcmp(callerid_num, "0000000000")) {
+ callerid_num = NULL;
+ }
+
+ if ((argc = switch_separate_string(data, '/', argv, (sizeof(argv) / sizeof(argv[0])))) < 2) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid dial string\n");
+ return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ }
+
+ if (switch_is_number(argv[0])) {
+ span_id = atoi(argv[0]);
+ } else {
+ span_name = argv[0];
+ }
+
+ if (*argv[1] == 'A') {
+ direction = FTDM_BOTTOM_UP;
+ } else if (*argv[1] == 'a') {
+ direction = FTDM_TOP_DOWN;
+ } else {
+ chan_id = atoi(argv[1]);
+ }
+
+ if (!(dest = argv[2])) {
+ dest = "";
+ }
+
+ if (span_id == 0 && chan_id != 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Span 0 is used to pick the first available span, selecting a channel is not supported (and doesn't make sense)\n");
+ return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ }
+
+ if (span_id == -1 && !zstr(span_name)) {
+ ftdm_span_t *span;
+ ftdm_status_t zstatus = ftdm_span_find_by_name(span_name, &span);
+ if (zstatus == FTDM_SUCCESS && span) {
+ span_id = span->span_id;
+ }
+ }
+
+ if (span_id == -1) {
+ //Look for a group
+ ftdm_group_t *group;
+ ftdm_status_t zstatus = ftdm_group_find_by_name(span_name, &group);
+ if (zstatus == FTDM_SUCCESS && group) {
+ group_id = group->group_id;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing ftdm span or group: %s\n", span_name);
+ return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ }
+ }
+
+ if (group_id < 0 && chan_id < 0) {
+ direction = FTDM_BOTTOM_UP;
+ chan_id = 0;
+ }
+
+ if (switch_test_flag(outbound_profile, SWITCH_CPF_SCREEN)) {
+ caller_data.screen = 1;
+ }
+
+ if (switch_test_flag(outbound_profile, SWITCH_CPF_HIDE_NUMBER)) {
+ caller_data.pres = 1;
+ }
+
+ if (!zstr(dest)) {
+ ftdm_set_string(caller_data.dnis.digits, dest);
+ }
+
+ if ((var = switch_event_get_header(var_event, "freetdm_outbound_ton")) || (var = switch_core_get_variable("freetdm_outbound_ton"))) {
+ if (!strcasecmp(var, "national")) {
+ caller_data.dnis.type = FTDM_TON_NATIONAL;
+ } else if (!strcasecmp(var, "international")) {
+ caller_data.dnis.type = FTDM_TON_INTERNATIONAL;
+ } else if (!strcasecmp(var, "local")) {
+ caller_data.dnis.type = FTDM_TON_SUBSCRIBER_NUMBER;
+ } else if (!strcasecmp(var, "unknown")) {
+ caller_data.dnis.type = FTDM_TON_UNKNOWN;
+ }
+ } else {
+ caller_data.dnis.type = outbound_profile->destination_number_ton;
+ }
+
+ caller_data.dnis.plan = outbound_profile->destination_number_numplan;
+
+ /* blindly copy data from outbound_profile. They will be overwritten
+ * by calling ftdm_caller_data if needed after */
+ caller_data.cid_num.type = outbound_profile->caller_ton;
+ caller_data.cid_num.plan = outbound_profile->caller_numplan;
+ caller_data.rdnis.type = outbound_profile->rdnis_ton;
+ caller_data.rdnis.plan = outbound_profile->rdnis_numplan;
+
+ ftdm_set_string(caller_data.cid_name, outbound_profile->caller_id_name);
+ ftdm_set_string(caller_data.cid_num.digits, switch_str_nil(outbound_profile->caller_id_number));
+
+ if (group_id >= 0) {
+ status = ftdm_channel_open_by_group(group_id, direction, &caller_data, &ftdmchan);
+ } else if (chan_id) {
+ status = ftdm_channel_open(span_id, chan_id, &ftdmchan);
+ } else {
+ status = ftdm_channel_open_by_span(span_id, direction, &caller_data, &ftdmchan);
+ }
+
+ if (status != FTDM_SUCCESS) {
+ if (caller_data.hangup_cause == SWITCH_CAUSE_NONE) {
+ caller_data.hangup_cause = SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+ }
+ return caller_data.hangup_cause;
+ }
+
+ if ((var = switch_event_get_header(var_event, "freetdm_pre_buffer_size"))) {
+ int tmp = atoi(var);
+ if (tmp > -1) {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_PRE_BUFFER_SIZE, &tmp);
+ }
+ }
+
+ ftdm_channel_clear_vars(ftdmchan);
+ for (h = var_event->headers; h; h = h->next) {
+ if (!strncasecmp(h->name, FREETDM_VAR_PREFIX, FREETDM_VAR_PREFIX_LEN)) {
+ char *v = h->name + FREETDM_VAR_PREFIX_LEN;
+ if (!zstr(v)) {
+ ftdm_channel_add_var(ftdmchan, v, h->value);
+ }
+ }
+ }
+
+ if ((*new_session = switch_core_session_request(freetdm_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, pool)) != 0) {
+ private_t *tech_pvt;
+ switch_caller_profile_t *caller_profile;
+ switch_channel_t *channel = switch_core_session_get_channel(*new_session);
+
+ switch_core_session_add_stream(*new_session, NULL);
+ if ((tech_pvt = (private_t *) switch_core_session_alloc(*new_session, sizeof(private_t))) != 0) {
+ tech_init(tech_pvt, *new_session, ftdmchan);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Hey where is my memory pool?\n");
+ switch_core_session_destroy(new_session);
+ cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ goto fail;
+ }
+
+ snprintf(name, sizeof(name), "FreeTDM/%u:%u/%s", ftdmchan->span_id, ftdmchan->chan_id, dest);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connect outbound channel %s\n", name);
+ switch_channel_set_name(channel, name);
+ switch_channel_set_variable(channel, "freetdm_span_name", ftdmchan->span->name);
+ switch_channel_set_variable_printf(channel, "freetdm_span_number", "%d", ftdmchan->span_id);
+ switch_channel_set_variable_printf(channel, "freetdm_chan_number", "%d", ftdmchan->chan_id);
+ ftdm_channel_set_caller_data(ftdmchan, &caller_data);
+ caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
+ caller_profile->destination_number = switch_core_strdup(caller_profile->pool, switch_str_nil(dest_num));
+ caller_profile->caller_id_number = switch_core_strdup(caller_profile->pool, switch_str_nil(callerid_num));
+ switch_channel_set_caller_profile(channel, caller_profile);
+ tech_pvt->caller_profile = caller_profile;
+
+
+ switch_channel_set_flag(channel, CF_OUTBOUND);
+ switch_channel_set_state(channel, CS_INIT);
+ if (ftdm_channel_add_token(ftdmchan, switch_core_session_get_uuid(*new_session), ftdmchan->token_count) != FTDM_SUCCESS) {
+ switch_core_session_destroy(new_session);
+ cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ goto fail;
+ }
+
+
+ if (ftdm_channel_outgoing_call(ftdmchan) != FTDM_SUCCESS) {
+ 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);
+ }
+ switch_core_session_destroy(new_session);
+ cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ goto fail;
+ }
+
+ ftdm_channel_init(ftdmchan);
+
+ return SWITCH_CAUSE_SUCCESS;
+ }
+
+ fail:
+
+ if (ftdmchan) {
+ ftdm_channel_done(ftdmchan);
+ }
+
+ return cause;
+
+}
+
+ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session_t **sp)
+{
+ switch_core_session_t *session = NULL;
+ private_t *tech_pvt = NULL;
+ switch_channel_t *channel = NULL;
+ char name[128];
+
+ *sp = NULL;
+
+ if (!(session = switch_core_session_request(freetdm_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, NULL))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Initilization Error!\n");
+ return FTDM_FAIL;
+ }
+
+ switch_core_session_add_stream(session, NULL);
+
+ tech_pvt = (private_t *) switch_core_session_alloc(session, sizeof(private_t));
+ assert(tech_pvt != NULL);
+ channel = switch_core_session_get_channel(session);
+ if (tech_init(tech_pvt, session, sigmsg->channel) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Initilization Error!\n");
+ switch_core_session_destroy(&session);
+ return FTDM_FAIL;
+ }
+
+ *sigmsg->channel->caller_data.collected = '\0';
+
+ if (zstr(sigmsg->channel->caller_data.cid_name)) {
+ switch_set_string(sigmsg->channel->caller_data.cid_name, sigmsg->channel->chan_name);
+ }
+
+ if (zstr(sigmsg->channel->caller_data.cid_num.digits)) {
+ if (!zstr(sigmsg->channel->caller_data.ani.digits)) {
+ switch_set_string(sigmsg->channel->caller_data.cid_num.digits, sigmsg->channel->caller_data.ani.digits);
+ } else {
+ switch_set_string(sigmsg->channel->caller_data.cid_num.digits, sigmsg->channel->chan_number);
+ }
+ }
+
+ tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
+ "FreeTDM",
+ SPAN_CONFIG[sigmsg->channel->span_id].dialplan,
+ sigmsg->channel->caller_data.cid_name,
+ sigmsg->channel->caller_data.cid_num.digits,
+ NULL,
+ sigmsg->channel->caller_data.ani.digits,
+ sigmsg->channel->caller_data.aniII,
+ sigmsg->channel->caller_data.rdnis.digits,
+ (char *) modname,
+ SPAN_CONFIG[sigmsg->channel->span_id].context,
+ sigmsg->channel->caller_data.dnis.digits);
+
+ assert(tech_pvt->caller_profile != NULL);
+
+ if (sigmsg->channel->caller_data.screen == 1 || sigmsg->channel->caller_data.screen == 3) {
+ switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_SCREEN);
+ }
+
+ if (sigmsg->channel->caller_data.pres) {
+ switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER);
+ }
+
+ snprintf(name, sizeof(name), "FreeTDM/%u:%u/%s", sigmsg->channel->span_id, sigmsg->channel->chan_id, tech_pvt->caller_profile->destination_number);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connect inbound channel %s\n", name);
+ switch_channel_set_name(channel, name);
+ switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
+
+ switch_channel_set_variable(channel, "freetdm_span_name", sigmsg->channel->span->name);
+ switch_channel_set_variable_printf(channel, "freetdm_span_number", "%d", sigmsg->channel->span_id);
+ switch_channel_set_variable_printf(channel, "freetdm_chan_number", "%d", sigmsg->channel->chan_id);
+
+ switch_channel_set_state(channel, CS_INIT);
+ if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error spawning thread\n");
+ switch_core_session_destroy(&session);
+ return FTDM_FAIL;
+ }
+
+ if (ftdm_channel_add_token(sigmsg->channel, switch_core_session_get_uuid(session), 0) != FTDM_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error adding token\n");
+ switch_core_session_destroy(&session);
+ return FTDM_FAIL;
+ }
+ *sp = session;
+
+ return FTDM_SUCCESS;
+}
+
+static FIO_SIGNAL_CB_FUNCTION(on_common_signal)
+{
+ switch_event_t *event = NULL;
+
+ switch (sigmsg->event_id) {
+
+ case FTDM_SIGEVENT_ALARM_CLEAR:
+ case FTDM_SIGEVENT_ALARM_TRAP:
+ {
+ if (ftdm_channel_get_alarms(sigmsg->channel) != 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 [%s]\n", sigmsg->channel->span_id, sigmsg->channel->chan_id);
+ 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 [%s]\n", sigmsg->channel->span_id, sigmsg->channel->chan_id);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-trap");
+ }
+ }
+ break;
+ default:
+ return FTDM_SUCCESS;
+ break;
+ }
+
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-name", "%s", sigmsg->channel->span->name);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-number", "%d", sigmsg->channel->span_id);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", sigmsg->channel->chan_id);
+
+ if (ftdm_test_alarm_flag(sigmsg->channel, FTDM_ALARM_RECOVER)) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "recover");
+ }
+ if (ftdm_test_alarm_flag(sigmsg->channel, FTDM_ALARM_LOOPBACK)) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "loopback");
+ }
+ if (ftdm_test_alarm_flag(sigmsg->channel, FTDM_ALARM_YELLOW)) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "yellow");
+ }
+ if (ftdm_test_alarm_flag(sigmsg->channel, FTDM_ALARM_RED)) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "red");
+ }
+ if (ftdm_test_alarm_flag(sigmsg->channel, FTDM_ALARM_BLUE)) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "blue");
+ }
+ if (ftdm_test_alarm_flag(sigmsg->channel, FTDM_ALARM_NOTOPEN)) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "notopen");
+ }
+ if (ftdm_test_alarm_flag(sigmsg->channel, FTDM_ALARM_AIS)) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "ais");
+ }
+ if (ftdm_test_alarm_flag(sigmsg->channel, FTDM_ALARM_RAI)) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "rai");
+ }
+ if (ftdm_test_alarm_flag(sigmsg->channel, FTDM_ALARM_GENERAL)) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "general");
+ }
+ switch_event_fire(&event);
+
+ return FTDM_BREAK;
+}
+
+static FIO_SIGNAL_CB_FUNCTION(on_fxo_signal)
+{
+ switch_core_session_t *session = NULL;
+ switch_channel_t *channel = NULL;
+ ftdm_status_t status;
+
+ ftdm_log(FTDM_LOG_DEBUG, "got FXO sig %d:%d [%s]\n", sigmsg->channel->span_id, sigmsg->channel->chan_id, ftdm_signal_event2str(sigmsg->event_id));
+
+ switch(sigmsg->event_id) {
+
+ case FTDM_SIGEVENT_PROGRESS_MEDIA:
+ {
+ if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_mark_pre_answered(channel);
+ switch_core_session_rwunlock(session);
+ }
+ }
+ break;
+ case FTDM_SIGEVENT_STOP:
+ {
+ private_t *tech_pvt = NULL;
+ while((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+ tech_pvt = switch_core_session_get_private(session);
+ switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+ ftdm_channel_clear_token(sigmsg->channel, 0);
+ channel = switch_core_session_get_channel(session);
+ switch_channel_hangup(channel, sigmsg->channel->caller_data.hangup_cause);
+ ftdm_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+ switch_core_session_rwunlock(session);
+ }
+ }
+ break;
+ case FTDM_SIGEVENT_UP:
+ {
+ if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_mark_answered(channel);
+ switch_core_session_rwunlock(session);
+ }
+ }
+ break;
+ case FTDM_SIGEVENT_START:
+ {
+ status = ftdm_channel_from_event(sigmsg, &session);
+ if (status != FTDM_SUCCESS) {
+ ftdm_set_state_locked(sigmsg->channel, FTDM_CHANNEL_STATE_DOWN);
+ }
+ }
+ break;
+
+ default:
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled msg type %d for channel %d:%d\n",
+ sigmsg->event_id, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+ }
+ break;
+
+ }
+
+ return FTDM_SUCCESS;
+}
+
+static FIO_SIGNAL_CB_FUNCTION(on_fxs_signal)
+{
+ switch_core_session_t *session = NULL;
+ switch_channel_t *channel = NULL;
+ ftdm_status_t status = FTDM_SUCCESS;
+
+ ftdm_log(FTDM_LOG_DEBUG, "got FXS sig [%s]\n", ftdm_signal_event2str(sigmsg->event_id));
+
+ switch(sigmsg->event_id) {
+ case FTDM_SIGEVENT_UP:
+ {
+ if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_mark_answered(channel);
+ switch_core_session_rwunlock(session);
+ }
+ }
+ break;
+ case FTDM_SIGEVENT_PROGRESS:
+ {
+ if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_mark_ring_ready(channel);
+ switch_core_session_rwunlock(session);
+ }
+ }
+ break;
+ case FTDM_SIGEVENT_START:
+ {
+ ftdm_clear_flag_locked(sigmsg->channel, FTDM_CHANNEL_HOLD);
+ status = ftdm_channel_from_event(sigmsg, &session);
+ if (status != FTDM_SUCCESS) {
+ ftdm_set_state_locked(sigmsg->channel, FTDM_CHANNEL_STATE_BUSY);
+ }
+ }
+ break;
+ case FTDM_SIGEVENT_STOP:
+ {
+ private_t *tech_pvt = NULL;
+ switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
+ if (sigmsg->channel->token_count) {
+ switch_core_session_t *session_a, *session_b, *session_t = NULL;
+ switch_channel_t *channel_a = NULL, *channel_b = NULL;
+ int digits = !zstr(sigmsg->channel->caller_data.collected);
+ const char *br_a_uuid = NULL, *br_b_uuid = NULL;
+ private_t *tech_pvt = NULL;
+
+
+ if ((session_a = switch_core_session_locate(sigmsg->channel->tokens[0]))) {
+ channel_a = switch_core_session_get_channel(session_a);
+ br_a_uuid = switch_channel_get_variable(channel_a, SWITCH_SIGNAL_BOND_VARIABLE);
+
+ tech_pvt = switch_core_session_get_private(session_a);
+ stop_hold(session_a, switch_channel_get_variable(channel_a, SWITCH_SIGNAL_BOND_VARIABLE));
+ switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+ }
+
+ if ((session_b = switch_core_session_locate(sigmsg->channel->tokens[1]))) {
+ channel_b = switch_core_session_get_channel(session_b);
+ br_b_uuid = switch_channel_get_variable(channel_b, SWITCH_SIGNAL_BOND_VARIABLE);
+
+ tech_pvt = switch_core_session_get_private(session_b);
+ stop_hold(session_a, switch_channel_get_variable(channel_b, SWITCH_SIGNAL_BOND_VARIABLE));
+ switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+ }
+
+ if (channel_a && channel_b && !switch_channel_test_flag(channel_a, CF_OUTBOUND) && !switch_channel_test_flag(channel_b, CF_OUTBOUND)) {
+ cause = SWITCH_CAUSE_ATTENDED_TRANSFER;
+ if (br_a_uuid && br_b_uuid) {
+ switch_ivr_uuid_bridge(br_a_uuid, br_b_uuid);
+ } else if (br_a_uuid && digits) {
+ session_t = switch_core_session_locate(br_a_uuid);
+ } else if (br_b_uuid && digits) {
+ session_t = switch_core_session_locate(br_b_uuid);
+ }
+ }
+
+ if (session_t) {
+ switch_ivr_session_transfer(session_t, sigmsg->channel->caller_data.collected, NULL, NULL);
+ switch_core_session_rwunlock(session_t);
+ }
+
+ if (session_a) {
+ switch_core_session_rwunlock(session_a);
+ }
+
+ if (session_b) {
+ switch_core_session_rwunlock(session_b);
+ }
+
+
+ }
+
+ while((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+ tech_pvt = switch_core_session_get_private(session);
+ switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+ channel = switch_core_session_get_channel(session);
+ switch_channel_hangup(channel, cause);
+ ftdm_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+ switch_core_session_rwunlock(session);
+ }
+ ftdm_channel_clear_token(sigmsg->channel, NULL);
+
+ }
+ break;
+
+ case FTDM_SIGEVENT_ADD_CALL:
+ {
+ cycle_foreground(sigmsg->channel, 1, NULL);
+ }
+ break;
+ case FTDM_SIGEVENT_FLASH:
+ {
+
+ if (ftdm_test_flag(sigmsg->channel, FTDM_CHANNEL_HOLD) && sigmsg->channel->token_count == 1) {
+ switch_core_session_t *session;
+ if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+ const char *buuid;
+ switch_channel_t *channel;
+ private_t *tech_pvt;
+
+ tech_pvt = switch_core_session_get_private(session);
+ channel = switch_core_session_get_channel(session);
+ buuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
+ ftdm_set_state_locked(sigmsg->channel, FTDM_CHANNEL_STATE_UP);
+ stop_hold(session, buuid);
+ switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+ switch_core_session_rwunlock(session);
+ }
+ } else if (sigmsg->channel->token_count == 2 && (SPAN_CONFIG[sigmsg->span_id].analog_options & ANALOG_OPTION_3WAY)) {
+ if (ftdm_test_flag(sigmsg->channel, FTDM_CHANNEL_3WAY)) {
+ ftdm_clear_flag(sigmsg->channel, FTDM_CHANNEL_3WAY);
+ if ((session = ftdm_channel_get_session(sigmsg->channel, 1))) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+ ftdm_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+ switch_core_session_rwunlock(session);
+ }
+ cycle_foreground(sigmsg->channel, 1, NULL);
+ } else {
+ char *cmd;
+ cmd = switch_mprintf("three_way::%s", sigmsg->channel->tokens[0]);
+ ftdm_set_flag(sigmsg->channel, FTDM_CHANNEL_3WAY);
+ cycle_foreground(sigmsg->channel, 1, cmd);
+ free(cmd);
+ }
+ } else if ((SPAN_CONFIG[sigmsg->span_id].analog_options & ANALOG_OPTION_CALL_SWAP)
+ || (SPAN_CONFIG[sigmsg->span_id].analog_options & ANALOG_OPTION_3WAY)
+ ) {
+ cycle_foreground(sigmsg->channel, 1, NULL);
+ if (sigmsg->channel->token_count == 1) {
+ ftdm_set_flag_locked(sigmsg->channel, FTDM_CHANNEL_HOLD);
+ ftdm_set_state_locked(sigmsg->channel, FTDM_CHANNEL_STATE_DIALTONE);
+ }
+ }
+
+ }
+ break;
+
+ case FTDM_SIGEVENT_COLLECTED_DIGIT:
+ {
+ char *dtmf = sigmsg->raw_data;
+ char *regex = SPAN_CONFIG[sigmsg->channel->span->span_id].dial_regex;
+ char *fail_regex = SPAN_CONFIG[sigmsg->channel->span->span_id].fail_dial_regex;
+
+ if (zstr(regex)) {
+ regex = NULL;
+ }
+
+ if (zstr(fail_regex)) {
+ fail_regex = NULL;
+ }
+
+ ftdm_log(FTDM_LOG_DEBUG, "got DTMF sig [%s]\n", dtmf);
+ switch_set_string(sigmsg->channel->caller_data.collected, dtmf);
+
+ if ((regex || fail_regex) && !zstr(dtmf)) {
+ switch_regex_t *re = NULL;
+ int ovector[30];
+ int match = 0;
+
+ if (fail_regex) {
+ match = switch_regex_perform(dtmf, fail_regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
+ status = match ? FTDM_SUCCESS : FTDM_BREAK;
+ switch_regex_safe_free(re);
+ }
+
+ if (status == FTDM_SUCCESS && regex) {
+ match = switch_regex_perform(dtmf, regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
+ status = match ? FTDM_BREAK : FTDM_SUCCESS;
+ }
+
+ switch_regex_safe_free(re);
+ }
+
+ }
+ break;
+
+ default:
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled msg type %d for channel %d:%d\n",
+ sigmsg->event_id, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+ }
+ break;
+
+ }
+
+ return status;
+}
+
+static FIO_SIGNAL_CB_FUNCTION(on_r2_signal)
+{
+ switch_core_session_t *session = NULL;
+ switch_channel_t *channel = NULL;
+ ftdm_status_t status = FTDM_SUCCESS;
+
+ ftdm_log(FTDM_LOG_DEBUG, "Got R2 channel sig [%s] in channel %d\n", ftdm_signal_event2str(sigmsg->event_id), sigmsg->channel->physical_chan_id);
+
+ if (on_common_signal(sigmsg) == FTDM_BREAK) {
+ return FTDM_SUCCESS;
+ }
+
+ switch(sigmsg->event_id) {
+ /* on_call_disconnect from the R2 side */
+ case FTDM_SIGEVENT_STOP:
+ {
+ private_t *tech_pvt = NULL;
+ while((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+ tech_pvt = switch_core_session_get_private(session);
+ switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+ channel = switch_core_session_get_channel(session);
+ switch_channel_hangup(channel, sigmsg->channel->caller_data.hangup_cause);
+ ftdm_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+ switch_core_session_rwunlock(session);
+ }
+ }
+ break;
+
+ /* on_call_offered from the R2 side */
+ case FTDM_SIGEVENT_START:
+ {
+ status = ftdm_channel_from_event(sigmsg, &session);
+ }
+ break;
+
+ /* on DNIS received from the R2 forward side, return status == FTDM_BREAK to stop requesting DNIS */
+ case FTDM_SIGEVENT_COLLECTED_DIGIT:
+ {
+ char *regex = SPAN_CONFIG[sigmsg->channel->span->span_id].dial_regex;
+ char *fail_regex = SPAN_CONFIG[sigmsg->channel->span->span_id].fail_dial_regex;
+
+ if (zstr(regex)) {
+ regex = NULL;
+ }
+
+ if (zstr(fail_regex)) {
+ fail_regex = NULL;
+ }
+
+ ftdm_log(FTDM_LOG_DEBUG, "R2 DNIS so far [%s]\n", sigmsg->channel->caller_data.dnis.digits);
+
+ if ((regex || fail_regex) && !zstr(sigmsg->channel->caller_data.dnis.digits)) {
+ switch_regex_t *re = NULL;
+ int ovector[30];
+ int match = 0;
+
+ if (fail_regex) {
+ match = switch_regex_perform(sigmsg->channel->caller_data.dnis.digits, fail_regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
+ status = match ? FTDM_SUCCESS : FTDM_BREAK;
+ switch_regex_safe_free(re);
+ }
+
+ if (status == FTDM_SUCCESS && regex) {
+ match = switch_regex_perform(sigmsg->channel->caller_data.dnis.digits, regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
+ status = match ? FTDM_BREAK : FTDM_SUCCESS;
+ }
+
+ switch_regex_safe_free(re);
+ }
+ }
+ break;
+
+ case FTDM_SIGEVENT_PROGRESS:
+ {
+ if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_mark_ring_ready(channel);
+ switch_core_session_rwunlock(session);
+ }
+ }
+ break;
+
+ case FTDM_SIGEVENT_UP:
+ {
+ if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+ ftdm_tone_type_t tt = FTDM_TONE_DTMF;
+ channel = switch_core_session_get_channel(session);
+ switch_channel_mark_answered(channel);
+ if (ftdm_channel_command(sigmsg->channel, FTDM_COMMAND_ENABLE_DTMF_DETECT, &tt) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to enable DTMF detection in R2 channel %d:%d\n", sigmsg->channel->span_id, sigmsg->channel->chan_id);
+ }
+ switch_core_session_rwunlock(session);
+ }
+ }
+ break;
+
+ default:
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled event %d from R2 for channel %d:%d\n",
+ sigmsg->event_id, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+ }
+ break;
+ }
+
+ return status;
+}
+
+static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal)
+{
+ switch_core_session_t *session = NULL;
+ switch_channel_t *channel = NULL;
+
+ ftdm_log(FTDM_LOG_DEBUG, "got clear channel sig [%s]\n", ftdm_signal_event2str(sigmsg->event_id));
+
+ if (on_common_signal(sigmsg) == FTDM_BREAK) {
+ return FTDM_SUCCESS;
+ }
+
+ switch(sigmsg->event_id) {
+ case FTDM_SIGEVENT_START:
+ {
+ ftdm_tone_type_t tt = FTDM_TONE_DTMF;
+
+ if (ftdm_channel_command(sigmsg->channel, FTDM_COMMAND_ENABLE_DTMF_DETECT, &tt) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "TONE ERROR\n");
+ }
+
+ return ftdm_channel_from_event(sigmsg, &session);
+ }
+ break;
+ case FTDM_SIGEVENT_STOP:
+ case FTDM_SIGEVENT_RESTART:
+ {
+ private_t *tech_pvt = NULL;
+ while((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+ tech_pvt = switch_core_session_get_private(session);
+ switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+ channel = switch_core_session_get_channel(session);
+ switch_channel_hangup(channel, sigmsg->channel->caller_data.hangup_cause);
+ ftdm_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+ switch_core_session_rwunlock(session);
+ }
+ }
+ break;
+ case FTDM_SIGEVENT_UP:
+ {
+ if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+ ftdm_tone_type_t tt = FTDM_TONE_DTMF;
+ channel = switch_core_session_get_channel(session);
+ switch_channel_mark_answered(channel);
+ if (ftdm_channel_command(sigmsg->channel, FTDM_COMMAND_ENABLE_DTMF_DETECT, &tt) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "TONE ERROR\n");
+ }
+ switch_core_session_rwunlock(session);
+ } else {
+ const char *uuid = ftdm_channel_get_uuid(sigmsg->channel, 0);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Session for channel %d:%d not found [UUID: %s]\n",
+ sigmsg->channel->span_id, sigmsg->channel->chan_id, (uuid) ? uuid : "N/A");
+ }
+ }
+ case FTDM_SIGEVENT_PROGRESS_MEDIA:
+ {
+ if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_mark_pre_answered(channel);
+ switch_core_session_rwunlock(session);
+ } else {
+ const char *uuid = ftdm_channel_get_uuid(sigmsg->channel, 0);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Session for channel %d:%d not found [UUID: %s]\n",
+ sigmsg->channel->span_id, sigmsg->channel->chan_id, (uuid) ? uuid : "N/A");
+ }
+ }
+ break;
+ case FTDM_SIGEVENT_PROGRESS:
+ {
+ if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_mark_ring_ready(channel);
+ switch_core_session_rwunlock(session);
+ } else {
+ const char *uuid = ftdm_channel_get_uuid(sigmsg->channel, 0);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Session for channel %d:%d not found [UUID: %s]\n",
+ sigmsg->channel->span_id, sigmsg->channel->chan_id, (uuid) ? uuid : "N/A");
+ }
+ }
+ default:
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled msg type %d for channel %d:%d\n",
+ sigmsg->event_id, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+ }
+ break;
+ }
+
+ return FTDM_SUCCESS;
+}
+
+
+static FIO_SIGNAL_CB_FUNCTION(on_analog_signal)
+{
+ switch_status_t status = SWITCH_STATUS_FALSE;
+
+ if (on_common_signal(sigmsg) == FTDM_BREAK) {
+ return FTDM_SUCCESS;
+ }
+
+ switch (sigmsg->channel->type) {
+ case FTDM_CHAN_TYPE_FXO:
+ case FTDM_CHAN_TYPE_EM:
+ {
+ status = on_fxo_signal(sigmsg);
+ }
+ break;
+ case FTDM_CHAN_TYPE_FXS:
+ {
+ status = on_fxs_signal(sigmsg);
+ }
+ break;
+ default:
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled analog channel type %d for channel %d:%d\n",
+ sigmsg->channel->type, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+ }
+ break;
+ }
+
+ return status;
+}
+
+static void ftdm_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
+{
+ char *data = NULL;
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ if (switch_vasprintf(&data, fmt, ap) != -1) {
+ switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, (char *)func, line, NULL, level, "%s", data);
+ free(data);
+ }
+
+ va_end(ap);
+
+}
+
+static uint32_t enable_analog_option(const char *str, uint32_t current_options)
+{
+ if (!strcasecmp(str, "3-way")) {
+ current_options |= ANALOG_OPTION_3WAY;
+ current_options &= ~ANALOG_OPTION_CALL_SWAP;
+ } else if (!strcasecmp(str, "call-swap")) {
+ current_options |= ANALOG_OPTION_CALL_SWAP;
+ current_options &= ~ANALOG_OPTION_3WAY;
+ }
+
+ return current_options;
+
+}
+
+static switch_status_t load_config(void)
+{
+ const char *cf = "freetdm.conf";
+ switch_xml_t cfg, xml, settings, param, spans, myspan;
+ ftdm_span_t *boost_spans[FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN];
+ ftdm_span_t *boost_span = NULL;
+ unsigned boosti = 0;
+ unsigned int i = 0;
+
+ memset(boost_spans, 0, sizeof(boost_spans));
+ memset(&globals, 0, sizeof(globals));
+ switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, module_pool);
+ if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf);
+ return SWITCH_STATUS_TERM;
+ }
+
+ if ((settings = switch_xml_child(cfg, "settings"))) {
+ for (param = switch_xml_child(settings, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+
+ if (!strcasecmp(var, "debug")) {
+ globals.debug = atoi(val);
+ } else if (!strcasecmp(var, "hold-music")) {
+ switch_set_string(globals.hold_music, val);
+ } else if (!strcasecmp(var, "enable-analog-option")) {
+ globals.analog_options = enable_analog_option(val, globals.analog_options);
+ }
+ }
+ }
+
+ if ((spans = switch_xml_child(cfg, "analog_spans"))) {
+ for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+ char *id = (char *) switch_xml_attr(myspan, "id");
+ char *name = (char *) switch_xml_attr(myspan, "name");
+ ftdm_status_t zstatus = FTDM_FAIL;
+ const char *context = "default";
+ const char *dialplan = "XML";
+ const char *tonegroup = NULL;
+ char *digit_timeout = NULL;
+ char *max_digits = NULL;
+ char *hotline = NULL;
+ char *dial_regex = NULL;
+ char *hold_music = NULL;
+ char *fail_dial_regex = NULL;
+ const char *enable_callerid = "true";
+
+ uint32_t span_id = 0, to = 0, max = 0;
+ ftdm_span_t *span = NULL;
+ analog_option_t analog_options = ANALOG_OPTION_NONE;
+
+ for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+
+ if (!strcasecmp(var, "tonegroup")) {
+ tonegroup = val;
+ } else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "digit-timeout")) {
+ digit_timeout = val;
+ } else if (!strcasecmp(var, "context")) {
+ context = val;
+ } else if (!strcasecmp(var, "dialplan")) {
+ dialplan = val;
+ } else if (!strcasecmp(var, "dial-regex")) {
+ dial_regex = val;
+ } else if (!strcasecmp(var, "enable-callerid")) {
+ enable_callerid = val;
+ } else if (!strcasecmp(var, "fail-dial-regex")) {
+ fail_dial_regex = val;
+ } else if (!strcasecmp(var, "hold-music")) {
+ hold_music = val;
+ } else if (!strcasecmp(var, "max_digits") || !strcasecmp(var, "max-digits")) {
+ max_digits = val;
+ } else if (!strcasecmp(var, "hotline")) {
+ hotline = val;
+ } else if (!strcasecmp(var, "enable-analog-option")) {
+ analog_options = enable_analog_option(val, analog_options);
+ }
+ }
+
+ if (!id && !name) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+ continue;
+ }
+
+
+
+ if (!tonegroup) {
+ tonegroup = "us";
+ }
+
+ if (digit_timeout) {
+ to = atoi(digit_timeout);
+ }
+
+ if (max_digits) {
+ max = atoi(max_digits);
+ }
+
+ if (name) {
+ zstatus = ftdm_span_find_by_name(name, &span);
+ } else {
+ if (switch_is_number(id)) {
+ span_id = atoi(id);
+ zstatus = ftdm_span_find(span_id, &span);
+ }
+
+ if (zstatus != FTDM_SUCCESS) {
+ zstatus = ftdm_span_find_by_name(id, &span);
+ }
+ }
+
+ if (zstatus != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+ continue;
+ }
+
+ if (!span_id) {
+ span_id = span->span_id;
+ }
+
+ if (ftdm_configure_span("analog", span, on_analog_signal,
+ "tonemap", tonegroup,
+ "digit_timeout", &to,
+ "max_dialstr", &max,
+ "hotline", hotline,
+ "enable_callerid", enable_callerid,
+ TAG_END) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error starting FreeTDM span %d\n", span_id);
+ continue;
+ }
+
+ SPAN_CONFIG[span->span_id].span = span;
+ switch_set_string(SPAN_CONFIG[span->span_id].context, context);
+ switch_set_string(SPAN_CONFIG[span->span_id].dialplan, dialplan);
+ SPAN_CONFIG[span->span_id].analog_options = analog_options | globals.analog_options;
+
+ if (dial_regex) {
+ switch_set_string(SPAN_CONFIG[span->span_id].dial_regex, dial_regex);
+ }
+
+ if (fail_dial_regex) {
+ switch_set_string(SPAN_CONFIG[span->span_id].fail_dial_regex, fail_dial_regex);
+ }
+
+ if (hold_music) {
+ switch_set_string(SPAN_CONFIG[span->span_id].hold_music, hold_music);
+ }
+ switch_copy_string(SPAN_CONFIG[span->span_id].type, "analog", sizeof(SPAN_CONFIG[span->span_id].type));
+ ftdm_span_start(span);
+ }
+ }
+
+ if ((spans = switch_xml_child(cfg, "analog_em_spans"))) {
+ for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+ char *id = (char *) switch_xml_attr(myspan, "id");
+ char *name = (char *) switch_xml_attr(myspan, "name");
+ ftdm_status_t zstatus = FTDM_FAIL;
+ const char *context = "default";
+ const char *dialplan = "XML";
+ const char *tonegroup = NULL;
+ char *digit_timeout = NULL;
+ char *max_digits = NULL;
+ char *dial_regex = NULL;
+ char *hold_music = NULL;
+ char *fail_dial_regex = NULL;
+ uint32_t span_id = 0, to = 0, max = 0;
+ ftdm_span_t *span = NULL;
+ analog_option_t analog_options = ANALOG_OPTION_NONE;
+
+ for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+
+ if (!strcasecmp(var, "tonegroup")) {
+ tonegroup = val;
+ } else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "digit-timeout")) {
+ digit_timeout = val;
+ } else if (!strcasecmp(var, "context")) {
+ context = val;
+ } else if (!strcasecmp(var, "dialplan")) {
+ dialplan = val;
+ } else if (!strcasecmp(var, "dial-regex")) {
+ dial_regex = val;
+ } else if (!strcasecmp(var, "fail-dial-regex")) {
+ fail_dial_regex = val;
+ } else if (!strcasecmp(var, "hold-music")) {
+ hold_music = val;
+ } else if (!strcasecmp(var, "max_digits") || !strcasecmp(var, "max-digits")) {
+ max_digits = val;
+ } else if (!strcasecmp(var, "enable-analog-option")) {
+ analog_options = enable_analog_option(val, analog_options);
+ }
+ }
+
+ if (!id && !name) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+ continue;
+ }
+
+
+ if (!tonegroup) {
+ tonegroup = "us";
+ }
+
+ if (digit_timeout) {
+ to = atoi(digit_timeout);
+ }
+
+ if (max_digits) {
+ max = atoi(max_digits);
+ }
+
+
+ if (name) {
+ zstatus = ftdm_span_find_by_name(name, &span);
+ } else {
+ if (switch_is_number(id)) {
+ span_id = atoi(id);
+ zstatus = ftdm_span_find(span_id, &span);
+ }
+
+ if (zstatus != FTDM_SUCCESS) {
+ zstatus = ftdm_span_find_by_name(id, &span);
+ }
+ }
+
+ if (zstatus != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+ continue;
+ }
+
+ if (!span_id) {
+ span_id = span->span_id;
+ }
+
+
+ if (ftdm_configure_span("analog_em", span, on_analog_signal,
+ "tonemap", tonegroup,
+ "digit_timeout", &to,
+ "max_dialstr", &max,
+ TAG_END) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error starting FreeTDM span %d\n", span_id);
+ continue;
+ }
+
+ SPAN_CONFIG[span->span_id].span = span;
+ switch_set_string(SPAN_CONFIG[span->span_id].context, context);
+ switch_set_string(SPAN_CONFIG[span->span_id].dialplan, dialplan);
+ SPAN_CONFIG[span->span_id].analog_options = analog_options | globals.analog_options;
+
+ if (dial_regex) {
+ switch_set_string(SPAN_CONFIG[span->span_id].dial_regex, dial_regex);
+ }
+
+ if (fail_dial_regex) {
+ switch_set_string(SPAN_CONFIG[span->span_id].fail_dial_regex, fail_dial_regex);
+ }
+
+ if (hold_music) {
+ switch_set_string(SPAN_CONFIG[span->span_id].hold_music, hold_music);
+ }
+ switch_copy_string(SPAN_CONFIG[span->span_id].type, "analog_em", sizeof(SPAN_CONFIG[span->span_id].type));
+ ftdm_span_start(span);
+ }
+ }
+
+ if ((spans = switch_xml_child(cfg, "pri_spans"))) {
+ for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+ char *id = (char *) switch_xml_attr(myspan, "id");
+ char *name = (char *) switch_xml_attr(myspan, "name");
+ ftdm_status_t zstatus = FTDM_FAIL;
+ const char *context = "default";
+ const char *dialplan = "XML";
+ //Q921NetUser_t mode = Q931_TE;
+ //Q931Dialect_t dialect = Q931_Dialect_National;
+ char *mode = NULL;
+ char *dialect = NULL;
+ uint32_t span_id = 0;
+ ftdm_span_t *span = NULL;
+ const char *tonegroup = NULL;
+ char *digit_timeout = NULL;
+ const char *opts = "none";
+ uint32_t to = 0;
+ int q921loglevel = -1;
+ int q931loglevel = -1;
+
+ // quick debug
+ //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ID: '%s', Name:'%s'\n",id,name);
+
+ for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+
+ if (!strcasecmp(var, "tonegroup")) {
+ tonegroup = val;
+ } else if (!strcasecmp(var, "mode")) {
+ mode = val;
+ } else if (!strcasecmp(var, "dialect")) {
+ dialect = val;
+ } else if (!strcasecmp(var, "q921loglevel")) {
+ if ((q921loglevel = switch_log_str2level(val)) == SWITCH_LOG_INVALID) {
+ q921loglevel = -1;
+ }
+ } else if (!strcasecmp(var, "q931loglevel")) {
+ if ((q931loglevel = switch_log_str2level(val)) == SWITCH_LOG_INVALID) {
+ q931loglevel = -1;
+ }
+ } else if (!strcasecmp(var, "context")) {
+ context = val;
+ } else if (!strcasecmp(var, "opts")) {
+ opts = val;
+ } else if (!strcasecmp(var, "dialplan")) {
+ dialplan = val;
+ } else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "digit-timeout")) {
+ digit_timeout = val;
+ }
+ }
+
+ if (!id && !name) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+ continue;
+ }
+
+ if (name) {
+ zstatus = ftdm_span_find_by_name(name, &span);
+ } else {
+ if (switch_is_number(id)) {
+ span_id = atoi(id);
+ zstatus = ftdm_span_find(span_id, &span);
+ }
+
+ if (zstatus != FTDM_SUCCESS) {
+ zstatus = ftdm_span_find_by_name(id, &span);
+ }
+ }
+
+ if (digit_timeout) {
+ to = atoi(digit_timeout);
+ }
+
+ if (zstatus != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+ continue;
+ }
+
+ if (!span_id) {
+ span_id = span->span_id;
+ }
+
+ if (!tonegroup) {
+ tonegroup = "us";
+ }
+
+ if (ftdm_configure_span("isdn", span, on_clear_channel_signal,
+ "mode", mode,
+ "dialect", dialect,
+ "digit_timeout", &to,
+ "opts", opts,
+ "tonemap", tonegroup,
+ "q921loglevel", q921loglevel,
+ "q931loglevel", q931loglevel,
+ TAG_END) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error starting FreeTDM span %d mode: %s dialect: %s error: %s\n", span_id, mode, dialect, span->last_error);
+ continue;
+ }
+
+ SPAN_CONFIG[span->span_id].span = span;
+ switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context));
+ switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan));
+ switch_copy_string(SPAN_CONFIG[span->span_id].type, "isdn", sizeof(SPAN_CONFIG[span->span_id].type));
+
+ ftdm_span_start(span);
+ }
+ }
+
+
+
+ if ((spans = switch_xml_child(cfg, "libpri_spans"))) {
+ for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+ char *id = (char *) switch_xml_attr(myspan, "id");
+ char *name = (char *) switch_xml_attr(myspan, "name");
+ ftdm_status_t zstatus = FTDM_FAIL;
+ const char *context = "default";
+ const char *dialplan = "XML";
+
+ const char *o_node = "cpe";
+ const char *o_switch = "dms100";
+ const char *o_dp = "unknown";
+ const char *o_l1 = "ulaw";
+ const char *o_debug = "none";
+ const char* opts = "none";
+
+ uint32_t span_id = 0;
+ ftdm_span_t *span = NULL;
+
+
+ for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+
+ if (!strcasecmp(var, "node")) {
+ o_node = val;
+ } else if (!strcasecmp(var, "switch")) {
+ o_switch = val;
+ } else if (!strcasecmp(var, "dp")) {
+ o_dp = val;
+ } else if (!strcasecmp(var, "l1")) {
+ o_l1 = val;
+ } else if (!strcasecmp(var, "debug")) {
+ o_debug = val;
+ } else if (!strcasecmp(var, "context")) {
+ context = val;
+ } else if (!strcasecmp(var, "opts")) {
+ opts = val;
+ } else if (!strcasecmp(var, "dialplan")) {
+ dialplan = val;
+ }
+ }
+
+ if (!id && !name) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+ continue;
+ }
+
+ if (name) {
+ zstatus = ftdm_span_find_by_name(name, &span);
+ } else {
+ if (switch_is_number(id)) {
+ span_id = atoi(id);
+ zstatus = ftdm_span_find(span_id, &span);
+ }
+
+ if (zstatus != FTDM_SUCCESS) {
+ zstatus = ftdm_span_find_by_name(id, &span);
+ }
+ }
+
+ if (zstatus != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+ continue;
+ }
+
+ if (!span_id) {
+ span_id = span->span_id;
+ }
+
+
+ if (ftdm_configure_span("libpri", span, on_clear_channel_signal,
+ "node", o_node,
+ "switch", o_switch,
+ "dp", o_dp,
+ "l1", o_l1,
+ "debug", o_debug,
+ "opts", opts,
+ TAG_END) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error starting FreeTDM span %d node: %s switch: %s dp: %s l1: %s debug: %s error: %s\n",
+ span_id, switch_str_nil(o_node), switch_str_nil(o_switch), switch_str_nil(o_dp), switch_str_nil(o_l1), switch_str_nil(o_debug),
+ span->last_error);
+ continue;
+ }
+
+ SPAN_CONFIG[span->span_id].span = span;
+ switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context));
+ switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan));
+ switch_copy_string(SPAN_CONFIG[span->span_id].type, "isdn", sizeof(SPAN_CONFIG[span->span_id].type));
+
+ ftdm_span_start(span);
+ }
+ }
+
+ if ((spans = switch_xml_child(cfg, "boost_spans"))) {
+ for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+ char *id = (char *) switch_xml_attr(myspan, "id");
+ char *name = (char *) switch_xml_attr(myspan, "name");
+ char *sigmod = (char *) switch_xml_attr(myspan, "sigmod");
+ ftdm_status_t zstatus = FTDM_FAIL;
+ const char *context = "default";
+ const char *dialplan = "XML";
+ uint32_t span_id = 0;
+ ftdm_span_t *span = NULL;
+ const char *tonegroup = NULL;
+ ftdm_conf_parameter_t spanparameters[30];
+ unsigned paramindex = 0;
+
+ if (!id && !name) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "boost span requires an id or name as attribute: <span id=ftid|name=ftname>\n");
+ continue;
+ }
+ memset(spanparameters, 0, sizeof(spanparameters));
+ if (sigmod) {
+ spanparameters[paramindex].var = "sigmod";
+ spanparameters[paramindex].val = sigmod;
+ paramindex++;
+ }
+
+ for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+ if (sizeof(spanparameters)/sizeof(spanparameters[0]) == paramindex) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Too many parameters for boost span, ignoring any parameter after %s\n", var);
+ break;
+ }
+ if (!strcasecmp(var, "tonegroup")) {
+ tonegroup = val;
+ } else if (!strcasecmp(var, "context")) {
+ context = val;
+ } else if (!strcasecmp(var, "dialplan")) {
+ dialplan = val;
+ } else {
+ spanparameters[paramindex].var = var;
+ spanparameters[paramindex].val = val;
+ paramindex++;
+ }
+ }
+
+ if (!tonegroup) {
+ tonegroup = "us";
+ }
+
+ if (name) {
+ zstatus = ftdm_span_find_by_name(name, &span);
+ } else {
+ if (switch_is_number(id)) {
+ span_id = atoi(id);
+ zstatus = ftdm_span_find(span_id, &span);
+ }
+
+ if (zstatus != FTDM_SUCCESS) {
+ zstatus = ftdm_span_find_by_name(id, &span);
+ }
+ }
+
+ if (zstatus != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+ continue;
+ }
+
+ if (!span_id) {
+ span_id = span->span_id;
+ }
+
+ if (ftdm_configure_span_signaling("sangoma_boost", span, on_clear_channel_signal, spanparameters) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error starting FreeTDM span %d error: %s\n", span_id, span->last_error);
+ continue;
+ }
+
+ SPAN_CONFIG[span->span_id].span = span;
+ switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context));
+ switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan));
+
+ switch_copy_string(SPAN_CONFIG[span->span_id].type, "Sangoma (boost)", sizeof(SPAN_CONFIG[span->span_id].type));
+ boost_spans[boosti++] = span;
+ }
+ }
+
+ if ((spans = switch_xml_child(cfg, "r2_spans"))) {
+ for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+ char *id = (char *) switch_xml_attr(myspan, "id");
+ char *name = (char *) switch_xml_attr(myspan, "name");
+ ftdm_status_t zstatus = FTDM_FAIL;
+
+ /* strings */
+ const char *variant = "itu";
+ const char *category = "national_subscriber";
+ const char *logdir = "/usr/local/freeswitch/log/"; /* FIXME: get PREFIX variable */
+ const char *logging = "notice,warning,error";
+ const char *advanced_protocol_file = "";
+
+ /* booleans */
+ int call_files = 0;
+ int get_ani_first = -1;
+ int immediate_accept = -1;
+ int double_answer = -1;
+ int skip_category = -1;
+ int forced_release = -1;
+ int charge_calls = -1;
+
+ /* integers */
+ int mfback_timeout = -1;
+ int metering_pulse_timeout = -1;
+ int allow_collect_calls = -1;
+ int max_ani = 10;
+ int max_dnis = 4;
+
+ /* common non r2 stuff */
+ const char *context = "default";
+ const char *dialplan = "XML";
+ char *dial_regex = NULL;
+ char *fail_dial_regex = NULL;
+ uint32_t span_id = 0;
+ ftdm_span_t *span = NULL;
+
+
+ for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+
+ /* string parameters */
+ if (!strcasecmp(var, "variant")) {
+ variant = val;
+ } else if (!strcasecmp(var, "category")) {
+ category = val;
+ } else if (!strcasecmp(var, "logdir")) {
+ logdir = val;
+ } else if (!strcasecmp(var, "logging")) {
+ logging = val;
+ } else if (!strcasecmp(var, "advanced_protocol_file")) {
+ advanced_protocol_file = val;
+
+ /* booleans */
+ } else if (!strcasecmp(var, "allow_collect_calls")) {
+ allow_collect_calls = switch_true(val);
+ } else if (!strcasecmp(var, "immediate_accept")) {
+ immediate_accept = switch_true(val);
+ } else if (!strcasecmp(var, "double_answer")) {
+ double_answer = switch_true(val);
+ } else if (!strcasecmp(var, "skip_category")) {
+ skip_category = switch_true(var);
+ } else if (!strcasecmp(var, "forced_release")) {
+ forced_release = switch_true(val);
+ } else if (!strcasecmp(var, "charge_calls")) {
+ charge_calls = switch_true(val);
+ } else if (!strcasecmp(var, "get_ani_first")) {
+ get_ani_first = switch_true(val);
+ } else if (!strcasecmp(var, "call_files")) {
+ call_files = switch_true(val);
+
+ /* integers */
+ } else if (!strcasecmp(var, "mfback_timeout")) {
+ mfback_timeout = atoi(val);
+ } else if (!strcasecmp(var, "metering_pulse_timeout")) {
+ metering_pulse_timeout = atoi(val);
+ } else if (!strcasecmp(var, "max_ani")) {
+ max_ani = atoi(val);
+ } else if (!strcasecmp(var, "max_dnis")) {
+ max_dnis = atoi(val);
+
+ /* common non r2 stuff */
+ } else if (!strcasecmp(var, "context")) {
+ context = val;
+ } else if (!strcasecmp(var, "dialplan")) {
+ dialplan = val;
+ } else if (!strcasecmp(var, "dial-regex")) {
+ dial_regex = val;
+ } else if (!strcasecmp(var, "fail-dial-regex")) {
+ fail_dial_regex = val;
+ }
+ }
+
+ if (!id && !name) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+ continue;
+ }
+
+ if (name) {
+ zstatus = ftdm_span_find_by_name(name, &span);
+ } else {
+ if (switch_is_number(id)) {
+ span_id = atoi(id);
+ zstatus = ftdm_span_find(span_id, &span);
+ }
+
+ if (zstatus != FTDM_SUCCESS) {
+ zstatus = ftdm_span_find_by_name(id, &span);
+ }
+ }
+
+ if (zstatus != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+ continue;
+ }
+
+ if (!span_id) {
+ span_id = span->span_id;
+ }
+
+ if (ftdm_configure_span("r2", span, on_r2_signal,
+ "variant", variant,
+ "max_ani", max_ani,
+ "max_dnis", max_dnis,
+ "category", category,
+ "logdir", logdir,
+ "logging", logging,
+ "advanced_protocol_file", advanced_protocol_file,
+ "allow_collect_calls", allow_collect_calls,
+ "immediate_accept", immediate_accept,
+ "double_answer", double_answer,
+ "skip_category", skip_category,
+ "forced_release", forced_release,
+ "charge_calls", charge_calls,
+ "get_ani_first", get_ani_first,
+ "call_files", call_files,
+ "mfback_timeout", mfback_timeout,
+ "metering_pulse_timeout", metering_pulse_timeout,
+ TAG_END) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error configuring R2 FreeTDM span %d, error: %s\n",
+ span_id, span->last_error);
+ continue;
+ }
+
+ if (dial_regex) {
+ switch_set_string(SPAN_CONFIG[span->span_id].dial_regex, dial_regex);
+ }
+
+ if (fail_dial_regex) {
+ switch_set_string(SPAN_CONFIG[span->span_id].fail_dial_regex, fail_dial_regex);
+ }
+
+ SPAN_CONFIG[span->span_id].span = span;
+ switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context));
+ switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan));
+ switch_copy_string(SPAN_CONFIG[span->span_id].type, "r2", sizeof(SPAN_CONFIG[span->span_id].type));
+
+ if (ftdm_span_start(span) == FTDM_FAIL) {
+ ftdm_log(FTDM_LOG_ERROR, "Error starting R2 FreeTDM span %d, error: %s\n", span_id, span->last_error);
+ continue;
+ }
+ }
+ }
+
+ /* start all boost spans now that we're done configuring. Unfortunately at this point boost modules have the limitation
+ * of needing all spans to be configured before starting them */
+ for ( ; i < boosti; i++) {
+ boost_span = boost_spans[i];
+ ftdm_log(FTDM_LOG_DEBUG, "Starting boost span %d\n", boost_span->span_id);
+ if (ftdm_span_start(boost_span) == FTDM_FAIL) {
+ ftdm_log(FTDM_LOG_ERROR, "Error starting boost FreeTDM span %d, error: %s\n", boost_span->span_id, boost_span->last_error);
+ continue;
+ }
+ }
+
+
+ switch_xml_free(xml);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+void dump_chan(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream)
+{
+ if (chan_id > span->chan_count) {
+ return;
+ }
+
+ stream->write_function(stream,
+ "span_id: %u\n"
+ "chan_id: %u\n"
+ "physical_span_id: %u\n"
+ "physical_chan_id: %u\n"
+ "type: %s\n"
+ "state: %s\n"
+ "last_state: %s\n"
+ "cid_date: %s\n"
+ "cid_name: %s\n"
+ "cid_num: %s\n"
+ "ani: %s\n"
+ "aniII: %s\n"
+ "dnis: %s\n"
+ "rdnis: %s\n"
+ "cause: %s\n\n",
+ span->channels[chan_id]->span_id,
+ span->channels[chan_id]->chan_id,
+ span->channels[chan_id]->physical_span_id,
+ span->channels[chan_id]->physical_chan_id,
+ ftdm_chan_type2str(span->channels[chan_id]->type),
+ ftdm_channel_state2str(span->channels[chan_id]->state),
+ ftdm_channel_state2str(span->channels[chan_id]->last_state),
+ span->channels[chan_id]->caller_data.cid_date,
+ span->channels[chan_id]->caller_data.cid_name,
+ span->channels[chan_id]->caller_data.cid_num.digits,
+ span->channels[chan_id]->caller_data.ani.digits,
+ span->channels[chan_id]->caller_data.aniII,
+ span->channels[chan_id]->caller_data.dnis.digits,
+ span->channels[chan_id]->caller_data.rdnis.digits,
+ switch_channel_cause2str(span->channels[chan_id]->caller_data.hangup_cause)
+ );
+}
+
+void dump_chan_xml(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream)
+{
+ if (chan_id > span->chan_count) {
+ return;
+ }
+
+ stream->write_function(stream,
+ " <channel>\n"
+ " <span-id>%u</span-id>\n"
+ " <chan-id>%u</chan-id>>\n"
+ " <physical-span-id>%u</physical-span-id>\n"
+ " <physical-chan-id>%u</physical-chan-id>\n"
+ " <type>%s</type>\n"
+ " <state>%s</state>\n"
+ " <last-state>%s</last-state>\n"
+ " <cid-date>%s</cid-date>\n"
+ " <cid-name>%s</cid-name>\n"
+ " <cid-num>%s</cid-num>\n"
+ " <ani>%s</ani>\n"
+ " <aniII>%s</aniII>\n"
+ " <dnis>%s</dnis>\n"
+ " <rdnis>%s</rdnis>\n"
+ " <cause>%s</cause>\n"
+ " </channel>\n",
+ span->channels[chan_id]->span_id,
+ span->channels[chan_id]->chan_id,
+ span->channels[chan_id]->physical_span_id,
+ span->channels[chan_id]->physical_chan_id,
+ ftdm_chan_type2str(span->channels[chan_id]->type),
+ ftdm_channel_state2str(span->channels[chan_id]->state),
+ ftdm_channel_state2str(span->channels[chan_id]->last_state),
+ span->channels[chan_id]->caller_data.cid_date,
+ span->channels[chan_id]->caller_data.cid_name,
+ span->channels[chan_id]->caller_data.cid_num.digits,
+ span->channels[chan_id]->caller_data.ani.digits,
+ span->channels[chan_id]->caller_data.aniII,
+ span->channels[chan_id]->caller_data.dnis.digits,
+ span->channels[chan_id]->caller_data.rdnis.digits,
+ switch_channel_cause2str(span->channels[chan_id]->caller_data.hangup_cause)
+ );
+}
+
+#define FT_SYNTAX "list || dump <span_id> [<chan_id>] || q931_pcap <span_id> on|off [pcapfilename without suffix] || gains <span> <txgain> <rxgain>"
+SWITCH_STANDARD_API(ft_function)
+{
+ char *mycmd = NULL, *argv[10] = { 0 };
+ int argc = 0;
+
+ if (!zstr(cmd) && (mycmd = strdup(cmd))) {
+ argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+ }
+
+ if (!argc) {
+ stream->write_function(stream, "%s", FT_SYNTAX);
+ goto end;
+ }
+
+ if (!strcasecmp(argv[0], "dump")) {
+ if (argc < 2) {
+ stream->write_function(stream, "-ERR Usage: ft dump <span_id> [<chan_id>]\n");
+ goto end;
+ } else {
+ uint32_t chan_id = 0;
+ ftdm_span_t *span;
+ char *as = NULL;
+
+ ftdm_span_find_by_name(argv[1], &span);
+
+ if (argc > 2) {
+ if (argv[3] && !strcasecmp(argv[2], "as")) {
+ as = argv[3];
+ } else {
+ chan_id = atoi(argv[2]);
+ }
+ }
+
+ if (argv[4] && !strcasecmp(argv[3], "as")) {
+ as = argv[4];
+ }
+
+ if (!zstr(as) && !strcasecmp(as, "xml")) {
+ stream->write_function(stream, "<channels>\n");
+ if (!span) {
+ stream->write_function(stream, "<error>invalid span</error>\n");
+ } else {
+ if (chan_id) {
+ if(chan_id > span->chan_count) {
+ stream->write_function(stream, "<error>invalid channel</error>\n");
+ } else {
+ dump_chan_xml(span, chan_id, stream);
+ }
+ } else {
+ uint32_t j;
+ for (j = 1; j <= span->chan_count; j++) {
+ dump_chan_xml(span, j, stream);
+ }
+
+ }
+ }
+ stream->write_function(stream, "</channels>\n");
+ } else {
+ if (!span) {
+ stream->write_function(stream, "-ERR invalid span\n");
+ } else {
+ if (chan_id) {
+ if(chan_id > span->chan_count) {
+ stream->write_function(stream, "-ERR invalid channel\n");
+ } else {
+ dump_chan(span, chan_id, stream);
+ }
+ } else {
+ uint32_t j;
+
+ stream->write_function(stream, "+OK\n");
+ for (j = 1; j <= span->chan_count; j++) {
+ dump_chan(span, j, stream);
+ }
+
+ }
+ }
+ }
+ }
+ } else if (!strcasecmp(argv[0], "list")) {
+ int j;
+ for (j = 0 ; j < FTDM_MAX_SPANS_INTERFACE; j++) {
+ if (SPAN_CONFIG[j].span) {
+ const char *flags = "none";
+ ftdm_signaling_status_t sigstatus;
+
+ if (SPAN_CONFIG[j].analog_options & ANALOG_OPTION_3WAY) {
+ flags = "3way";
+ } else if (SPAN_CONFIG[j].analog_options & ANALOG_OPTION_CALL_SWAP) {
+ flags = "call swap";
+ }
+
+ if ((FTDM_SUCCESS == ftdm_span_get_sig_status(SPAN_CONFIG[j].span, &sigstatus))) {
+ stream->write_function(stream,
+ "+OK\n"
+ "span: %u (%s)\n"
+ "type: %s\n"
+ "signaling_status: %s\n"
+ "chan_count: %u\n"
+ "dialplan: %s\n"
+ "context: %s\n"
+ "dial_regex: %s\n"
+ "fail_dial_regex: %s\n"
+ "hold_music: %s\n"
+ "analog_options %s\n",
+ j,
+ SPAN_CONFIG[j].span->name,
+ SPAN_CONFIG[j].type,
+ ftdm_signaling_status2str(sigstatus),
+ SPAN_CONFIG[j].span->chan_count,
+ SPAN_CONFIG[j].dialplan,
+ SPAN_CONFIG[j].context,
+ SPAN_CONFIG[j].dial_regex,
+ SPAN_CONFIG[j].fail_dial_regex,
+ SPAN_CONFIG[j].hold_music,
+ flags
+ );
+ } else {
+ stream->write_function(stream,
+ "+OK\n"
+ "span: %u (%s)\n"
+ "type: %s\n"
+ "chan_count: %u\n"
+ "dialplan: %s\n"
+ "context: %s\n"
+ "dial_regex: %s\n"
+ "fail_dial_regex: %s\n"
+ "hold_music: %s\n"
+ "analog_options %s\n",
+ j,
+ SPAN_CONFIG[j].span->name,
+ SPAN_CONFIG[j].type,
+ SPAN_CONFIG[j].span->chan_count,
+ SPAN_CONFIG[j].dialplan,
+ SPAN_CONFIG[j].context,
+ SPAN_CONFIG[j].dial_regex,
+ SPAN_CONFIG[j].fail_dial_regex,
+ SPAN_CONFIG[j].hold_music,
+ flags
+ );
+ }
+ }
+ }
+ } else if (!strcasecmp(argv[0], "stop") || !strcasecmp(argv[0], "start")) {
+ char *span_name = argv[1];
+ ftdm_span_t *span = NULL;
+ ftdm_status_t status;
+
+ if (span_name) {
+ ftdm_span_find_by_name(span_name, &span);
+ }
+
+ if (!span) {
+ stream->write_function(stream, "-ERR no span\n");
+ goto end;
+ }
+
+ if (!strcasecmp(argv[0], "stop")) {
+ status = ftdm_span_stop(span);
+ } else {
+ status = ftdm_span_start(span);
+ }
+
+ stream->write_function(stream, status == FTDM_SUCCESS ? "+OK\n" : "-ERR failure\n");
+
+ goto end;
+
+ /*Q931ToPcap enhancement*/
+ } else if (!strcasecmp(argv[0], "q931_pcap")) {
+ int32_t span_id = 0;
+ ftdm_span_t *span;
+ const char *pcapfn = NULL;
+ char *tmp_path = NULL;
+
+ if (argc < 3) {
+ stream->write_function(stream, "-ERR Usage: ft q931_pcap <span_id> on|off [pcapfilename without suffix]\n");
+ goto end;
+ }
+ span_id = atoi(argv[1]);
+ if (!(span_id && (span = SPAN_CONFIG[span_id].span))) {
+ stream->write_function(stream, "-ERR invalid span\n");
+ goto end;
+ }
+
+ /*Look for a given file name or use default file name*/
+ if (argc > 3) {
+ if(argv[3]){
+ pcapfn=argv[3];
+ }
+ }
+ else {
+ pcapfn="q931";
+ }
+
+ /*Add log directory path to file name*/
+ tmp_path=switch_mprintf("%s%s%s.pcap", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR, pcapfn);
+
+ if(!strcasecmp(argv[2], "on")) {
+ if (ftdm_configure_span("isdn", span, on_clear_channel_signal, "q931topcap", 1, "pcapfilename", tmp_path, TAG_END) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_WARNING, "Error couldn't (re-)enable Q931-To-Pcap!\n");
+ goto end;
+ } else {
+ stream->write_function(stream, "+OK\n");
+ }
+ } else if(!strcasecmp(argv[2], "off")) {
+ if (ftdm_configure_span("isdn", span, on_clear_channel_signal, "q931topcap", 0, TAG_END) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error couldn't enable Q931-To-Pcap!\n");
+ goto end;
+ } else {
+ stream->write_function(stream, "+OK\n");
+ }
+ } else {
+ stream->write_function(stream, "-ERR Usage: ft q931_pcap <span_id> on|off [pcapfilename without suffix]\n");
+ goto end;
+ }
+
+ } else if (!strcasecmp(argv[0], "gains")) {
+ unsigned int i = 0;
+ float txgain = 0.0;
+ float rxgain = 0.0;
+ uint32_t chan_id = 0;
+ ftdm_span_t *span = NULL;
+ if (argc < 4) {
+ stream->write_function(stream, "-ERR Usage: ft gains <txgain> <rxgain> <span_id> [<chan_id>]\n");
+ goto end;
+ }
+ ftdm_span_find_by_name(argv[3], &span);
+ if (!span) {
+ stream->write_function(stream, "-ERR invalid span\n");
+ goto end;
+ }
+ if (argc > 4) {
+ chan_id = atoi(argv[4]);
+ if (chan_id > span->chan_count) {
+ stream->write_function(stream, "-ERR invalid chan\n");
+ goto end;
+ }
+ }
+ i = sscanf(argv[1], "%f", &rxgain);
+ i += sscanf(argv[2], "%f", &txgain);
+ if (i != 2) {
+ stream->write_function(stream, "-ERR invalid gains\n");
+ goto end;
+ }
+ if (chan_id) {
+ ftdm_channel_command(span->channels[chan_id], FTDM_COMMAND_SET_RX_GAIN, &rxgain);
+ ftdm_channel_command(span->channels[chan_id], FTDM_COMMAND_SET_TX_GAIN, &txgain);
+ } else {
+ for (i = 1; i < span->chan_count; i++) {
+ ftdm_channel_command(span->channels[i], FTDM_COMMAND_SET_RX_GAIN, &rxgain);
+ ftdm_channel_command(span->channels[i], FTDM_COMMAND_SET_TX_GAIN, &txgain);
+ }
+ }
+ stream->write_function(stream, "+OK gains set to Rx %f and Tx %f\n", rxgain, txgain);
+ } else {
+ char *rply = ftdm_api_execute(cmd, NULL);
+
+ if (rply) {
+ stream->write_function(stream, "%s", rply);
+ free(rply);
+ } else {
+ stream->write_function(stream, "-ERR Usage: %s\n", FT_SYNTAX);
+ }
+ }
+ /*Q931ToPcap enhancement done*/
+
+ end:
+
+ switch_safe_free(mycmd);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+SWITCH_STANDARD_APP(disable_ec_function)
+{
+ private_t *tech_pvt;
+ int x = 0;
+
+ if (!switch_core_session_check_interface(session, freetdm_endpoint_interface)) {
+ ftdm_log(FTDM_LOG_ERROR, "This application is only for FreeTDM channels.\n");
+ return;
+ }
+
+ tech_pvt = switch_core_session_get_private(session);
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ switch_channel_hangup(switch_core_session_get_channel(session), SWITCH_CAUSE_LOSE_RACE);
+ return;
+ }
+
+ ftdm_channel_command(tech_pvt->ftdmchan, FTDM_COMMAND_DISABLE_ECHOCANCEL, &x);
+ ftdm_channel_command(tech_pvt->ftdmchan, FTDM_COMMAND_DISABLE_ECHOTRAIN, &x);
+ ftdm_log(FTDM_LOG_INFO, "Echo Canceller Disabled\n");
+}
+
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_freetdm_load)
+{
+
+ switch_api_interface_t *commands_api_interface;
+ switch_application_interface_t *app_interface;
+
+ module_pool = pool;
+
+ ftdm_global_set_logger(ftdm_logger);
+
+ if (ftdm_global_init() != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error loading FreeTDM\n");
+ return SWITCH_STATUS_TERM;
+ }
+
+ if (ftdm_global_configuration() != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error configuring FreeTDM\n");
+ return SWITCH_STATUS_TERM;
+ }
+
+ if (load_config() != SWITCH_STATUS_SUCCESS) {
+ ftdm_global_destroy();
+ return SWITCH_STATUS_TERM;
+ }
+
+ *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+ freetdm_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
+ freetdm_endpoint_interface->interface_name = "freetdm";
+ freetdm_endpoint_interface->io_routines = &freetdm_io_routines;
+ freetdm_endpoint_interface->state_handler = &freetdm_state_handlers;
+
+ SWITCH_ADD_API(commands_api_interface, "ftdm", "FreeTDM commands", ft_function, FT_SYNTAX);
+
+ SWITCH_ADD_APP(app_interface, "disable_ec", "Disable Echo Canceller", "Disable Echo Canceller", disable_ec_function, "", SAF_NONE);
+
+ /* indicate that the module should continue to be loaded */
+ return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_freetdm_shutdown)
+{
+ ftdm_global_destroy();
+
+ // this breaks pika but they are MIA so *shrug*
+ //return SWITCH_STATUS_NOUNLOAD;
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/mod_freetdm/mod_openzap.2005.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/mod_freetdm/mod_openzap.2005.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/mod_freetdm/mod_openzap.2005.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="mod_freetdm"
+ ProjectGUID="{FE3540C5-3303-46E0-A69E-D92F775687F1}"
+ RootNamespace="mod_freetdm"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="FreeSwitchCore.lib"
+ OutputFile="$(SolutionDir)$(OutDir)/mod/$(InputName).dll"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=""../../../w32/Library/$(OutDir)""
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+ SubSystem="2"
+ ImportLibrary="$(OutDir)/mod_freetdm.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="FreeSwitchCore.lib"
+ OutputFile="$(SolutionDir)$(OutDir)/mod/$(InputName).dll"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories=""../../../w32/Library/$(OutDir)""
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ LinkTimeCodeGeneration="1"
+ ImportLibrary="$(OutDir)/mod_freetdm.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\mod_freetdm.c"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/msvc/freetdm.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/msvc/freetdm.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/msvc/freetdm.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,455 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="freetdm"
+ ProjectGUID="{93B8812C-3EC4-4F78-8970-FFBFC99E167D}"
+ RootNamespace="freetdm"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ BuildLogFile="$(IntDir)\BuildLog-freetdm.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ DisableLanguageExtensions="false"
+ RuntimeTypeInfo="false"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ GenerateDebugInformation="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-freetdm.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS"
+ RuntimeLibrary="2"
+ DisableLanguageExtensions="false"
+ RuntimeTypeInfo="false"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ BuildLogFile="$(IntDir)\BuildLog-freetdm.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ DisableLanguageExtensions="false"
+ RuntimeTypeInfo="false"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ GenerateDebugInformation="true"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-freetdm.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS"
+ RuntimeLibrary="2"
+ DisableLanguageExtensions="false"
+ RuntimeTypeInfo="false"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\src\include\fsk.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\g711.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\hashtable.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\hashtable_itr.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\hashtable_private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\libteletone.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\libteletone_detect.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\libteletone_generate.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\freetdm.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\uart.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\ftdm_buffer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\ftdm_config.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\ftdm_dso.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\ftdm_threadmutex.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\ftdm_types.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\src\fsk.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\g711.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hashtable.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hashtable_itr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\libteletone_detect.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\libteletone_generate.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\uart.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\ftdm_buffer.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\ftdm_callerid.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\ftdm_config.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\ftdm_dso.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\ftdm_io.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\ftdm_queue.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\ftdm_threadmutex.c"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/msvc/openzap.2005.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/msvc/openzap.2005.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/msvc/openzap.2005.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,301 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="freetdm"
+ ProjectGUID="{93B8812C-3EC4-4F78-8970-FFBFC99E167D}"
+ RootNamespace="freetdm"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ BuildLogFile="$(IntDir)\BuildLog-freetdm.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ DisableLanguageExtensions="false"
+ RuntimeTypeInfo="false"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-freetdm.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS"
+ RuntimeLibrary="2"
+ DisableLanguageExtensions="false"
+ RuntimeTypeInfo="false"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\src\fsk.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\g711.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hashtable.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hashtable_itr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\libteletone_detect.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\libteletone_generate.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\uart.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\ftdm_buffer.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\ftdm_callerid.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\ftdm_config.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\ftdm_dso.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\ftdm_io.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\ftdm_threadmutex.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\src\include\fsk.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\g711.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\hashtable.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\hashtable_itr.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\hashtable_private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\libteletone.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\libteletone_detect.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\libteletone_generate.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\freetdm.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\uart.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\ftdm_buffer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\ftdm_config.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\ftdm_dso.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\ftdm_threadmutex.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\ftdm_types.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/msvc/testanalog/testanalog.2005.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/msvc/testanalog/testanalog.2005.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/msvc/testanalog/testanalog.2005.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="testanalog"
+ ProjectGUID="{BB833648-BAFF-4BE2-94DB-F8BB043C588C}"
+ RootNamespace="testanalog"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\src\testanalog.c"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/msvc/testanalog/testanalog.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/msvc/testanalog/testanalog.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/msvc/testanalog/testanalog.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,349 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="testanalog"
+ ProjectGUID="{BB833648-BAFF-4BE2-94DB-F8BB043C588C}"
+ RootNamespace="testanalog"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\src\testanalog.c"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/msvc/testboost/testboost.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/msvc/testboost/testboost.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/msvc/testboost/testboost.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="testboost"
+ ProjectGUID="{2B1BAF36-0241-43E7-B865-A8338AD48E2E}"
+ RootNamespace="testboost"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ BuildLogFile="$(IntDir)\BuildLog-testboost.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../src/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="..\..\debug\freetdm.lib"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-testboost.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../src/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\src\testboost.c"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/msvc/testboost/testsangomaboost.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/msvc/testboost/testsangomaboost.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/msvc/testboost/testsangomaboost.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="testsangomaboost"
+ ProjectGUID="{0DA69C18-4FA1-4E8C-89CE-12498637C5BE}"
+ RootNamespace="testsangomaboost"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ BuildLogFile="$(IntDir)\BuildLog-testsangomaboost.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../src/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="..\..\debug\freetdm.lib"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-testsangomaboost.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../src/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\src\testsangomaboost.c"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/msvc/testisdn/testisdn.2005.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/msvc/testisdn/testisdn.2005.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/msvc/testisdn/testisdn.2005.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="testisdn"
+ ProjectGUID="{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}"
+ RootNamespace="testisdn"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\src\testisdn.c"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/msvc/testisdn/testisdn.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/msvc/testisdn/testisdn.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/msvc/testisdn/testisdn.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,349 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="testisdn"
+ ProjectGUID="{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}"
+ RootNamespace="testisdn"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\src\testisdn.c"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/openzap.2005.sln (0 => 17141)
--- freeswitch/trunk/libs/freetdm/openzap.2005.sln (rev 0)
+++ freeswitch/trunk/libs/freetdm/openzap.2005.sln 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,82 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openzap", "msvc\openzap.2005.vcproj", "{93B8812C-3EC4-4F78-8970-FFBFC99E167D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testanalog", "msvc\testanalog\testanalog.2005.vcproj", "{BB833648-BAFF-4BE2-94DB-F8BB043C588C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testisdn", "msvc\testisdn\testisdn.2005.vcproj", "{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_openzap", "mod_openzap\mod_openzap.2005.vcproj", "{FE3540C5-3303-46E0-A69E-D92F775687F1}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_analog", "src\ozmod\ozmod_analog\ozmod_analog.2005.vcproj", "{37C94798-6E33-4B4F-8EE0-C72A7DC91157}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_analog_em", "src\ozmod\ozmod_analog_em\ozmod_analog_em.2005.vcproj", "{C539D7C8-26A8-4A94-B938-77672165C130}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_isdn", "src\ozmod\ozmod_isdn\ozmod_isdn.2005.vcproj", "{729344A5-D5E9-434D-8EE8-AF8C6C795D15}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_wanpipe", "src\ozmod\ozmod_wanpipe\ozmod_wanpipe.2005.vcproj", "{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_pika", "src\ozmod\ozmod_pika\ozmod_pika.2005.vcproj", "{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.Build.0 = Debug|Win32
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.ActiveCfg = Release|Win32
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.Build.0 = Release|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.Build.0 = Debug|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.ActiveCfg = Release|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.Build.0 = Release|Win32
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.Build.0 = Debug|Win32
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.ActiveCfg = Release|Win32
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.Build.0 = Release|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.Build.0 = Debug|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.ActiveCfg = Release|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.Build.0 = Release|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.ActiveCfg = Debug|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.Build.0 = Debug|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.ActiveCfg = Release|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.Build.0 = Release|Win32
+ {C539D7C8-26A8-4A94-B938-77672165C130}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C539D7C8-26A8-4A94-B938-77672165C130}.Debug|Win32.Build.0 = Debug|Win32
+ {C539D7C8-26A8-4A94-B938-77672165C130}.Release|Win32.ActiveCfg = Release|Win32
+ {C539D7C8-26A8-4A94-B938-77672165C130}.Release|Win32.Build.0 = Release|Win32
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.ActiveCfg = Debug|Win32
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.Build.0 = Debug|Win32
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.ActiveCfg = Release|Win32
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.Build.0 = Release|Win32
+ {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|Win32.ActiveCfg = Release|Win32
+ {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Release|Win32.ActiveCfg = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
Added: freeswitch/trunk/libs/freetdm/ozrename.sh (0 => 17141)
--- freeswitch/trunk/libs/freetdm/ozrename.sh (rev 0)
+++ freeswitch/trunk/libs/freetdm/ozrename.sh 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,99 @@
+# renaming main header and build file
+copy="cp -r"
+
+$copy src/include/openzap.h src/include/freetdm.h
+svn delete src/include/openzap.h
+$copy openzap.pc.in freetdm.pc.in
+svn delete openzap.pc.in
+
+# create mod_freetdm
+mkdir mod_freetdm
+cp mod_openzap/* mod_freetdm/
+mv mod_freetdm/mod_openzap.c mod_freetdm/mod_freetdm.c
+svn delete --force mod_openzap
+
+
+##### ozmod stuff ####
+# rename anything ozmod to ftmod, including directories first
+mkdir ./src/ftmod
+for file in `find ./src/ozmod -name *ozmod_* -type d`
+do
+ $copy ${file} ${file//ozmod/ftmod}
+done
+
+#remove .svn directories in the copied ozmod dirs
+find ./src/ftmod -name *.svn -exec rm -rf {} \;
+
+# copy ozmod c files
+for file in `find ./src/ftmod -name *ozmod_*.c`
+do
+ mv $file ${file//ozmod/ftmod}
+done
+
+# copy ozmod h files
+for file in `find ./src/ftmod -name *ozmod_*.h`
+do
+ mv $file ${file//ozmod/ftmod}
+done
+
+#### end ozmod stuff ####
+
+# renaming other zap files
+for file in `find ./ -name *zap_*.c`
+do
+ mv $file ${file//zap_/ftdm_}
+done
+
+for file in `find ./ -name *zap_*.h`
+do
+ mv $file ${file//zap_/ftdm_}
+done
+
+svn revert -R src/ozmod
+svn delete --force src/ozmod
+
+# replace full openzap occurences first (handles openzap.h, libopenzap etc)
+find ./ -name *.c -exec sed -i 's,openzap,freetdm,g' {} \;
+
+find ./ -name *.h -exec sed -i 's,openzap,freetdm,g' {} \;
+
+sed -i 's,openzap,freetdm,g' Makefile.am
+
+sed -i 's,openzap,freetdm,g' configure.ac
+
+sed -i 's,openzap,freetdm,g' mod_freetdm/Makefile.in
+
+# replace inside files
+find ./ -name *.c -exec sed -i 's,oz,ft,g' {} \;
+find ./ -name *.c -exec sed -i 's,OZ,FT,g' {} \;
+find ./ -name *.c -exec sed -i 's,zap,ftdm,g' {} \;
+find ./ -name *.c -exec sed -i 's,ZAP,FTDM,g' {} \;
+find ./ -name *.c -exec sed -i 's,zchan,ftdmchan,g' {} \;
+
+find ./ -name *.h -exec sed -i 's,oz,ft,g' {} \;
+find ./ -name *.h -exec sed -i 's,OZ,FT,g' {} \;
+find ./ -name *.h -exec sed -i 's,zap,ftdm,g' {} \;
+find ./ -name *.h -exec sed -i 's,ZAP,FTDM,g' {} \;
+find ./ -name *.h -exec sed -i 's,zchan,ftdmchan,g' {} \;
+
+sed -i 's,oz,ft,g' Makefile.am
+sed -i 's,OZ,FT,g' Makefile.am
+sed -i 's,zap,ftdm,g' Makefile.am
+sed -i 's,ZAP,FTDM,g' Makefile.am
+sed -i 's,zchan,ftdmchan,g' Makefile.am
+
+sed -i 's,oz,ft,g' configure.ac
+sed -i 's,OZ,FT,g' configure.ac
+sed -i 's,zap,ftdm,g' configure.ac
+sed -i 's,ZAP,FTDM,g' configure.ac
+sed -i 's,zchan,ftdmchan,g' configure.ac
+
+sed -i 's,oz,ft,g' mod_freetdm/Makefile.in
+sed -i 's,OZ,FT,g' mod_freetdm/Makefile.in
+sed -i 's,zap,ftdm,g' mod_freetdm/Makefile.in
+sed -i 's,ZAP,FTDM,g' mod_freetdm/Makefile.in
+sed -i 's,zchan,ftdmchan,g' mod_freetdm/Makefile.in
+
+svn add src/ftmod/
+svn add mod_freetdm/
+
Property changes on: freeswitch/trunk/libs/freetdm/ozrename.sh
___________________________________________________________________
Name: svn:executable
+ *
Added: freeswitch/trunk/libs/freetdm/ozreplace.sh (0 => 17141)
--- freeswitch/trunk/libs/freetdm/ozreplace.sh (rev 0)
+++ freeswitch/trunk/libs/freetdm/ozreplace.sh 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,13 @@
+##### ozmod stuff ####
+# replace full openzap occurences first (handles openzap.h, libopenzap etc)
+sed -i 's,openzap,freetdm,g' $1
+sed -i 's,ozmod,ftmod,g' $1
+
+sed -i 's,zchan,ftdmchan,g' $1
+sed -i 's,oz,ft,g' $1
+sed -i 's,OZ,FT,g' $1
+sed -i 's,zap,ftdm,g' $1
+sed -i 's,ZAP,FTDM,g' $1
+sed -i 's,zio,fio,g' $1
+sed -i 's,ZIO,FIO,g' $1
+
Property changes on: freeswitch/trunk/libs/freetdm/ozreplace.sh
___________________________________________________________________
Name: svn:executable
+ *
Added: freeswitch/trunk/libs/freetdm/patches/oz.diff (0 => 17141)
--- freeswitch/trunk/libs/freetdm/patches/oz.diff (rev 0)
+++ freeswitch/trunk/libs/freetdm/patches/oz.diff 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,134 @@
+Index: src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c
+===================================================================
+--- src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c (revision 745)
++++ src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c (working copy)
+@@ -98,19 +98,21 @@
+ * so we can have one analong handler thread that will deal with all the idle analog channels for events
+ * the alternative would be for the driver to provide one socket for all of the oob events for all analog channels
+ */
+-static __inline__ int tdmv_api_wait_socket(sng_fd_t fd, int timeout, int *flags)
++static __inline__ int tdmv_api_wait_socket(zap_channel_t *zchan, int timeout, int *flags)
+ {
+
+ #ifdef LIBSANGOMA_VERSION
+ int err;
+- sangoma_wait_obj_t sangoma_wait_obj;
++ sangoma_wait_obj_t *sangoma_wait_obj = zchan->mod_data;
+
+- sangoma_init_wait_obj(&sangoma_wait_obj, fd, 1, 1, *flags, SANGOMA_WAIT_OBJ);
++ sangoma_init_wait_obj(sangoma_wait_obj, zchan->sockfd, 1, 1, 0, SANGOMA_WAIT_OBJ);
+
+- err=sangoma_socket_waitfor_many(&sangoma_wait_obj,1 , timeout);
++ err = sangoma_socket_waitfor_many(&sangoma_wait_obj, 1, timeout);
++
+ if (err > 0) {
+- *flags=sangoma_wait_obj.flags_out;
++ *flags = sangoma_wait_obj.flags_out;
+ }
++
+ return err;
+
+ #else
+@@ -118,7 +120,7 @@
+ int res;
+
+ memset(&pfds[0], 0, sizeof(pfds[0]));
+- pfds[0].fd = fd;
++ pfds[0].fd = zchan->sockfd;
+ pfds[0].events = *flags;
+ res = poll(pfds, 1, timeout);
+ *flags = 0;
+@@ -200,6 +202,15 @@
+
+ if (sockfd != WP_INVALID_SOCKET && zap_span_add_channel(span, sockfd, type, &chan) == ZAP_SUCCESS) {
+ wanpipe_tdm_api_t tdm_api;
++#ifdef LIBSANGOMA_VERSION
++ sangoma_wait_obj_t *sangoma_wait_obj;
++
++ sangoma_wait_obj = malloc(sizeof(*sangoma_wait_obj));
++ memset(sangoma_wait_obj, 0, sizeof(*sangoma_wait_obj));
++ sangoma_init_wait_obj(sangoma_wait_obj, sockfd, 1, 1, 0, SANGOMA_WAIT_OBJ);
++ chan->mod_data = sangoma_wait_obj;
++#endif
++
+ memset(&tdm_api,0,sizeof(tdm_api));
+
+ chan->physical_span_id = spanno;
+@@ -211,7 +222,7 @@
+
+ dtmf = "software";
+
+- /* FIXME: Handle Error Conditino Check for return code */
++ /* FIXME: Handle Error Condition Check for return code */
+ err= sangoma_tdm_get_hw_coding(chan->sockfd, &tdm_api);
+
+ if (tdm_api.wp_tdm_cmd.hw_tdm_coding) {
+@@ -606,7 +617,7 @@
+ inflags |= POLLPRI;
+ }
+
+- result = tdmv_api_wait_socket(zchan->sockfd, to, &inflags);
++ result = tdmv_api_wait_socket(zchan, to, &inflags);
+
+ *flags = ZAP_NO_FLAGS;
+
+@@ -643,26 +654,30 @@
+ ZIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event)
+ {
+ #ifdef LIBSANGOMA_VERSION
+- sangoma_wait_obj_t pfds[ZAP_MAX_CHANNELS_SPAN];
++ sangoma_wait_obj_t *pfds[ZAP_MAX_CHANNELS_SPAN] = { 0 };
+ #else
+ struct pollfd pfds[ZAP_MAX_CHANNELS_SPAN];
+ #endif
+
+ uint32_t i, j = 0, k = 0, l = 0;
+- int objects=0;
+ int r;
+
+ for(i = 1; i <= span->chan_count; i++) {
+ zap_channel_t *zchan = span->channels[i];
+
++
+ #ifdef LIBSANGOMA_VERSION
+- sangoma_init_wait_obj(&pfds[j], zchan->sockfd , 1, 1, POLLPRI, SANGOMA_WAIT_OBJ);
++ if (!zchan->mod_data) {
++ continue;
++ }
++ pfds[j] = zchan->mod_data;
++
+ #else
+ memset(&pfds[j], 0, sizeof(pfds[j]));
+ pfds[j].fd = span->channels[i]->sockfd;
+ pfds[j].events = POLLPRI;
+ #endif
+- objects++;
++
+ /* The driver probably should be able to do this wink/flash/ringing by itself this is sort of a hack to make it work! */
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_WINK) || zap_test_flag(zchan, ZAP_CHANNEL_FLASH)) {
+@@ -703,7 +718,7 @@
+ ms = l;
+ }
+ #ifdef LIBSANGOMA_VERSION
+- r = sangoma_socket_waitfor_many(pfds,objects,ms);
++ r = sangoma_socket_waitfor_many(pfds, j, ms);
+ #else
+ r = poll(pfds, j, ms);
+ #endif
+@@ -935,6 +950,15 @@
+ */
+ static ZIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy)
+ {
++ sangoma_wait_obj_t *sangoma_wait_obj;
++
++ if (zchan->mod_data) {
++ sangoma_wait_obj = zchan->mod_data;
++ zchan->mod_data = NULL;
++ sangoma_release_wait_obj(sangoma_wait_obj);
++ free(sangoma_wait_obj);
++ }
++
+ if (zchan->sockfd > -1) {
+ close(zchan->sockfd);
+ zchan->sockfd = WP_INVALID_SOCKET;
Added: freeswitch/trunk/libs/freetdm/src/detect_dtmf.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/detect_dtmf.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/detect_dtmf.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,33 @@
+//#include "freetdm.h"
+#include "libteletone_detect.h"
+
+int main(int argc, char *argv[])
+{
+ int fd, b;
+ short sln[512] = {0};
+ teletone_dtmf_detect_state_t dtmf_detect = {0};
+ char digit_str[128] = "";
+
+ if (argc < 2) {
+ fprintf(stderr, "Arg Error!\n");
+ exit(-1);
+ }
+
+ teletone_dtmf_detect_init (&dtmf_detect, 8000);
+
+ if ((fd = open(argv[1], O_RDONLY)) < 0) {
+ fprintf(stderr, "File Error! [%s]\n", strerror(errno));
+ exit(-1);
+ }
+
+ while((b = read(fd, sln, 320)) > 0) {
+ teletone_dtmf_detect(&dtmf_detect, sln, b / 2);
+ teletone_dtmf_get(&dtmf_detect, digit_str, sizeof(digit_str));
+ if (*digit_str) {
+ printf("digit: %s\n", digit_str);
+ }
+ }
+ close(fd);
+ return 0;
+}
+
Added: freeswitch/trunk/libs/freetdm/src/detect_tones.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/detect_tones.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/detect_tones.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,32 @@
+//#include "freetdm.h"
+#include "libteletone_detect.h"
+
+int main(int argc, char *argv[])
+{
+ teletone_multi_tone_t mt = {0};
+ teletone_tone_map_t map = {{0}};
+
+ int fd, b;
+ short sln[512] = {0};
+
+ if (argc < 2) {
+ fprintf(stderr, "Arg Error!\n");
+ exit(-1);
+ }
+
+ map.freqs[0] = atof("350");
+ map.freqs[1] = atof("440");
+ teletone_multi_tone_init(&mt, &map);
+
+ if ((fd = open(argv[1], O_RDONLY)) < 0) {
+ fprintf(stderr, "File Error! [%s]\n", strerror(errno));
+ exit(-1);
+ }
+
+ while((b = read(fd, sln, 320)) > 0) {
+ printf("TEST %d %d\n", b, teletone_multi_tone_detect(&mt, sln, b / 2));
+ }
+ close(fd);
+ return 0;
+}
+
Added: freeswitch/trunk/libs/freetdm/src/fsk.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/fsk.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/fsk.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,351 @@
+
+/*
+ * bell202.c
+ *
+ * Copyright (c) 2005 Robert Krten. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * This module contains a Bell-202 1200-baud FSK decoder, suitable for
+ * use in a library. The general style of the library calls is modeled
+ * after the POSIX pthread_*() functions.
+ *
+ * 2005 03 20 R. Krten created
+*/
+#include <freetdm.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+
+#include "fsk.h"
+#include "uart.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+fsk_modem_definition_t fsk_modem_definitions[] =
+{
+ { /* FSK_V23_FORWARD_MODE1 */ 1700, 1300, 600 },
+ { /* FSK_V23_FORWARD_MODE2 */ 2100, 1300, 1200 },
+ { /* FSK_V23_BACKWARD */ 450, 390, 75 },
+ { /* FSK_BELL202 */ 2200, 1200, 1200 },
+};
+
+/*
+ * dsp_fsk_attr_init
+ *
+ * Initializes the attributes structure; this must be done before the
+ * attributes structure is used.
+*/
+
+void dsp_fsk_attr_init (dsp_fsk_attr_t *attr)
+{
+ memset(attr, 0, sizeof(*attr));
+}
+
+/*
+ * dsp_fsk_attr_get_bithandler
+ * dsp_fsk_attr_set_bithandler
+ * dsp_fsk_attr_get_bytehandler
+ * dsp_fsk_attr_set_bytehandler
+ * dsp_fsk_attr_getsamplerate
+ * dsp_fsk_attr_setsamplerate
+ *
+ * These functions get and set their respective elements from the
+ * attributes structure. If an error code is returned, it is just
+ * zero == ok, -1 == fail.
+*/
+
+bithandler_func_t dsp_fsk_attr_get_bithandler(dsp_fsk_attr_t *attr, void **bithandler_arg)
+{
+ *bithandler_arg = attr->bithandler_arg;
+ return attr->bithandler;
+}
+
+void dsp_fsk_attr_set_bithandler(dsp_fsk_attr_t *attr, bithandler_func_t bithandler, void *bithandler_arg)
+{
+ attr->bithandler = bithandler;
+ attr->bithandler_arg = bithandler_arg;
+}
+
+bytehandler_func_t dsp_fsk_attr_get_bytehandler(dsp_fsk_attr_t *attr, void **bytehandler_arg)
+{
+ *bytehandler_arg = attr->bytehandler_arg;
+ return attr->bytehandler;
+}
+
+void dsp_fsk_attr_set_bytehandler(dsp_fsk_attr_t *attr, bytehandler_func_t bytehandler, void *bytehandler_arg)
+{
+ attr->bytehandler = bytehandler;
+ attr->bytehandler_arg = bytehandler_arg;
+}
+
+int dsp_fsk_attr_get_samplerate (dsp_fsk_attr_t *attr)
+{
+ return attr->sample_rate;
+}
+
+int dsp_fsk_attr_set_samplerate (dsp_fsk_attr_t *attr, int samplerate)
+{
+ if (samplerate <= 0) {
+ return -1;
+ }
+ attr->sample_rate = samplerate;
+ return 0;
+}
+
+/*
+ * dsp_fsk_create
+ *
+ * Creates a handle for subsequent use. The handle is created to contain
+ * a context data structure for use by the sample handler function. The
+ * function expects an initialized attributes structure, and returns the
+ * handle or a NULL if there were errors.
+ *
+ * Once created, the handle can be used until it is destroyed.
+*/
+
+dsp_fsk_handle_t *dsp_fsk_create(dsp_fsk_attr_t *attr)
+{
+ int i;
+ double phi_mark, phi_space;
+ dsp_fsk_handle_t *handle;
+
+ handle = ftdm_malloc(sizeof(*handle));
+ if (!handle) {
+ return NULL;
+ }
+
+ memset(handle, 0, sizeof(*handle));
+
+ /* fill the attributes member */
+ memcpy(&handle->attr, attr, sizeof(*attr));
+
+ /* see if we can do downsampling. We only really need 6 samples to "match" */
+ if (attr->sample_rate / fsk_modem_definitions[FSK_BELL202].freq_mark > 6) {
+ handle->downsampling_count = attr->sample_rate / fsk_modem_definitions[FSK_BELL202].freq_mark / 6;
+ } else {
+ handle->downsampling_count = 1;
+ }
+ handle->current_downsample = 1;
+
+ /* calculate the correlate size (number of samples required for slowest wave) */
+ handle->corrsize = attr->sample_rate / handle->downsampling_count / fsk_modem_definitions[FSK_BELL202].freq_mark;
+
+ /* allocate the correlation sin/cos arrays and initialize */
+ for (i = 0; i < 4; i++) {
+ handle->correlates[i] = ftdm_malloc(sizeof(double) * handle->corrsize);
+ if (handle->correlates[i] == NULL) {
+ /* some failed, back out memory allocations */
+ dsp_fsk_destroy(&handle);
+ return NULL;
+ }
+ }
+
+ /* now initialize them */
+ phi_mark = 2. * M_PI / ((double) attr->sample_rate / (double) handle->downsampling_count / (double) fsk_modem_definitions[FSK_BELL202].freq_mark);
+ phi_space = 2. * M_PI / ((double) attr->sample_rate / (double) handle->downsampling_count / (double) fsk_modem_definitions[FSK_BELL202].freq_space);
+
+ for (i = 0; i < handle->corrsize; i++) {
+ handle->correlates[0][i] = sin(phi_mark * (double) i);
+ handle->correlates[1][i] = cos(phi_mark * (double) i);
+ handle->correlates[2][i] = sin(phi_space * (double) i);
+ handle->correlates[3][i] = cos(phi_space * (double) i);
+ }
+
+ /* initialize the ring buffer */
+ handle->buffer = ftdm_malloc(sizeof(double) * handle->corrsize);
+ if (!handle->buffer) { /* failed; back out memory allocations */
+ dsp_fsk_destroy(&handle);
+ return NULL;
+ }
+ memset(handle->buffer, 0, sizeof(double) * handle->corrsize);
+ handle->ringstart = 0;
+
+ /* initalize intra-cell position */
+ handle->cellpos = 0;
+ handle->celladj = fsk_modem_definitions[FSK_BELL202].baud_rate / (double) attr->sample_rate * (double) handle->downsampling_count;
+
+ /* if they have provided a byte handler, add a UART to the processing chain */
+ if (handle->attr.bytehandler) {
+ dsp_uart_attr_t uart_attr;
+ dsp_uart_handle_t *uart_handle;
+
+ dsp_uart_attr_init(&uart_attr);
+ dsp_uart_attr_set_bytehandler(&uart_attr, handle->attr.bytehandler, handle->attr.bytehandler_arg);
+ uart_handle = dsp_uart_create(&uart_attr);
+ if (uart_handle == NULL) {
+ dsp_fsk_destroy(&handle);
+ return NULL;
+ }
+ handle->attr.bithandler = dsp_uart_bit_handler;
+ handle->attr.bithandler_arg = uart_handle;
+ }
+
+ return handle;
+}
+
+/*
+ * dsp_fsk_destroy
+ *
+ * Destroys a handle, releasing any associated memory. Sets handle pointer to NULL
+ * so A destroyed handle can not be used for anything after the destroy.
+*/
+
+void dsp_fsk_destroy(dsp_fsk_handle_t **handle)
+{
+ int i;
+
+ /* if empty handle, just return */
+ if (*handle == NULL) {
+ return;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if ((*handle)->correlates[i] != NULL) {
+ ftdm_safe_free((*handle)->correlates[i]);
+ (*handle)->correlates[i] = NULL;
+ }
+ }
+
+ if ((*handle)->buffer != NULL) {
+ ftdm_safe_free((*handle)->buffer);
+ (*handle)->buffer = NULL;
+ }
+
+ if ((*handle)->attr.bytehandler) {
+ dsp_uart_handle_t** dhandle = (void *)(&(*handle)->attr.bithandler_arg);
+ dsp_uart_destroy(dhandle);
+ }
+
+ ftdm_safe_free(*handle);
+ *handle = NULL;
+}
+
+/*
+ * dsp_fsk_sample
+ *
+ * This is the main processing entry point. The function accepts a normalized
+ * sample (i.e., one whose range is between -1 and +1). The function performs
+ * the Bell-202 FSK modem decode processing, and, if it detects a valid bit,
+ * will call the bithandler associated with the attributes structure.
+ *
+ * For the Bell-202 standard, a logical zero (space) is 2200 Hz, and a logical
+ * one (mark) is 1200 Hz.
+*/
+
+void
+dsp_fsk_sample (dsp_fsk_handle_t *handle, double normalized_sample)
+{
+ double val;
+ double factors[4];
+ int i, j;
+
+ /* if we can avoid processing samples, do so */
+ if (handle->downsampling_count != 1) {
+ if (handle->current_downsample < handle->downsampling_count) {
+ handle->current_downsample++;
+ return; /* throw this sample out */
+ }
+ handle->current_downsample = 1;
+ }
+
+ /* store sample in buffer */
+ handle->buffer[handle->ringstart++] = normalized_sample;
+ if (handle->ringstart >= handle->corrsize) {
+ handle->ringstart = 0;
+ }
+
+ /* do the correlation calculation */
+ factors[0] = factors[1] = factors[2] = factors[3] = 0; /* clear out intermediate sums */
+ j = handle->ringstart;
+ for (i = 0; i < handle->corrsize; i++) {
+ if (j >= handle->corrsize) {
+ j = 0;
+ }
+ val = handle->buffer[j];
+ factors[0] += handle->correlates[0][i] * val;
+ factors[1] += handle->correlates[1][i] * val;
+ factors[2] += handle->correlates[2][i] * val;
+ factors[3] += handle->correlates[3][i] * val;
+ j++;
+ }
+
+ /* store the bit (bit value is comparison of the two sets of correlate factors) */
+ handle->previous_bit = handle->current_bit;
+ handle->current_bit = (factors[0] * factors[0] + factors[1] * factors[1] > factors[2] * factors[2] + factors[3] * factors[3]);
+
+ /* if there's a transition, we can synchronize the cell position */
+ if (handle->previous_bit != handle->current_bit) {
+ handle->cellpos = 0.5; /* adjust cell position to be in the middle of the cell */
+ }
+ handle->cellpos += handle->celladj; /* walk the cell along */
+
+ if (handle->cellpos > 1.0) {
+ handle->cellpos -= 1.0;
+
+ switch (handle->state) {
+ case FSK_STATE_DATA:
+ {
+
+ (*handle->attr.bithandler) (handle->attr.bithandler_arg, handle->current_bit);
+ }
+ break;
+ case FSK_STATE_CHANSEIZE:
+ {
+
+ if (handle->last_bit != handle->current_bit) {
+ handle->conscutive_state_bits++;
+ } else {
+ handle->conscutive_state_bits = 0;
+ }
+
+ if (handle->conscutive_state_bits > 15) {
+ handle->state = FSK_STATE_CARRIERSIG;
+ handle->conscutive_state_bits = 0;
+ }
+ }
+ break;
+ case FSK_STATE_CARRIERSIG:
+ {
+ if (handle->current_bit) {
+ handle->conscutive_state_bits++;
+ } else {
+ handle->conscutive_state_bits = 0;
+ }
+
+ if (handle->conscutive_state_bits > 15) {
+ handle->state = FSK_STATE_DATA;
+ handle->conscutive_state_bits = 0;
+ }
+ }
+ break;
+ }
+
+ handle->last_bit = handle->current_bit;
+ }
+}
+
Added: freeswitch/trunk/libs/freetdm/src/ftdm_buffer.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftdm_buffer.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftdm_buffer.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#include "freetdm.h"
+#include "ftdm_buffer.h"
+
+static unsigned buffer_id = 0;
+
+struct ftdm_buffer {
+ unsigned char *data;
+ unsigned char *head;
+ ftdm_size_t used;
+ ftdm_size_t actually_used;
+ ftdm_size_t datalen;
+ ftdm_size_t max_len;
+ ftdm_size_t blocksize;
+ unsigned id;
+ int loops;
+};
+
+
+FT_DECLARE(ftdm_status_t) ftdm_buffer_create(ftdm_buffer_t **buffer, ftdm_size_t blocksize, ftdm_size_t start_len, ftdm_size_t max_len)
+{
+ ftdm_buffer_t *new_buffer;
+
+ new_buffer = ftdm_malloc(sizeof(*new_buffer));
+ if (new_buffer) {
+ memset(new_buffer, 0, sizeof(*new_buffer));
+
+ if (start_len) {
+ new_buffer->data = ftdm_malloc(start_len);
+ if (!new_buffer->data) {
+ ftdm_safe_free(new_buffer);
+ return FTDM_MEMERR;
+ }
+ memset(new_buffer->data, 0, start_len);
+ }
+
+ new_buffer->max_len = max_len;
+ new_buffer->datalen = start_len;
+ new_buffer->id = buffer_id++;
+ new_buffer->blocksize = blocksize;
+ new_buffer->head = new_buffer->data;
+
+ *buffer = new_buffer;
+ return FTDM_SUCCESS;
+ }
+
+ return FTDM_MEMERR;
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_len(ftdm_buffer_t *buffer)
+{
+
+ assert(buffer != NULL);
+
+ return buffer->datalen;
+
+}
+
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_freespace(ftdm_buffer_t *buffer)
+{
+ assert(buffer != NULL);
+
+
+ if (buffer->max_len) {
+ return (ftdm_size_t) (buffer->max_len - buffer->used);
+ }
+ return 1000000;
+
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_inuse(ftdm_buffer_t *buffer)
+{
+ assert(buffer != NULL);
+
+ return buffer->used;
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_seek(ftdm_buffer_t *buffer, ftdm_size_t datalen)
+{
+ ftdm_size_t reading = 0;
+
+ assert(buffer != NULL);
+
+ if (buffer->used < 1) {
+ buffer->used = 0;
+ return 0;
+ } else if (buffer->used >= datalen) {
+ reading = datalen;
+ } else {
+ reading = buffer->used;
+ }
+
+ buffer->used = buffer->actually_used - reading;
+ buffer->head = buffer->data + reading;
+
+ return reading;
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_toss(ftdm_buffer_t *buffer, ftdm_size_t datalen)
+{
+ ftdm_size_t reading = 0;
+
+ assert(buffer != NULL);
+
+ if (buffer->used < 1) {
+ buffer->used = 0;
+ return 0;
+ } else if (buffer->used >= datalen) {
+ reading = datalen;
+ } else {
+ reading = buffer->used;
+ }
+
+ buffer->used -= reading;
+ buffer->head += reading;
+
+ return buffer->used;
+}
+
+FT_DECLARE(void) ftdm_buffer_set_loops(ftdm_buffer_t *buffer, int loops)
+{
+ buffer->loops = loops;
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_read_loop(ftdm_buffer_t *buffer, void *data, ftdm_size_t datalen)
+{
+ ftdm_size_t len;
+ if ((len = ftdm_buffer_read(buffer, data, datalen)) < datalen) {
+ if (buffer->loops == 0) {
+ return len;
+ }
+ buffer->head = buffer->data;
+ buffer->used = buffer->actually_used;
+ len = ftdm_buffer_read(buffer, (char*)data + len, datalen - len);
+ buffer->loops--;
+ }
+ return len;
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_read(ftdm_buffer_t *buffer, void *data, ftdm_size_t datalen)
+{
+ ftdm_size_t reading = 0;
+
+ assert(buffer != NULL);
+ assert(data != NULL);
+
+
+ if (buffer->used < 1) {
+ buffer->used = 0;
+ return 0;
+ } else if (buffer->used >= datalen) {
+ reading = datalen;
+ } else {
+ reading = buffer->used;
+ }
+
+ memcpy(data, buffer->head, reading);
+ buffer->used -= reading;
+ buffer->head += reading;
+
+ /* if (buffer->id == 4) printf("%u o %d = %d\n", buffer->id, (unsigned)reading, (unsigned)buffer->used); */
+ return reading;
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_write(ftdm_buffer_t *buffer, const void *data, ftdm_size_t datalen)
+{
+ ftdm_size_t freespace, actual_freespace;
+
+ assert(buffer != NULL);
+ assert(data != NULL);
+ assert(buffer->data != NULL);
+
+ if (!datalen) {
+ return buffer->used;
+ }
+
+ actual_freespace = buffer->datalen - buffer->actually_used;
+ if (actual_freespace < datalen && (!buffer->max_len || (buffer->used + datalen <= buffer->max_len))) {
+ memmove(buffer->data, buffer->head, buffer->used);
+ buffer->head = buffer->data;
+ buffer->actually_used = buffer->used;
+ }
+
+ freespace = buffer->datalen - buffer->used;
+
+ /*
+ if (buffer->data != buffer->head) {
+ memmove(buffer->data, buffer->head, buffer->used);
+ buffer->head = buffer->data;
+ }
+ */
+
+ if (freespace < datalen) {
+ ftdm_size_t new_size, new_block_size;
+ void *data;
+
+ new_size = buffer->datalen + datalen;
+ new_block_size = buffer->datalen + buffer->blocksize;
+
+ if (new_block_size > new_size) {
+ new_size = new_block_size;
+ }
+ buffer->head = buffer->data;
+ data = realloc(buffer->data, new_size);
+ if (!data) {
+ return 0;
+ }
+ buffer->data = data;
+ buffer->head = buffer->data;
+ buffer->datalen = new_size;
+ }
+
+
+ freespace = buffer->datalen - buffer->used;
+
+ if (freespace < datalen) {
+ return 0;
+ } else {
+ memcpy(buffer->head + buffer->used, data, datalen);
+ buffer->used += datalen;
+ buffer->actually_used += datalen;
+ }
+ /* if (buffer->id == 4) printf("%u i %d = %d\n", buffer->id, (unsigned)datalen, (unsigned)buffer->used); */
+
+ return buffer->used;
+}
+
+FT_DECLARE(void) ftdm_buffer_zero(ftdm_buffer_t *buffer)
+{
+ assert(buffer != NULL);
+ assert(buffer->data != NULL);
+
+ buffer->used = 0;
+ buffer->actually_used = 0;
+ buffer->head = buffer->data;
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_zwrite(ftdm_buffer_t *buffer, const void *data, ftdm_size_t datalen)
+{
+ ftdm_size_t w;
+
+ if (!(w = ftdm_buffer_write(buffer, data, datalen))) {
+ ftdm_buffer_zero(buffer);
+ return ftdm_buffer_write(buffer, data, datalen);
+ }
+
+ return w;
+}
+
+FT_DECLARE(void) ftdm_buffer_destroy(ftdm_buffer_t **buffer)
+{
+ if (*buffer) {
+ ftdm_safe_free((*buffer)->data);
+ ftdm_safe_free(*buffer);
+ }
+
+ *buffer = NULL;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/ftdm_callerid.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftdm_callerid.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftdm_callerid.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,307 @@
+#include "freetdm.h"
+#include "fsk.h"
+#include "uart.h"
+
+
+
+static void fsk_byte_handler (void *x, int data)
+{
+ ftdm_fsk_data_state_t *state = (ftdm_fsk_data_state_t *) x;
+ uint8_t byte = (uint8_t)data;
+
+ top:
+
+ if (state->init == 3) {
+ return;
+ }
+
+ if (state->dlen) {
+ goto add_byte;
+ }
+
+ if (state->bpos == 1) {
+ state->blen = byte;
+
+ if ((uint32_t)(state->dlen = state->bpos + byte + 2) > state->bufsize) {
+ state->dlen = state->bufsize;
+ }
+ goto top;
+ }
+
+ add_byte:
+
+ if (state->bpos <= state->dlen) {
+ state->buf[state->bpos++] = byte;
+ } else {
+ state->init = 3;
+ }
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_init(ftdm_fsk_data_state_t *state, uint8_t *data, uint32_t datalen)
+{
+ memset(state, 0, sizeof(*state));
+ state->buf = data;
+ state->bufsize = datalen;
+ state->bpos = 2;
+
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_sdmf(ftdm_fsk_data_state_t *state, const char *date, char *number)
+{
+ size_t dlen = strlen(date);
+ size_t nlen = strlen(number);
+
+ state->buf[0] = FTDM_CID_TYPE_SDMF;
+ memcpy(&state->buf[state->bpos], date, dlen);
+ state->bpos += dlen;
+ memcpy(&state->buf[state->bpos], number, nlen);
+ state->bpos += nlen;
+
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_mdmf(ftdm_fsk_data_state_t *state, ftdm_mdmf_type_t type, const uint8_t *data, uint32_t datalen)
+{
+ state->buf[0] = FTDM_CID_TYPE_MDMF;
+ state->buf[state->bpos++] = type;
+ state->buf[state->bpos++] = (uint8_t)datalen;
+ memcpy(&state->buf[state->bpos], data, datalen);
+ state->bpos += datalen;
+ return FTDM_SUCCESS;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_checksum(ftdm_fsk_data_state_t *state)
+{
+ uint32_t i;
+ uint8_t check = 0;
+
+ state->buf[1] = (uint8_t)(state->bpos - 2);
+
+ for (i = 0; i < state->bpos; i++) {
+ check = check + state->buf[i];
+ }
+
+ state->checksum = state->buf[state->bpos] = (uint8_t)(256 - check);
+ state->bpos++;
+
+ state->dlen = state->bpos;
+ state->blen = state->buf[1];
+
+ return FTDM_SUCCESS;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_parse(ftdm_fsk_data_state_t *state, ftdm_size_t *type, char **data, ftdm_size_t *len)
+{
+
+ ftdm_size_t i;
+ int sum = 0;
+
+ top:
+
+ if (state->checksum != 0 || state->ppos >= state->dlen - 1) {
+ return FTDM_FAIL;
+ }
+
+ if (!state->ppos) {
+ for(i = 0; i < state->bpos; i++) {
+ sum += state->buf[i];
+ }
+ state->checksum = sum % 256;
+ state->ppos = 2;
+
+ if (state->buf[0] != FTDM_CID_TYPE_MDMF && state->buf[0] != FTDM_CID_TYPE_SDMF) {
+ state->checksum = -1;
+ }
+ goto top;
+ }
+
+ if (state->buf[0] == FTDM_CID_TYPE_SDMF) {
+ /* convert sdmf to mdmf so we don't need 2 parsers */
+ if (state->ppos == 2) {
+ *type = MDMF_DATETIME;
+ *len = 8;
+ } else {
+ if (state->buf[state->ppos] == 'P' || state->buf[state->ppos] == 'O') {
+ *type = MDMF_NO_NUM;
+ *len = 1;
+ } else {
+ *type = MDMF_PHONE_NUM;
+ *len = state->blen - 8;
+ }
+ }
+ *data = (char *)&state->buf[state->ppos];
+ state->ppos += *len;
+ return FTDM_SUCCESS;
+ } else if (state->buf[0] == FTDM_CID_TYPE_MDMF) {
+ *type = state->buf[state->ppos++];
+ *len = state->buf[state->ppos++];
+ *data = (char *)&state->buf[state->ppos];
+ state->ppos += *len;
+ return FTDM_SUCCESS;
+ }
+
+ return FTDM_FAIL;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_fsk_demod_feed(ftdm_fsk_data_state_t *state, int16_t *data, ftdm_size_t samples)
+{
+ uint32_t x;
+ int16_t *sp = data;
+
+ if (state->init == 3) {
+ return FTDM_FAIL;
+ }
+
+ for (x = 0; x < samples; x++) {
+ dsp_fsk_sample (state->fsk1200_handle, (double) *sp++ / 32767.0);
+ if (state->dlen && state->bpos >= state->dlen) {
+ state->init = 3;
+ return FTDM_FAIL;
+ }
+ }
+
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_fsk_demod_destroy(ftdm_fsk_data_state_t *state)
+{
+ dsp_fsk_destroy(&state->fsk1200_handle);
+ memset(state, 0, sizeof(*state));
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(int) ftdm_fsk_demod_init(ftdm_fsk_data_state_t *state, int rate, uint8_t *buf, ftdm_size_t bufsize)
+{
+
+ dsp_fsk_attr_t fsk1200_attr;
+
+ if (state->fsk1200_handle) {
+ dsp_fsk_destroy(&state->fsk1200_handle);
+ }
+
+ memset(state, 0, sizeof(*state));
+ memset(buf, 0, bufsize);
+ state->buf = buf;
+ state->bufsize = bufsize;
+
+ dsp_fsk_attr_init (&fsk1200_attr);
+ dsp_fsk_attr_set_samplerate (&fsk1200_attr, rate);
+ dsp_fsk_attr_set_bytehandler (&fsk1200_attr, fsk_byte_handler, state);
+ state->fsk1200_handle = dsp_fsk_create (&fsk1200_attr);
+
+ if (state->fsk1200_handle == NULL) {
+ return FTDM_FAIL;
+ }
+
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_fsk_modulator_generate_bit(ftdm_fsk_modulator_t *fsk_trans, int8_t bit, int16_t *buf, ftdm_size_t buflen)
+{
+ ftdm_size_t i;
+
+ for(i = 0 ; i < buflen; i++) {
+ fsk_trans->bit_accum += fsk_trans->bit_factor;
+ if (fsk_trans->bit_accum >= FTDM_FSK_MOD_FACTOR) {
+ fsk_trans->bit_accum -= (FTDM_FSK_MOD_FACTOR + fsk_trans->bit_factor);
+ break;
+ }
+
+ buf[i] = teletone_dds_state_modulate_sample(&fsk_trans->dds, bit);
+ }
+
+ return i;
+}
+
+
+FT_DECLARE(int32_t) ftdm_fsk_modulator_generate_carrier_bits(ftdm_fsk_modulator_t *fsk_trans, uint32_t bits)
+{
+ uint32_t i = 0;
+ ftdm_size_t r = 0;
+ int8_t bit = 1;
+
+ for (i = 0; i < bits; i++) {
+ if ((r = ftdm_fsk_modulator_generate_bit(fsk_trans, bit, fsk_trans->sample_buffer, sizeof(fsk_trans->sample_buffer) / 2))) {
+ if (fsk_trans->write_sample_callback(fsk_trans->sample_buffer, r, fsk_trans->user_data) != FTDM_SUCCESS) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ return i;
+}
+
+
+FT_DECLARE(void) ftdm_fsk_modulator_generate_chan_sieze(ftdm_fsk_modulator_t *fsk_trans)
+{
+ uint32_t i = 0;
+ ftdm_size_t r = 0;
+ int8_t bit = 0;
+
+ for (i = 0; i < fsk_trans->chan_sieze_bits; i++) {
+ if ((r = ftdm_fsk_modulator_generate_bit(fsk_trans, bit, fsk_trans->sample_buffer, sizeof(fsk_trans->sample_buffer) / 2))) {
+ if (fsk_trans->write_sample_callback(fsk_trans->sample_buffer, r, fsk_trans->user_data) != FTDM_SUCCESS) {
+ break;
+ }
+ } else {
+ break;
+ }
+ bit = !bit;
+ }
+
+
+}
+
+
+FT_DECLARE(void) ftdm_fsk_modulator_send_data(ftdm_fsk_modulator_t *fsk_trans)
+{
+ ftdm_size_t r = 0;
+ int8_t bit = 0;
+
+ while((bit = ftdm_bitstream_get_bit(&fsk_trans->bs)) > -1) {
+ if ((r = ftdm_fsk_modulator_generate_bit(fsk_trans, bit, fsk_trans->sample_buffer, sizeof(fsk_trans->sample_buffer) / 2))) {
+ if (fsk_trans->write_sample_callback(fsk_trans->sample_buffer, r, fsk_trans->user_data) != FTDM_SUCCESS) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_fsk_modulator_init(ftdm_fsk_modulator_t *fsk_trans,
+ fsk_modem_types_t modem_type,
+ uint32_t sample_rate,
+ ftdm_fsk_data_state_t *fsk_data,
+ float db_level,
+ uint32_t carrier_bits_start,
+ uint32_t carrier_bits_stop,
+ uint32_t chan_sieze_bits,
+ ftdm_fsk_write_sample_t write_sample_callback,
+ void *user_data)
+{
+ memset(fsk_trans, 0, sizeof(*fsk_trans));
+ fsk_trans->modem_type = modem_type;
+ teletone_dds_state_set_tone(&fsk_trans->dds, fsk_modem_definitions[fsk_trans->modem_type].freq_space, sample_rate, 0);
+ teletone_dds_state_set_tone(&fsk_trans->dds, fsk_modem_definitions[fsk_trans->modem_type].freq_mark, sample_rate, 1);
+ fsk_trans->bit_factor = (uint32_t)((fsk_modem_definitions[fsk_trans->modem_type].baud_rate * FTDM_FSK_MOD_FACTOR) / (float)sample_rate);
+ fsk_trans->samples_per_bit = (uint32_t) (sample_rate / fsk_modem_definitions[fsk_trans->modem_type].baud_rate);
+ fsk_trans->est_bytes = (int32_t)(((fsk_data->dlen * 10) + carrier_bits_start + carrier_bits_stop + chan_sieze_bits) * ((fsk_trans->samples_per_bit + 1) * 2));
+ fsk_trans->bit_accum = 0;
+ fsk_trans->fsk_data = fsk_data;
+ teletone_dds_state_set_tx_level(&fsk_trans->dds, db_level);
+ ftdm_bitstream_init(&fsk_trans->bs, fsk_trans->fsk_data->buf, (uint32_t)fsk_trans->fsk_data->dlen, FTDM_ENDIAN_BIG, 1);
+ fsk_trans->carrier_bits_start = carrier_bits_start;
+ fsk_trans->carrier_bits_stop = carrier_bits_stop;
+ fsk_trans->chan_sieze_bits = chan_sieze_bits;
+ fsk_trans->write_sample_callback = write_sample_callback;
+ fsk_trans->user_data = user_data;
+ return FTDM_SUCCESS;
+}
+
Added: freeswitch/trunk/libs/freetdm/src/ftdm_config.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftdm_config.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftdm_config.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#include "freetdm.h"
+#include "ftdm_config.h"
+
+int ftdm_config_open_file(ftdm_config_t *cfg, const char *file_path)
+{
+ FILE *f;
+ const char *path = NULL;
+ char path_buf[1024];
+
+ if (file_path[0] == '/') {
+ path = file_path;
+ } else {
+ snprintf(path_buf, sizeof(path_buf), "%s%s%s", FTDM_CONFIG_DIR, FTDM_PATH_SEPARATOR, file_path);
+ path = path_buf;
+ }
+
+ if (!path) {
+ return 0;
+ }
+
+ memset(cfg, 0, sizeof(*cfg));
+ cfg->lockto = -1;
+ ftdm_log(FTDM_LOG_DEBUG, "Configuration file is %s.\n", path);
+ f = fopen(path, "r");
+
+ if (!f) {
+ if (file_path[0] != '/') {
+ int last = -1;
+ char *var, *val;
+
+ snprintf(path_buf, sizeof(path_buf), "%s%sfreetdm.conf", FTDM_CONFIG_DIR, FTDM_PATH_SEPARATOR);
+ path = path_buf;
+
+ if ((f = fopen(path, "r")) == 0) {
+ return 0;
+ }
+
+ cfg->file = f;
+ ftdm_set_string(cfg->path, path);
+
+ while (ftdm_config_next_pair(cfg, &var, &val)) {
+ if ((cfg->sectno != last) && !strcmp(cfg->section, file_path)) {
+ cfg->lockto = cfg->sectno;
+ return 1;
+ }
+ }
+
+ ftdm_config_close_file(cfg);
+ memset(cfg, 0, sizeof(*cfg));
+ return 0;
+ }
+
+ return 0;
+ } else {
+ cfg->file = f;
+ ftdm_set_string(cfg->path, path);
+ return 1;
+ }
+}
+
+void ftdm_config_close_file(ftdm_config_t *cfg)
+{
+
+ if (cfg->file) {
+ fclose(cfg->file);
+ }
+
+ memset(cfg, 0, sizeof(*cfg));
+}
+
+
+
+int ftdm_config_next_pair(ftdm_config_t *cfg, char **var, char **val)
+{
+ int ret = 0;
+ char *p, *end;
+
+ *var = *val = NULL;
+
+ if (!cfg->path) {
+ return 0;
+ }
+
+ for (;;) {
+ cfg->lineno++;
+
+ if (!fgets(cfg->buf, sizeof(cfg->buf), cfg->file)) {
+ ret = 0;
+ break;
+ }
+ *var = cfg->buf;
+
+ if (**var == '[' && (end = strchr(*var, ']')) != 0) {
+ *end = '\0';
+ (*var)++;
+ if (**var == '+') {
+ (*var)++;
+ ftdm_copy_string(cfg->section, *var, sizeof(cfg->section));
+ cfg->sectno++;
+
+ if (cfg->lockto > -1 && cfg->sectno != cfg->lockto) {
+ break;
+ }
+ cfg->catno = 0;
+ cfg->lineno = 0;
+ *var = (char *) "";
+ *val = (char *) "";
+ return 1;
+ } else {
+ ftdm_copy_string(cfg->category, *var, sizeof(cfg->category));
+ cfg->catno++;
+ }
+ continue;
+ }
+
+
+
+ if (**var == '#' || **var == ';' || **var == '\n' || **var == '\r') {
+ continue;
+ }
+
+ if (!strncmp(*var, "__END__", 7)) {
+ break;
+ }
+
+
+ if ((end = strchr(*var, ';')) && *(end+1) == *end) {
+ *end = '\0';
+ end--;
+ } else if ((end = strchr(*var, '\n')) != 0) {
+ if (*(end - 1) == '\r') {
+ end--;
+ }
+ *end = '\0';
+ }
+
+ p = *var;
+ while ((*p == ' ' || *p == '\t') && p != end) {
+ *p = '\0';
+ p++;
+ }
+ *var = p;
+
+
+ if ((*val = strchr(*var, '=')) == 0) {
+ ret = -1;
+ /* log_printf(0, server.log, "Invalid syntax on %s: line %d\n", cfg->path, cfg->lineno); */
+ continue;
+ } else {
+ p = *val - 1;
+ *(*val) = '\0';
+ (*val)++;
+ if (*(*val) == '>') {
+ *(*val) = '\0';
+ (*val)++;
+ }
+
+ while ((*p == ' ' || *p == '\t') && p != *var) {
+ *p = '\0';
+ p--;
+ }
+
+ p = *val;
+ while ((*p == ' ' || *p == '\t') && p != end) {
+ *p = '\0';
+ p++;
+ }
+ *val = p;
+ ret = 1;
+ break;
+ }
+ }
+
+
+ return ret;
+
+}
+
+FT_DECLARE (int) ftdm_config_get_cas_bits(char *strvalue, unsigned char *outbits)
+{
+ char cas_bits[5];
+ unsigned char bit = 0x8;
+ int x = 0;
+ char *double_colon = strchr(strvalue, ':');
+ if (!double_colon) {
+ ftdm_log(FTDM_LOG_ERROR, "No CAS bits specified: %s, :xxxx definition expected, where x is 1 or 0\n", strvalue);
+ return -1;
+ }
+ double_colon++;
+ *outbits = 0;
+ cas_bits[4] = 0;
+ if (sscanf(double_colon, "%c%c%c%c", &cas_bits[0], &cas_bits[1], &cas_bits[2], &cas_bits[3]) != 4) {
+ ftdm_log(FTDM_LOG_ERROR, "Invalid CAS bits specified: '%s', :xxxx definition expected, where x is 1 or 0\n", double_colon);
+ return -1;
+ }
+ ftdm_log(FTDM_LOG_DEBUG, "CAS bits specification found: %s\n", cas_bits);
+ for (; cas_bits[x]; x++) {
+ if ('1' == cas_bits[x]) {
+ *outbits |= bit;
+ } else if ('0' != cas_bits[x]) {
+ ftdm_log(FTDM_LOG_ERROR, "Invalid CAS pattern specified: %s, just 0 or 1 allowed for each bit\n");
+ return -1;
+ }
+ bit >>= 1;
+ }
+ return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/ftdm_dso.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftdm_dso.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftdm_dso.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,116 @@
+/*
+ * Cross Platform dso/dll load abstraction
+ * Copyright(C) 2008 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer.
+ *
+ */
+
+#include "freetdm.h"
+#include "ftdm_dso.h"
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef WIN32
+#include <windows.h>
+#include <stdio.h>
+
+
+FT_DECLARE(void) ftdm_dso_destroy(ftdm_dso_lib_t *lib) {
+ if (lib && *lib) {
+ FreeLibrary(*lib);
+ *lib = NULL;
+ }
+}
+
+FT_DECLARE(ftdm_dso_lib_t) ftdm_dso_open(const char *path, char **err) {
+ HINSTANCE lib;
+
+ lib = LoadLibraryEx(path, NULL, 0);
+
+ if (!lib) {
+ LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ }
+
+ if (!lib) {
+ DWORD error = GetLastError();
+ char tmp[80];
+ sprintf(tmp, "dll open error [%ul]\n", error);
+ *err = ftdm_strdup(tmp);
+ }
+
+ return lib;
+}
+
+FT_DECLARE(void*) ftdm_dso_func_sym(ftdm_dso_lib_t lib, const char *sym, char **err) {
+ FARPROC func = GetProcAddress(lib, sym);
+ if (!func) {
+ DWORD error = GetLastError();
+ char tmp[80];
+ sprintf(tmp, "dll sym error [%ul]\n", error);
+ *err = ftdm_strdup(tmp);
+ }
+ return (void *)(intptr_t)func; // this should really be addr - ftdm_dso_func_data
+}
+
+#else
+
+/*
+** {========================================================================
+** This is an implementation of loadlib based on the dlfcn interface.
+** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
+** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least
+** as an emulation layer on top of native functions.
+** =========================================================================
+*/
+
+
+#include <dlfcn.h>
+
+FT_DECLARE(void) ftdm_dso_destroy(ftdm_dso_lib_t *lib) {
+ if (lib && *lib) {
+ dlclose(*lib);
+ *lib = NULL;
+ }
+}
+
+FT_DECLARE(ftdm_dso_lib_t) ftdm_dso_open(const char *path, char **err) {
+ void *lib = dlopen(path, RTLD_NOW | RTLD_LOCAL);
+ if (lib == NULL) {
+ *err = ftdm_strdup(dlerror());
+ }
+ return lib;
+}
+
+FT_DECLARE(void*) ftdm_dso_func_sym(ftdm_dso_lib_t lib, const char *sym, char **err) {
+ void *func = dlsym(lib, sym);
+ if (!func) {
+ *err = ftdm_strdup(dlerror());
+ }
+ return func;
+}
+#endif
+
+/* }====================================================== */
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4
+ */
Added: freeswitch/trunk/libs/freetdm/src/ftdm_io.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftdm_io.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftdm_io.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3927 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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:
+ *
+ * Moises Silva <moy@sangoma.com>
+ * David Yat Sin <dyatsin@sangoma.com>
+ *
+ */
+
+#define _GNU_SOURCE
+#ifndef WIN32
+#endif
+#include "freetdm.h"
+#include <stdarg.h>
+#ifdef WIN32
+#include <io.h>
+#endif
+#ifdef FTDM_PIKA_SUPPORT
+#include "ftdm_pika.h"
+#endif
+
+#define SPAN_PENDING_CHANS_QUEUE_SIZE 1000
+
+static int time_is_init = 0;
+
+static void time_init(void)
+{
+#ifdef WIN32
+ timeBeginPeriod(1);
+#endif
+ time_is_init = 1;
+}
+
+static void time_end(void)
+{
+#ifdef WIN32
+ timeEndPeriod(1);
+#endif
+ time_is_init = 0;
+}
+
+FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void)
+{
+#ifdef WIN32
+ return timeGetTime();
+#else
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return ((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
+#endif
+}
+
+static struct {
+ ftdm_hash_t *interface_hash;
+ ftdm_hash_t *module_hash;
+ ftdm_hash_t *span_hash;
+ ftdm_hash_t *group_hash;
+ ftdm_mutex_t *mutex;
+ ftdm_mutex_t *span_mutex;
+ ftdm_mutex_t *group_mutex;
+ uint32_t span_index;
+ uint32_t group_index;
+ uint32_t running;
+ ftdm_span_t *spans;
+ ftdm_group_t *groups;
+} globals;
+
+
+/* enum lookup funcs */
+FTDM_ENUM_NAMES(TONEMAP_NAMES, TONEMAP_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_tonemap, ftdm_tonemap2str, ftdm_tonemap_t, TONEMAP_NAMES, FTDM_TONEMAP_INVALID)
+
+FTDM_ENUM_NAMES(OOB_NAMES, OOB_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_oob_event, ftdm_oob_event2str, ftdm_oob_event_t, OOB_NAMES, FTDM_OOB_INVALID)
+
+FTDM_ENUM_NAMES(TRUNK_TYPE_NAMES, TRUNK_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_trunk_type, ftdm_trunk_type2str, ftdm_trunk_type_t, TRUNK_TYPE_NAMES, FTDM_TRUNK_NONE)
+
+FTDM_ENUM_NAMES(START_TYPE_NAMES, START_TYPE_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_analog_start_type, ftdm_analog_start_type2str, ftdm_analog_start_type_t, START_TYPE_NAMES, FTDM_ANALOG_START_NA)
+
+FTDM_ENUM_NAMES(SIGNAL_NAMES, SIGNAL_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_signal_event, ftdm_signal_event2str, ftdm_signal_event_t, SIGNAL_NAMES, FTDM_SIGEVENT_INVALID)
+
+FTDM_ENUM_NAMES(CHANNEL_STATE_NAMES, CHANNEL_STATE_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t, CHANNEL_STATE_NAMES, FTDM_CHANNEL_STATE_INVALID)
+
+FTDM_ENUM_NAMES(MDMF_TYPE_NAMES, MDMF_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_mdmf_type, ftdm_mdmf_type2str, ftdm_mdmf_type_t, MDMF_TYPE_NAMES, MDMF_INVALID)
+
+FTDM_ENUM_NAMES(CHAN_TYPE_NAMES, CHAN_TYPE_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_chan_type, ftdm_chan_type2str, ftdm_chan_type_t, CHAN_TYPE_NAMES, FTDM_CHAN_TYPE_COUNT)
+
+FTDM_ENUM_NAMES(SIGNALING_STATUS_NAMES, SIGSTATUS_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_signaling_status, ftdm_signaling_status2str, ftdm_signaling_status_t, SIGNALING_STATUS_NAMES, FTDM_SIG_STATE_INVALID)
+
+static const char *cut_path(const char *in)
+{
+ const char *p, *ret = in;
+ char delims[] = "/\\";
+ char *i;
+
+ for (i = delims; *i; i++) {
+ p = in;
+ while ((p = strchr(p, *i)) != 0) {
+ ret = ++p;
+ }
+ }
+ return ret;
+}
+
+static void null_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
+{
+ if (file && func && line && level && fmt) {
+ return;
+ }
+ return;
+}
+
+
+static const char *LEVEL_NAMES[] = {
+ "EMERG",
+ "ALERT",
+ "CRIT",
+ "ERROR",
+ "WARNING",
+ "NOTICE",
+ "INFO",
+ "DEBUG",
+ NULL
+};
+
+static int ftdm_log_level = 7;
+
+static void default_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
+{
+ const char *fp;
+ char data[1024];
+ va_list ap;
+
+ if (level < 0 || level > 7) {
+ level = 7;
+ }
+ if (level > ftdm_log_level) {
+ return;
+ }
+
+ fp = cut_path(file);
+
+ va_start(ap, fmt);
+
+ vsnprintf(data, sizeof(data), fmt, ap);
+
+
+ fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], file, line, func, data);
+
+ va_end(ap);
+
+}
+
+static __inline__ void *ftdm_std_malloc(void *pool, ftdm_size_t size)
+{
+ void *ptr = malloc(size);
+ pool = NULL; /* fix warning */
+ ftdm_assert_return(ptr != NULL, NULL, "Out of memory");
+ return ptr;
+}
+
+static __inline__ void *ftdm_std_calloc(void *pool, ftdm_size_t elements, ftdm_size_t size)
+{
+ void *ptr = calloc(elements, size);
+ pool = NULL;
+ ftdm_assert_return(ptr != NULL, NULL, "Out of memory");
+ return ptr;
+}
+
+static __inline__ void ftdm_std_free(void *pool, void *ptr)
+{
+ pool = NULL;
+ ftdm_assert_return(ptr != NULL, , "Attempted to free null pointer");
+ free(ptr);
+}
+
+FT_DECLARE_DATA ftdm_memory_handler_t g_ftdm_mem_handler =
+{
+ /*.pool =*/ NULL,
+ /*.malloc =*/ ftdm_std_malloc,
+ /*.calloc =*/ ftdm_std_calloc,
+ /*.free =*/ ftdm_std_free
+};
+
+FT_DECLARE_DATA ftdm_crash_policy_t g_ftdm_crash_policy = FTDM_CRASH_NEVER;
+
+static ftdm_status_t ftdm_set_caller_data(ftdm_span_t *span, ftdm_caller_data_t *caller_data)
+{
+ if (!caller_data) {
+ ftdm_log(FTDM_LOG_CRIT, "Error: trying to set caller data, but no caller_data!\n");
+ return FTDM_FAIL;
+ }
+
+ if (caller_data->cid_num.plan == FTDM_NPI_INVALID) {
+ caller_data->cid_num.plan = span->default_caller_data.cid_num.plan;
+ }
+
+ if (caller_data->cid_num.type == FTDM_TON_INVALID) {
+ caller_data->cid_num.type = span->default_caller_data.cid_num.type;
+ }
+
+ if (caller_data->ani.plan == FTDM_NPI_INVALID) {
+ caller_data->ani.plan = span->default_caller_data.ani.plan;
+ }
+
+ if (caller_data->ani.type == FTDM_TON_INVALID) {
+ caller_data->ani.type = span->default_caller_data.ani.type;
+ }
+
+ if (caller_data->rdnis.plan == FTDM_NPI_INVALID) {
+ caller_data->rdnis.plan = span->default_caller_data.rdnis.plan;
+ }
+
+ if (caller_data->rdnis.type == FTDM_NPI_INVALID) {
+ caller_data->rdnis.type = span->default_caller_data.rdnis.type;
+ }
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_set_caller_data(ftdm_channel_t *ftdmchan, ftdm_caller_data_t *caller_data)
+{
+ ftdm_status_t err = FTDM_SUCCESS;
+ if (!ftdmchan) {
+ ftdm_log(FTDM_LOG_CRIT, "Error: trying to set caller data, but no ftdmchan!\n");
+ return FTDM_FAIL;
+ }
+ if ((err = ftdm_set_caller_data(ftdmchan->span, caller_data)) != FTDM_SUCCESS) {
+ return err;
+ }
+ ftdmchan->caller_data = *caller_data;
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE_DATA ftdm_logger_t ftdm_log = null_logger;
+
+FT_DECLARE(void) ftdm_global_set_crash_policy(ftdm_crash_policy_t policy)
+{
+ g_ftdm_crash_policy |= policy;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_global_set_memory_handler(ftdm_memory_handler_t *handler)
+{
+ if (!handler) {
+ return FTDM_FAIL;
+ }
+ if (!handler->malloc) {
+ return FTDM_FAIL;
+ }
+ if (!handler->calloc) {
+ return FTDM_FAIL;
+ }
+ if (!handler->free) {
+ return FTDM_FAIL;
+ }
+ memcpy(&g_ftdm_mem_handler, handler, sizeof(*handler));
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(void) ftdm_global_set_logger(ftdm_logger_t logger)
+{
+ if (logger) {
+ ftdm_log = logger;
+ } else {
+ ftdm_log = null_logger;
+ }
+}
+
+FT_DECLARE(void) ftdm_global_set_default_logger(int level)
+{
+ if (level < 0 || level > 7) {
+ level = 7;
+ }
+
+ ftdm_log = default_logger;
+ ftdm_log_level = level;
+}
+
+FT_DECLARE_NONSTD(int) ftdm_hash_equalkeys(void *k1, void *k2)
+{
+ return strcmp((char *) k1, (char *) k2) ? 0 : 1;
+}
+
+FT_DECLARE_NONSTD(uint32_t) ftdm_hash_hashfromstring(void *ky)
+{
+ unsigned char *str = (unsigned char *) ky;
+ uint32_t hash = 0;
+ int c;
+
+ while ((c = *str++)) {
+ hash = c + (hash << 6) + (hash << 16) - hash;
+ }
+
+ return hash;
+}
+
+static ftdm_status_t ftdm_channel_destroy(ftdm_channel_t *ftdmchan)
+{
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CONFIGURED)) {
+
+ while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
+ ftdm_log(FTDM_LOG_INFO, "Waiting for thread to exit on channel %u:%u\n", ftdmchan->span_id, ftdmchan->chan_id);
+ ftdm_sleep(500);
+ }
+
+ ftdm_mutex_lock(ftdmchan->pre_buffer_mutex);
+ ftdm_buffer_destroy(&ftdmchan->pre_buffer);
+ ftdm_mutex_unlock(ftdmchan->pre_buffer_mutex);
+
+ ftdm_buffer_destroy(&ftdmchan->digit_buffer);
+ ftdm_buffer_destroy(&ftdmchan->gen_dtmf_buffer);
+ ftdm_buffer_destroy(&ftdmchan->dtmf_buffer);
+ ftdm_buffer_destroy(&ftdmchan->fsk_buffer);
+ ftdmchan->pre_buffer_size = 0;
+
+ hashtable_destroy(ftdmchan->variable_hash);
+
+ ftdm_safe_free(ftdmchan->dtmf_hangup_buf);
+
+ if (ftdmchan->tone_session.buffer) {
+ teletone_destroy_session(&ftdmchan->tone_session);
+ memset(&ftdmchan->tone_session, 0, sizeof(ftdmchan->tone_session));
+ }
+
+
+ if (ftdmchan->span->fio->channel_destroy) {
+ ftdm_log(FTDM_LOG_INFO, "Closing channel %s:%u:%u fd:%d\n", ftdmchan->span->type, ftdmchan->span_id, ftdmchan->chan_id, ftdmchan->sockfd);
+ if (ftdmchan->span->fio->channel_destroy(ftdmchan) == FTDM_SUCCESS) {
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_CONFIGURED);
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "Error Closing channel %u:%u fd:%d\n", ftdmchan->span_id, ftdmchan->chan_id, ftdmchan->sockfd);
+ }
+ }
+
+ ftdm_mutex_destroy(&ftdmchan->mutex);
+ ftdm_mutex_destroy(&ftdmchan->pre_buffer_mutex);
+ }
+
+ return FTDM_SUCCESS;
+}
+
+static ftdm_status_t ftdm_span_destroy(ftdm_span_t *span)
+{
+ ftdm_status_t status = FTDM_SUCCESS;
+ unsigned j;
+
+ ftdm_mutex_lock(span->mutex);
+
+ /* stop the signaling */
+ if (span->stop) {
+ status = span->stop(span);
+ }
+
+ /* destroy the channels */
+ ftdm_clear_flag(span, FTDM_SPAN_CONFIGURED);
+ for(j = 1; j <= span->chan_count && span->channels[j]; j++) {
+ ftdm_channel_t *cur_chan = span->channels[j];
+ if (cur_chan) {
+ if (ftdm_test_flag(cur_chan, FTDM_CHANNEL_CONFIGURED)) {
+ ftdm_channel_destroy(cur_chan);
+ }
+ ftdm_safe_free(cur_chan);
+ cur_chan = NULL;
+ }
+ }
+
+ /* destroy the I/O for the span */
+ if (span->fio && span->fio->span_destroy) {
+ ftdm_log(FTDM_LOG_INFO, "Destroying span %u type (%s)\n", span->span_id, span->type);
+ if (span->fio->span_destroy(span) != FTDM_SUCCESS) {
+ status = FTDM_FAIL;
+ }
+ ftdm_safe_free(span->type);
+ ftdm_safe_free(span->dtmf_hangup);
+ }
+
+ /* destroy final basic resources of the span data structure */
+ ftdm_queue_destroy(&span->pendingchans);
+ ftdm_mutex_unlock(span->mutex);
+ ftdm_mutex_destroy(&span->mutex);
+ ftdm_safe_free(span->signal_data);
+
+ return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_get_alarms(ftdm_channel_t *ftdmchan)
+{
+ ftdm_status_t status = FTDM_FAIL;
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CONFIGURED)) {
+ if (ftdmchan->span->fio->get_alarms) {
+ if ((status = ftdmchan->span->fio->get_alarms(ftdmchan)) == FTDM_SUCCESS) {
+ *ftdmchan->last_error = '\0';
+ if (ftdm_test_alarm_flag(ftdmchan, FTDM_ALARM_RED)) {
+ snprintf(ftdmchan->last_error + strlen(ftdmchan->last_error), sizeof(ftdmchan->last_error) - strlen(ftdmchan->last_error), "RED/");
+ }
+ if (ftdm_test_alarm_flag(ftdmchan, FTDM_ALARM_YELLOW)) {
+ snprintf(ftdmchan->last_error + strlen(ftdmchan->last_error), sizeof(ftdmchan->last_error) - strlen(ftdmchan->last_error), "YELLOW/");
+ }
+ if (ftdm_test_alarm_flag(ftdmchan, FTDM_ALARM_BLUE)) {
+ snprintf(ftdmchan->last_error + strlen(ftdmchan->last_error), sizeof(ftdmchan->last_error) - strlen(ftdmchan->last_error), "BLUE/");
+ }
+ if (ftdm_test_alarm_flag(ftdmchan, FTDM_ALARM_LOOPBACK)) {
+ snprintf(ftdmchan->last_error + strlen(ftdmchan->last_error), sizeof(ftdmchan->last_error) - strlen(ftdmchan->last_error), "LOOP/");
+ }
+ if (ftdm_test_alarm_flag(ftdmchan, FTDM_ALARM_RECOVER)) {
+ snprintf(ftdmchan->last_error + strlen(ftdmchan->last_error), sizeof(ftdmchan->last_error) - strlen(ftdmchan->last_error), "RECOVER/");
+ }
+ *(ftdmchan->last_error + strlen(ftdmchan->last_error) - 1) = '\0';
+
+ }
+ } else {
+ status = FTDM_NOTIMPL;
+ }
+ }
+
+ return status;
+}
+
+static void ftdm_span_add(ftdm_span_t *span)
+{
+ ftdm_span_t *sp;
+ ftdm_mutex_lock(globals.span_mutex);
+ for (sp = globals.spans; sp && sp->next; sp = sp->next);
+ if (sp) {
+ sp->next = span;
+ } else {
+ globals.spans = span;
+ }
+ hashtable_insert(globals.span_hash, (void *)span->name, span, HASHTABLE_FLAG_NONE);
+ ftdm_mutex_unlock(globals.span_mutex);
+}
+
+#if 0
+static void ftdm_span_del(ftdm_span_t *span)
+{
+ ftdm_span_t *last = NULL, *sp;
+
+ ftdm_mutex_lock(globals.span_mutex);
+ for (sp = globals.spans; sp; sp = sp->next) {
+
+ if (sp == span) {
+ if (last) {
+ last->next = sp->next;
+ } else {
+ globals.spans = sp->next;
+ }
+ hashtable_remove(globals.span_hash, (void *)sp->name);
+ break;
+ }
+
+ last = sp;
+ }
+ ftdm_mutex_unlock(globals.span_mutex);
+}
+#endif
+
+FT_DECLARE(ftdm_status_t) ftdm_span_stop(ftdm_span_t *span)
+{
+ if (span->stop) {
+ span->stop(span);
+ return FTDM_SUCCESS;
+ }
+
+ return FTDM_FAIL;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_create(ftdm_io_interface_t *fio, ftdm_span_t **span, const char *name)
+{
+ ftdm_span_t *new_span = NULL;
+ ftdm_status_t status = FTDM_FAIL;
+
+ ftdm_assert(fio != NULL, "No IO provided\n");
+
+ ftdm_mutex_lock(globals.mutex);
+
+ if (globals.span_index < FTDM_MAX_SPANS_INTERFACE) {
+ new_span = ftdm_calloc(sizeof(*new_span), 1);
+ ftdm_assert(new_span, "allocating span failed\n");
+
+ status = ftdm_mutex_create(&new_span->mutex);
+ ftdm_assert(status == FTDM_SUCCESS, "mutex creation failed\n");
+
+ status = ftdm_queue_create(&new_span->pendingchans, SPAN_PENDING_CHANS_QUEUE_SIZE);
+ ftdm_assert(status == FTDM_SUCCESS, "span chans queue creation failed\n");
+
+ ftdm_set_flag(new_span, FTDM_SPAN_CONFIGURED);
+ new_span->span_id = ++globals.span_index;
+ new_span->fio = fio;
+ ftdm_copy_string(new_span->tone_map[FTDM_TONEMAP_DIAL], "%(1000,0,350,440)", FTDM_TONEMAP_LEN);
+ ftdm_copy_string(new_span->tone_map[FTDM_TONEMAP_RING], "%(2000,4000,440,480)", FTDM_TONEMAP_LEN);
+ ftdm_copy_string(new_span->tone_map[FTDM_TONEMAP_BUSY], "%(500,500,480,620)", FTDM_TONEMAP_LEN);
+ ftdm_copy_string(new_span->tone_map[FTDM_TONEMAP_ATTN], "%(100,100,1400,2060,2450,2600)", FTDM_TONEMAP_LEN);
+ new_span->trunk_type = FTDM_TRUNK_NONE;
+ new_span->data_type = FTDM_TYPE_SPAN;
+
+ ftdm_mutex_lock(globals.span_mutex);
+ if (!ftdm_strlen_zero(name) && hashtable_search(globals.span_hash, (void *)name)) {
+ ftdm_log(FTDM_LOG_WARNING, "name %s is already used, substituting 'span%d' as the name\n", name, new_span->span_id);
+ name = NULL;
+ }
+ ftdm_mutex_unlock(globals.span_mutex);
+
+ if (!name) {
+ char buf[128] = "";
+ snprintf(buf, sizeof(buf), "span%d", new_span->span_id);
+ name = buf;
+ }
+ new_span->name = ftdm_strdup(name);
+ ftdm_span_add(new_span);
+ *span = new_span;
+ status = FTDM_SUCCESS;
+ }
+ ftdm_mutex_unlock(globals.mutex);
+ return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_close_all(void)
+{
+ ftdm_span_t *span;
+ uint32_t i = 0, j;
+
+ ftdm_mutex_lock(globals.span_mutex);
+ for (span = globals.spans; span; span = span->next) {
+ if (ftdm_test_flag(span, FTDM_SPAN_CONFIGURED)) {
+ for(j = 1; j <= span->chan_count && span->channels[j]; j++) {
+ ftdm_channel_t *toclose = span->channels[j];
+ if (ftdm_test_flag(toclose, FTDM_CHANNEL_INUSE)) {
+ ftdm_channel_close(&toclose);
+ }
+ i++;
+ }
+ }
+ }
+ ftdm_mutex_unlock(globals.span_mutex);
+
+ return i ? FTDM_SUCCESS : FTDM_FAIL;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_load_tones(ftdm_span_t *span, const char *mapname)
+{
+ ftdm_config_t cfg;
+ char *var, *val;
+ int x = 0;
+
+ if (!ftdm_config_open_file(&cfg, "tones.conf")) {
+ snprintf(span->last_error, sizeof(span->last_error), "error loading tones.");
+ return FTDM_FAIL;
+ }
+
+ while (ftdm_config_next_pair(&cfg, &var, &val)) {
+ int detect = 0;
+
+ if (!strcasecmp(cfg.category, mapname) && var && val) {
+ uint32_t index;
+ char *name = NULL;
+
+ if (!strncasecmp(var, "detect-", 7)) {
+ name = var + 7;
+ detect = 1;
+ } else if (!strncasecmp(var, "generate-", 9)) {
+ name = var + 9;
+ } else {
+ ftdm_log(FTDM_LOG_WARNING, "Unknown tone name %s\n", var);
+ continue;
+ }
+
+ index = ftdm_str2ftdm_tonemap(name);
+
+ if (index >= FTDM_TONEMAP_INVALID || index == FTDM_TONEMAP_NONE) {
+ ftdm_log(FTDM_LOG_WARNING, "Unknown tone name %s\n", name);
+ } else {
+ if (detect) {
+ char *p = val, *next;
+ int i = 0;
+ do {
+ teletone_process_t this;
+ next = strchr(p, ',');
+ this = (teletone_process_t)atof(p);
+ span->tone_detect_map[index].freqs[i++] = this;
+ if (next) {
+ p = next + 1;
+ }
+ } while (next);
+ ftdm_log(FTDM_LOG_DEBUG, "added tone detect [%s] = [%s]\n", name, val);
+ } else {
+ ftdm_log(FTDM_LOG_DEBUG, "added tone generation [%s] = [%s]\n", name, val);
+ ftdm_copy_string(span->tone_map[index], val, sizeof(span->tone_map[index]));
+ }
+ x++;
+ }
+ }
+ }
+
+ ftdm_config_close_file(&cfg);
+
+ if (!x) {
+ snprintf(span->last_error, sizeof(span->last_error), "error loading tones.");
+ return FTDM_FAIL;
+ }
+
+ return FTDM_SUCCESS;
+
+}
+
+#define FTDM_SLINEAR_MAX_VALUE 32767
+#define FTDM_SLINEAR_MIN_VALUE -32767
+static void reset_gain_table(unsigned char *gain_table, float new_gain, ftdm_codec_t codec_gain)
+{
+ /* sample value */
+ unsigned char sv = 0;
+ /* linear gain factor */
+ float lingain = 0;
+ /* linear value for each table sample */
+ float linvalue = 0;
+ /* amplified (or attenuated in case of negative amplification) sample value */
+ int ampvalue = 0;
+
+ /* gain tables are only for alaw and ulaw */
+ if (codec_gain != FTDM_CODEC_ALAW && codec_gain != FTDM_CODEC_ULAW) {
+ ftdm_log(FTDM_LOG_WARNING, "Not resetting gain table because codec is not ALAW or ULAW but %d\n", codec_gain);
+ return;
+ }
+
+ if (!new_gain) {
+ /* for a 0.0db gain table, each alaw/ulaw sample value is left untouched (0 ==0, 1 == 1, 2 == 2 etc)*/
+ sv = 0;
+ while (1) {
+ gain_table[sv] = sv;
+ if (sv == (FTDM_GAINS_TABLE_SIZE-1)) {
+ break;
+ }
+ sv++;
+ }
+ return;
+ }
+
+ /* use the 20log rule to increase the gain: http://en.wikipedia.org/wiki/Gain, http:/en.wipedia.org/wiki/20_log_rule#Definitions */
+ lingain = (float)pow(10.0, new_gain/ 20.0);
+ sv = 0;
+ while (1) {
+ /* get the linear value for this alaw/ulaw sample value */
+ linvalue = codec_gain == FTDM_CODEC_ALAW ? (float)alaw_to_linear(sv) : (float)ulaw_to_linear(sv);
+
+ /* multiply the linear value and the previously calculated linear gain */
+ ampvalue = (int)(linvalue * lingain);
+
+ /* chop it if goes beyond the limits */
+ if (ampvalue > FTDM_SLINEAR_MAX_VALUE) {
+ ampvalue = FTDM_SLINEAR_MAX_VALUE;
+ }
+
+ if (ampvalue < FTDM_SLINEAR_MIN_VALUE) {
+ ampvalue = FTDM_SLINEAR_MIN_VALUE;
+ }
+ gain_table[sv] = codec_gain == FTDM_CODEC_ALAW ? linear_to_alaw(ampvalue) : linear_to_ulaw(ampvalue);
+ if (sv == (FTDM_GAINS_TABLE_SIZE-1)) {
+ break;
+ }
+ sv++;
+ }
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_add_channel(ftdm_span_t *span, ftdm_socket_t sockfd, ftdm_chan_type_t type, ftdm_channel_t **chan)
+{
+ unsigned char i = 0;
+ if (span->chan_count < FTDM_MAX_CHANNELS_SPAN) {
+ ftdm_channel_t *new_chan = span->channels[++span->chan_count];
+
+ if (!new_chan) {
+ if (!(new_chan = ftdm_calloc(1, sizeof(*new_chan)))) {
+ return FTDM_FAIL;
+ }
+ span->channels[span->chan_count] = new_chan;
+ }
+
+ new_chan->type = type;
+ new_chan->sockfd = sockfd;
+ new_chan->fio = span->fio;
+ new_chan->span_id = span->span_id;
+ new_chan->chan_id = span->chan_count;
+ new_chan->span = span;
+ new_chan->fds[0] = -1;
+ new_chan->fds[1] = -1;
+ new_chan->data_type = FTDM_TYPE_CHANNEL;
+ if (!new_chan->dtmf_on) {
+ new_chan->dtmf_on = FTDM_DEFAULT_DTMF_ON;
+ }
+
+ if (!new_chan->dtmf_off) {
+ new_chan->dtmf_off = FTDM_DEFAULT_DTMF_OFF;
+ }
+
+ ftdm_mutex_create(&new_chan->mutex);
+ ftdm_mutex_create(&new_chan->pre_buffer_mutex);
+
+ ftdm_buffer_create(&new_chan->digit_buffer, 128, 128, 0);
+ ftdm_buffer_create(&new_chan->gen_dtmf_buffer, 128, 128, 0);
+ new_chan->variable_hash = create_hashtable(16, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+
+ new_chan->dtmf_hangup_buf = ftdm_calloc (span->dtmf_hangup_len + 1, sizeof (char));
+
+ /* set 0.0db gain table */
+ i = 0;
+ while (1) {
+ new_chan->txgain_table[i] = i;
+ new_chan->rxgain_table[i] = i;
+ if (i == (sizeof(new_chan->txgain_table)-1)) {
+ break;
+ }
+ i++;
+ }
+
+ ftdm_set_flag(new_chan, FTDM_CHANNEL_CONFIGURED | FTDM_CHANNEL_READY);
+ *chan = new_chan;
+ return FTDM_SUCCESS;
+ }
+
+ return FTDM_FAIL;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_find_by_name(const char *name, ftdm_span_t **span)
+{
+ ftdm_status_t status = FTDM_FAIL;
+
+ ftdm_mutex_lock(globals.span_mutex);
+ if (!ftdm_strlen_zero(name)) {
+ if ((*span = hashtable_search(globals.span_hash, (void *)name))) {
+ status = FTDM_SUCCESS;
+ } else {
+ int span_id = atoi(name);
+
+ ftdm_span_find(span_id, span);
+ if (*span) {
+ status = FTDM_SUCCESS;
+ }
+ }
+ }
+ ftdm_mutex_unlock(globals.span_mutex);
+
+ return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_find(uint32_t id, ftdm_span_t **span)
+{
+ ftdm_span_t *fspan = NULL, *sp;
+
+ if (id > FTDM_MAX_SPANS_INTERFACE) {
+ return FTDM_FAIL;
+ }
+
+ ftdm_mutex_lock(globals.span_mutex);
+ for (sp = globals.spans; sp; sp = sp->next) {
+ if (sp->span_id == id) {
+ fspan = sp;
+ break;
+ }
+ }
+ ftdm_mutex_unlock(globals.span_mutex);
+
+ if (!fspan || !ftdm_test_flag(fspan, FTDM_SPAN_CONFIGURED)) {
+ return FTDM_FAIL;
+ }
+
+ *span = fspan;
+
+ return FTDM_SUCCESS;
+
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_set_event_callback(ftdm_span_t *span, fio_event_cb_t event_callback)
+{
+ ftdm_mutex_lock(span->mutex);
+ span->event_callback = event_callback;
+ ftdm_mutex_unlock(span->mutex);
+ return FTDM_SUCCESS;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_span_poll_event(ftdm_span_t *span, uint32_t ms)
+{
+ assert(span->fio != NULL);
+
+ if (span->fio->poll_event) {
+ return span->fio->poll_event(span, ms);
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "poll_event method not implemented in module %s!", span->fio->name);
+ }
+
+ return FTDM_NOTIMPL;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_next_event(ftdm_span_t *span, ftdm_event_t **event)
+{
+ ftdm_status_t status = FTDM_FAIL;
+ ftdm_sigmsg_t sigmsg;
+ ftdm_assert_return(span->fio != NULL, FTDM_FAIL, "No I/O module attached to this span!\n");
+
+ if (!span->fio->next_event) {
+ ftdm_log(FTDM_LOG_ERROR, "next_event method not implemented in module %s!", span->fio->name);
+ return FTDM_NOTIMPL;
+ }
+
+ status = span->fio->next_event(span, event);
+ if (status != FTDM_SUCCESS) {
+ return status;
+ }
+
+ /* before returning the event to the user we do some core operations with certain OOB events */
+ memset(&sigmsg, 0, sizeof(sigmsg));
+ sigmsg.span_id = span->span_id;
+ sigmsg.chan_id = (*event)->channel->chan_id;
+ sigmsg.channel = (*event)->channel;
+ switch ((*event)->enum_id) {
+ case FTDM_OOB_ALARM_CLEAR:
+ {
+ sigmsg.event_id = FTDM_SIGEVENT_ALARM_CLEAR;
+ ftdm_clear_flag_locked((*event)->channel, FTDM_CHANNEL_IN_ALARM);
+ ftdm_span_send_signal(span, &sigmsg);
+ }
+ break;
+ case FTDM_OOB_ALARM_TRAP:
+ {
+ sigmsg.event_id = FTDM_SIGEVENT_ALARM_TRAP;
+ ftdm_set_flag_locked((*event)->channel, FTDM_CHANNEL_IN_ALARM);
+ ftdm_span_send_signal(span, &sigmsg);
+ }
+ break;
+ default:
+ /* NOOP */
+ break;
+ }
+
+ return status;
+}
+
+static ftdm_status_t ftdmchan_fsk_write_sample(int16_t *buf, ftdm_size_t buflen, void *user_data)
+{
+ ftdm_channel_t *ftdmchan = (ftdm_channel_t *) user_data;
+ ftdm_buffer_write(ftdmchan->fsk_buffer, buf, buflen * 2);
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_send_fsk_data(ftdm_channel_t *ftdmchan, ftdm_fsk_data_state_t *fsk_data, float db_level)
+{
+ struct ftdm_fsk_modulator fsk_trans;
+
+ if (!ftdmchan->fsk_buffer) {
+ ftdm_buffer_create(&ftdmchan->fsk_buffer, 128, 128, 0);
+ } else {
+ ftdm_buffer_zero(ftdmchan->fsk_buffer);
+ }
+
+ if (ftdmchan->token_count > 1) {
+ ftdm_fsk_modulator_init(&fsk_trans, FSK_BELL202, ftdmchan->rate, fsk_data, db_level, 80, 5, 0, ftdmchan_fsk_write_sample, ftdmchan);
+ ftdm_fsk_modulator_send_all((&fsk_trans));
+ } else {
+ ftdm_fsk_modulator_init(&fsk_trans, FSK_BELL202, ftdmchan->rate, fsk_data, db_level, 180, 5, 300, ftdmchan_fsk_write_sample, ftdmchan);
+ ftdm_fsk_modulator_send_all((&fsk_trans));
+ ftdmchan->buffer_delay = 3500 / ftdmchan->effective_interval;
+ }
+
+ return FTDM_SUCCESS;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_set_event_callback(ftdm_channel_t *ftdmchan, fio_event_cb_t event_callback)
+{
+ ftdm_mutex_lock(ftdmchan->mutex);
+ ftdmchan->event_callback = event_callback;
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_clear_token(ftdm_channel_t *ftdmchan, const char *token)
+{
+ ftdm_status_t status = FTDM_FAIL;
+
+ ftdm_mutex_lock(ftdmchan->mutex);
+ if (token == NULL) {
+ memset(ftdmchan->tokens, 0, sizeof(ftdmchan->tokens));
+ ftdmchan->token_count = 0;
+ } else if (*token != '\0') {
+ char tokens[FTDM_MAX_TOKENS][FTDM_TOKEN_STRLEN];
+ int32_t i, count = ftdmchan->token_count;
+ memcpy(tokens, ftdmchan->tokens, sizeof(tokens));
+ memset(ftdmchan->tokens, 0, sizeof(ftdmchan->tokens));
+ ftdmchan->token_count = 0;
+
+ for (i = 0; i < count; i++) {
+ if (strcmp(tokens[i], token)) {
+ ftdm_copy_string(ftdmchan->tokens[ftdmchan->token_count], tokens[i], sizeof(ftdmchan->tokens[ftdmchan->token_count]));
+ ftdmchan->token_count++;
+ }
+ }
+
+ status = FTDM_SUCCESS;
+ }
+ ftdm_mutex_unlock(ftdmchan->mutex);
+
+ return status;
+}
+
+FT_DECLARE(void) ftdm_channel_rotate_tokens(ftdm_channel_t *ftdmchan)
+{
+ if (ftdmchan->token_count) {
+ memmove(ftdmchan->tokens[1], ftdmchan->tokens[0], ftdmchan->token_count * FTDM_TOKEN_STRLEN);
+ ftdm_copy_string(ftdmchan->tokens[0], ftdmchan->tokens[ftdmchan->token_count], FTDM_TOKEN_STRLEN);
+ *ftdmchan->tokens[ftdmchan->token_count] = '\0';
+ }
+}
+
+FT_DECLARE(void) ftdm_channel_replace_token(ftdm_channel_t *ftdmchan, const char *old_token, const char *new_token)
+{
+ unsigned int i;
+
+ if (ftdmchan->token_count) {
+ for(i = 0; i < ftdmchan->token_count; i++) {
+ if (!strcmp(ftdmchan->tokens[i], old_token)) {
+ ftdm_copy_string(ftdmchan->tokens[i], new_token, FTDM_TOKEN_STRLEN);
+ break;
+ }
+ }
+ }
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_add_token(ftdm_channel_t *ftdmchan, char *token, int end)
+{
+ ftdm_status_t status = FTDM_FAIL;
+
+ ftdm_mutex_lock(ftdmchan->mutex);
+ if (ftdmchan->token_count < FTDM_MAX_TOKENS) {
+ if (end) {
+ ftdm_copy_string(ftdmchan->tokens[ftdmchan->token_count++], token, FTDM_TOKEN_STRLEN);
+ } else {
+ memmove(ftdmchan->tokens[1], ftdmchan->tokens[0], ftdmchan->token_count * FTDM_TOKEN_STRLEN);
+ ftdm_copy_string(ftdmchan->tokens[0], token, FTDM_TOKEN_STRLEN);
+ ftdmchan->token_count++;
+ }
+ status = FTDM_SUCCESS;
+ }
+ ftdm_mutex_unlock(ftdmchan->mutex);
+
+ return status;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_complete_state(ftdm_channel_t *ftdmchan)
+{
+ ftdm_channel_state_t state = ftdmchan->state;
+
+ if (state == FTDM_CHANNEL_STATE_PROGRESS) {
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
+ } else if (state == FTDM_CHANNEL_STATE_UP) {
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_MEDIA);
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_ANSWERED);
+ } else if (state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_MEDIA);
+ }
+
+ return FTDM_SUCCESS;
+}
+
+static int ftdm_parse_state_map(ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, ftdm_state_map_t *state_map)
+{
+ int x = 0, ok = 0;
+ ftdm_state_direction_t direction = ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) ? ZSD_OUTBOUND : ZSD_INBOUND;
+
+ for(x = 0; x < FTDM_MAP_NODE_SIZE; x++) {
+ int i = 0, proceed = 0;
+ if (!state_map->nodes[x].type) {
+ break;
+ }
+
+ if (state_map->nodes[x].direction != direction) {
+ continue;
+ }
+
+ if (state_map->nodes[x].check_states[0] == FTDM_ANY_STATE) {
+ proceed = 1;
+ } else {
+ for(i = 0; i < FTDM_MAP_MAX; i++) {
+ if (state_map->nodes[x].check_states[i] == ftdmchan->state) {
+ proceed = 1;
+ break;
+ }
+ }
+ }
+
+ if (!proceed) {
+ continue;
+ }
+
+ for(i = 0; i < FTDM_MAP_MAX; i++) {
+ ok = (state_map->nodes[x].type == ZSM_ACCEPTABLE);
+ if (state_map->nodes[x].states[i] == FTDM_END) {
+ break;
+ }
+ if (state_map->nodes[x].states[i] == state) {
+ ok = !ok;
+ goto end;
+ }
+ }
+ }
+ end:
+
+ return ok;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int lock)
+{
+ int ok = 1;
+
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY)) {
+ return FTDM_FAIL;
+ }
+
+ if (ftdm_test_flag(ftdmchan->span, FTDM_SPAN_SUSPENDED)) {
+ if (state != FTDM_CHANNEL_STATE_RESTART && state != FTDM_CHANNEL_STATE_DOWN) {
+ return FTDM_FAIL;
+ }
+ }
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
+ ftdm_log(FTDM_LOG_CRIT, "Ignored state change request from %s to %s, the previous state change has not been processed yet\n",
+ ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
+ return FTDM_FAIL;
+ }
+
+ if (lock) {
+ ftdm_mutex_lock(ftdmchan->mutex);
+ }
+
+ if (ftdmchan->span->state_map) {
+ ok = ftdm_parse_state_map(ftdmchan, state, ftdmchan->span->state_map);
+ goto end;
+ }
+
+ switch(ftdmchan->state) {
+ case FTDM_CHANNEL_STATE_HANGUP:
+ case FTDM_CHANNEL_STATE_TERMINATING:
+ {
+ ok = 0;
+ switch(state) {
+ case FTDM_CHANNEL_STATE_DOWN:
+ case FTDM_CHANNEL_STATE_BUSY:
+ case FTDM_CHANNEL_STATE_RESTART:
+ ok = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_UP:
+ {
+ ok = 1;
+ switch(state) {
+ case FTDM_CHANNEL_STATE_PROGRESS:
+ case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+ case FTDM_CHANNEL_STATE_RING:
+ ok = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_DOWN:
+ {
+ ok = 0;
+
+ switch(state) {
+ case FTDM_CHANNEL_STATE_DIALTONE:
+ case FTDM_CHANNEL_STATE_COLLECT:
+ case FTDM_CHANNEL_STATE_DIALING:
+ case FTDM_CHANNEL_STATE_RING:
+ case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+ case FTDM_CHANNEL_STATE_PROGRESS:
+ case FTDM_CHANNEL_STATE_GET_CALLERID:
+ case FTDM_CHANNEL_STATE_GENRING:
+ ok = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_BUSY:
+ {
+ switch(state) {
+ case FTDM_CHANNEL_STATE_UP:
+ ok = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_RING:
+ {
+ switch(state) {
+ case FTDM_CHANNEL_STATE_UP:
+ ok = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ end:
+
+ if (state == ftdmchan->state) {
+ ok = 0;
+ }
+
+
+ if (ok) {
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+
+ ftdm_mutex_lock(ftdmchan->span->mutex);
+ ftdm_set_flag(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
+ ftdm_queue_enqueue(ftdmchan->span->pendingchans, ftdmchan);
+ ftdm_mutex_unlock(ftdmchan->span->mutex);
+
+ ftdmchan->last_state = ftdmchan->state;
+ ftdmchan->state = state;
+ }
+
+ if (lock) {
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ }
+
+ return ok ? FTDM_SUCCESS : FTDM_FAIL;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_group_channel_use_count(ftdm_group_t *group, uint32_t *count)
+{
+ uint32_t j;
+
+ *count = 0;
+
+ if (!group) {
+ return FTDM_FAIL;
+ }
+
+ for(j = 0; j < group->chan_count && group->channels[j]; j++) {
+ if (group->channels[j]) {
+ if (ftdm_test_flag(group->channels[j], FTDM_CHANNEL_INUSE)) {
+ (*count)++;
+ }
+ }
+ }
+
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
+{
+ ftdm_status_t status = FTDM_FAIL;
+ ftdm_channel_t *check;
+ uint32_t i, count;
+ ftdm_group_t *group = NULL;
+
+ if (group_id) {
+ ftdm_group_find(group_id, &group);
+ }
+
+ if (!group) {
+ ftdm_log(FTDM_LOG_ERROR, "Group %d not defined!\n", group_id);
+ *ftdmchan = NULL;
+ return FTDM_FAIL;
+ }
+
+ ftdm_group_channel_use_count(group, &count);
+
+ if (count >= group->chan_count) {
+ ftdm_log(FTDM_LOG_ERROR, "All circuits are busy (%d channels used out of %d available).\n", count, group->chan_count);
+ *ftdmchan = NULL;
+ return FTDM_FAIL;
+ }
+
+
+ if (direction == FTDM_TOP_DOWN) {
+ i = 0;
+ } else {
+ i = group->chan_count-1;
+ }
+
+ ftdm_mutex_lock(group->mutex);
+ for (;;) {
+ if (direction == FTDM_TOP_DOWN) {
+ if (i >= group->chan_count) {
+ break;
+ }
+ } else {
+ if (i < 0) {
+ break;
+ }
+ }
+
+ if (!(check = group->channels[i])) {
+ status = FTDM_FAIL;
+ break;
+ }
+
+ if (ftdm_test_flag(check, FTDM_CHANNEL_READY) &&
+ !ftdm_test_flag(check, FTDM_CHANNEL_INUSE) &&
+ !ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) &&
+ !ftdm_test_flag(check, FTDM_CHANNEL_IN_ALARM) &&
+ check->state == FTDM_CHANNEL_STATE_DOWN &&
+ FTDM_IS_VOICE_CHANNEL(check)
+ ) {
+ ftdm_span_t* span = NULL;
+ ftdm_span_find(check->span_id, &span);
+ if (span && span->channel_request) {
+ status = span->channel_request(span, check->chan_id, direction, caller_data, ftdmchan);
+ break;
+ }
+
+ status = check->fio->open(check);
+
+ if (status == FTDM_SUCCESS) {
+ ftdm_set_flag(check, FTDM_CHANNEL_INUSE);
+ ftdm_channel_open_chan(check);
+ *ftdmchan = check;
+ break;
+ }
+ }
+
+ if (direction == FTDM_TOP_DOWN) {
+ i++;
+ } else {
+ i--;
+ }
+ }
+ ftdm_mutex_unlock(group->mutex);
+ return status;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_span_channel_use_count(ftdm_span_t *span, uint32_t *count)
+{
+ uint32_t j;
+
+ *count = 0;
+
+ if (!span || !ftdm_test_flag(span, FTDM_SPAN_CONFIGURED)) {
+ return FTDM_FAIL;
+ }
+
+ for(j = 1; j <= span->chan_count && span->channels[j]; j++) {
+ if (span->channels[j]) {
+ if (ftdm_test_flag(span->channels[j], FTDM_CHANNEL_INUSE)) {
+ (*count)++;
+ }
+ }
+ }
+
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
+{
+ ftdm_status_t status = FTDM_FAIL;
+ ftdm_channel_t *check;
+ uint32_t i, j, count;
+ ftdm_span_t *span = NULL;
+ uint32_t span_max;
+
+ if (span_id) {
+ ftdm_span_find(span_id, &span);
+
+ if (!span || !ftdm_test_flag(span, FTDM_SPAN_CONFIGURED)) {
+ ftdm_log(FTDM_LOG_CRIT, "SPAN NOT DEFINED!\n");
+ *ftdmchan = NULL;
+ return FTDM_FAIL;
+ }
+
+ ftdm_span_channel_use_count(span, &count);
+
+ if (count >= span->chan_count) {
+ ftdm_log(FTDM_LOG_CRIT, "All circuits are busy.\n");
+ *ftdmchan = NULL;
+ return FTDM_FAIL;
+ }
+
+ if (span->channel_request && !span->suggest_chan_id) {
+ ftdm_set_caller_data(span, caller_data);
+ return span->channel_request(span, 0, direction, caller_data, ftdmchan);
+ }
+
+ span_max = span_id;
+ j = span_id;
+ } else {
+ ftdm_log(FTDM_LOG_CRIT, "No span supplied\n");
+ *ftdmchan = NULL;
+ return FTDM_FAIL;
+ }
+
+ ftdm_mutex_lock(span->mutex);
+
+ if (direction == FTDM_TOP_DOWN) {
+ i = 1;
+ } else {
+ i = span->chan_count;
+ }
+
+ for(;;) {
+
+ if (direction == FTDM_TOP_DOWN) {
+ if (i > span->chan_count) {
+ break;
+ }
+ } else {
+ if (i == 0) {
+ break;
+ }
+ }
+
+ if (!(check = span->channels[i])) {
+ status = FTDM_FAIL;
+ break;
+ }
+
+ if (ftdm_test_flag(check, FTDM_CHANNEL_READY) &&
+ !ftdm_test_flag(check, FTDM_CHANNEL_INUSE) &&
+ !ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) &&
+ !ftdm_test_flag(check, FTDM_CHANNEL_IN_ALARM) &&
+ check->state == FTDM_CHANNEL_STATE_DOWN &&
+ FTDM_IS_VOICE_CHANNEL(check)
+ ) {
+
+ if (span && span->channel_request) {
+ ftdm_set_caller_data(span, caller_data);
+ status = span->channel_request(span, i, direction, caller_data, ftdmchan);
+ break;
+ }
+
+ status = check->fio->open(check);
+
+ if (status == FTDM_SUCCESS) {
+ ftdm_set_flag(check, FTDM_CHANNEL_INUSE);
+ ftdm_channel_open_chan(check);
+ *ftdmchan = check;
+ break;
+ }
+ }
+
+ if (direction == FTDM_TOP_DOWN) {
+ i++;
+ } else {
+ i--;
+ }
+ }
+
+ ftdm_mutex_unlock(span->mutex);
+
+ return status;
+}
+
+static ftdm_status_t ftdm_channel_reset(ftdm_channel_t *ftdmchan)
+{
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_OPEN);
+ ftdmchan->event_callback = NULL;
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF);
+ ftdm_channel_done(ftdmchan);
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_HOLD);
+
+ memset(ftdmchan->tokens, 0, sizeof(ftdmchan->tokens));
+ ftdmchan->token_count = 0;
+
+ ftdm_channel_flush_dtmf(ftdmchan);
+
+ if (ftdmchan->gen_dtmf_buffer) {
+ ftdm_buffer_zero(ftdmchan->gen_dtmf_buffer);
+ }
+
+ if (ftdmchan->digit_buffer) {
+ ftdm_buffer_zero(ftdmchan->digit_buffer);
+ }
+
+ if (!ftdmchan->dtmf_on) {
+ ftdmchan->dtmf_on = FTDM_DEFAULT_DTMF_ON;
+ }
+
+ if (!ftdmchan->dtmf_off) {
+ ftdmchan->dtmf_off = FTDM_DEFAULT_DTMF_OFF;
+ }
+
+ memset(ftdmchan->dtmf_hangup_buf, '\0', ftdmchan->span->dtmf_hangup_len);
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE)) {
+ ftdmchan->effective_codec = ftdmchan->native_codec;
+ ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE);
+ }
+
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_init(ftdm_channel_t *ftdmchan)
+{
+ if (ftdmchan->init_state != FTDM_CHANNEL_STATE_DOWN) {
+ ftdm_set_state_locked(ftdmchan, ftdmchan->init_state);
+ ftdmchan->init_state = FTDM_CHANNEL_STATE_DOWN;
+ }
+
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan)
+{
+ ftdm_status_t status = FTDM_FAIL;
+
+ assert(ftdmchan != NULL);
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED)) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "Channel is suspended\n");
+ return FTDM_FAIL;
+ }
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "Channel is alarmed\n");
+ return FTDM_FAIL;
+ }
+
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY) || (status = ftdm_mutex_trylock(ftdmchan->mutex)) != FTDM_SUCCESS) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Channel is not ready or is in use %d %d", ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY), status);
+ return status;
+ }
+
+ status = FTDM_FAIL;
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY)) {
+ status = ftdmchan->span->fio->open(ftdmchan);
+ if (status == FTDM_SUCCESS) {
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OPEN | FTDM_CHANNEL_INUSE);
+ }
+ } else {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "Channel is not ready");
+ }
+
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan)
+{
+ ftdm_channel_t *check;
+ ftdm_status_t status = FTDM_FAIL;
+ ftdm_span_t *span = NULL;
+
+ ftdm_mutex_unlock(globals.mutex);
+ ftdm_span_find(span_id, &span);
+
+ if (!span || !ftdm_test_flag(span, FTDM_SPAN_CONFIGURED) || chan_id >= FTDM_MAX_CHANNELS_SPAN) {
+ ftdm_log(FTDM_LOG_CRIT, "SPAN NOT DEFINED!\n");
+ *ftdmchan = NULL;
+ goto done;
+ }
+
+ if (span->channel_request) {
+ ftdm_log(FTDM_LOG_ERROR, "Individual channel selection not implemented on this span.\n");
+ *ftdmchan = NULL;
+ goto done;
+ }
+
+ if (!(check = span->channels[chan_id])) {
+ ftdm_log(FTDM_LOG_ERROR, "Invalid Channel %d\n", chan_id);
+ *ftdmchan = NULL;
+ goto done;
+ }
+
+ if (ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) || ftdm_test_flag(check, FTDM_CHANNEL_IN_ALARM) ||
+ !ftdm_test_flag(check, FTDM_CHANNEL_READY) || (status = ftdm_mutex_trylock(check->mutex)) != FTDM_SUCCESS) {
+ *ftdmchan = NULL;
+ goto done;
+ }
+
+ status = FTDM_FAIL;
+
+ if (ftdm_test_flag(check, FTDM_CHANNEL_READY) && (!ftdm_test_flag(check, FTDM_CHANNEL_INUSE) ||
+ (check->type == FTDM_CHAN_TYPE_FXS && check->token_count == 1))) {
+ if (!ftdm_test_flag(check, FTDM_CHANNEL_OPEN)) {
+ status = check->fio->open(check);
+ if (status == FTDM_SUCCESS) {
+ ftdm_set_flag(check, FTDM_CHANNEL_OPEN);
+ }
+ } else {
+ status = FTDM_SUCCESS;
+ }
+ ftdm_set_flag(check, FTDM_CHANNEL_INUSE);
+ *ftdmchan = check;
+ }
+ ftdm_mutex_unlock(check->mutex);
+
+ done:
+ ftdm_mutex_unlock(globals.mutex);
+
+ return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_outgoing_call(ftdm_channel_t *ftdmchan)
+{
+ ftdm_status_t status;
+
+ assert(ftdmchan != NULL);
+
+ if (ftdmchan->span->outgoing_call) {
+ if ((status = ftdmchan->span->outgoing_call(ftdmchan)) == FTDM_SUCCESS) {
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
+ }
+ return status;
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "outgoing_call method not implemented!\n");
+ }
+
+ return FTDM_FAIL;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_set_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t sigstatus)
+{
+ ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "Null channel\n");
+ ftdm_assert_return(ftdmchan->span != NULL, FTDM_FAIL, "Null span\n");
+
+ if (ftdmchan->span->set_channel_sig_status) {
+ return ftdmchan->span->set_channel_sig_status(ftdmchan, sigstatus);
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "set_channel_sig_status method not implemented!\n");
+ return FTDM_FAIL;
+ }
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_get_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t *sigstatus)
+{
+ ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "Null channel\n");
+ ftdm_assert_return(ftdmchan->span != NULL, FTDM_FAIL, "Null span\n");
+ ftdm_assert_return(sigstatus != NULL, FTDM_FAIL, "Null sig status parameter\n");
+
+ if (ftdmchan->span->get_channel_sig_status) {
+ return ftdmchan->span->get_channel_sig_status(ftdmchan, sigstatus);
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "get_channel_sig_status method not implemented!\n");
+ return FTDM_FAIL;
+ }
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_set_sig_status(ftdm_span_t *span, ftdm_signaling_status_t sigstatus)
+{
+ ftdm_assert_return(span != NULL, FTDM_FAIL, "Null span\n");
+
+ if (span->set_span_sig_status) {
+ return span->set_span_sig_status(span, sigstatus);
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "set_span_sig_status method not implemented!\n");
+ return FTDM_FAIL;
+ }
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_get_sig_status(ftdm_span_t *span, ftdm_signaling_status_t *sigstatus)
+{
+ ftdm_assert_return(span != NULL, FTDM_FAIL, "Null span\n");
+ ftdm_assert_return(sigstatus != NULL, FTDM_FAIL, "Null sig status parameter\n");
+
+ if (span->get_span_sig_status) {
+ return span->get_span_sig_status(span, sigstatus);
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "get_span_sig_status method not implemented!\n");
+ return FTDM_FAIL;
+ }
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan)
+{
+ assert(ftdmchan != NULL);
+
+ ftdm_mutex_lock(ftdmchan->mutex);
+
+ memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data));
+
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_INUSE);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_WINK);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_FLASH);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_HOLD);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_RINGING);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_PROGRESS_DETECT);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_3WAY);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_MEDIA);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_ANSWERED);
+ ftdm_mutex_lock(ftdmchan->pre_buffer_mutex);
+ ftdm_buffer_destroy(&ftdmchan->pre_buffer);
+ ftdmchan->pre_buffer_size = 0;
+ ftdm_mutex_unlock(ftdmchan->pre_buffer_mutex);
+
+ ftdmchan->init_state = FTDM_CHANNEL_STATE_DOWN;
+ ftdmchan->state = FTDM_CHANNEL_STATE_DOWN;
+
+ ftdm_log(FTDM_LOG_DEBUG, "channel done %u:%u\n", ftdmchan->span_id, ftdmchan->chan_id);
+
+ ftdm_mutex_unlock(ftdmchan->mutex);
+
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_use(ftdm_channel_t *ftdmchan)
+{
+
+ assert(ftdmchan != NULL);
+
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_INUSE);
+
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_close(ftdm_channel_t **ftdmchan)
+{
+ ftdm_channel_t *check;
+ ftdm_status_t status = FTDM_FAIL;
+
+ assert(ftdmchan != NULL);
+ check = *ftdmchan;
+ *ftdmchan = NULL;
+
+ if (!check) {
+ return FTDM_FAIL;
+ }
+
+ if (!ftdm_test_flag(check, FTDM_CHANNEL_INUSE)) {
+ ftdm_log(FTDM_LOG_WARNING, "Called ftdm_channel_close but never ftdm_channel_open in chan %d:%d??\n", check->span_id, check->chan_id);
+ return FTDM_FAIL;
+ }
+
+ if (ftdm_test_flag(check, FTDM_CHANNEL_CONFIGURED)) {
+ ftdm_mutex_lock(check->mutex);
+ if (ftdm_test_flag(check, FTDM_CHANNEL_OPEN)) {
+ status = check->fio->close(check);
+ if (status == FTDM_SUCCESS) {
+ ftdm_clear_flag(check, FTDM_CHANNEL_INUSE);
+ ftdm_channel_reset(check);
+ *ftdmchan = NULL;
+ }
+ }
+ check->ring_count = 0;
+ ftdm_mutex_unlock(check->mutex);
+ }
+
+ return status;
+}
+
+
+static ftdm_status_t ftdmchan_activate_dtmf_buffer(ftdm_channel_t *ftdmchan)
+{
+
+ if (!ftdmchan->dtmf_buffer) {
+ if (ftdm_buffer_create(&ftdmchan->dtmf_buffer, 1024, 3192, 0) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to allocate DTMF Buffer!\n");
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "buffer error");
+ return FTDM_FAIL;
+ } else {
+ ftdm_log(FTDM_LOG_DEBUG, "Created DTMF Buffer!\n");
+ }
+ }
+
+
+ if (!ftdmchan->tone_session.buffer) {
+ memset(&ftdmchan->tone_session, 0, sizeof(ftdmchan->tone_session));
+ teletone_init_session(&ftdmchan->tone_session, 0, NULL, NULL);
+ }
+
+ ftdmchan->tone_session.rate = ftdmchan->rate;
+ ftdmchan->tone_session.duration = ftdmchan->dtmf_on * (ftdmchan->tone_session.rate / 1000);
+ ftdmchan->tone_session.wait = ftdmchan->dtmf_off * (ftdmchan->tone_session.rate / 1000);
+ ftdmchan->tone_session.volume = -7;
+
+ /*
+ ftdmchan->tone_session.debug = 1;
+ ftdmchan->tone_session.debug_stream = stdout;
+ */
+
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_command_t command, void *obj)
+{
+ ftdm_status_t status = FTDM_FAIL;
+
+ assert(ftdmchan != NULL);
+ assert(ftdmchan->fio != NULL);
+
+ ftdm_mutex_lock(ftdmchan->mutex);
+
+ switch(command) {
+
+ case FTDM_COMMAND_ENABLE_CALLERID_DETECT:
+ {
+ if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_CALLERID)) {
+ if (ftdm_fsk_demod_init(&ftdmchan->fsk, ftdmchan->rate, ftdmchan->fsk_buf, sizeof(ftdmchan->fsk_buf)) != FTDM_SUCCESS) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT);
+ }
+ }
+ break;
+ case FTDM_COMMAND_DISABLE_CALLERID_DETECT:
+ {
+ if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_CALLERID)) {
+ ftdm_fsk_demod_destroy(&ftdmchan->fsk);
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT);
+ }
+ }
+ break;
+ case FTDM_COMMAND_TRACE_INPUT:
+ {
+ char *path = (char *) obj;
+ if (ftdmchan->fds[0] > 0) {
+ close(ftdmchan->fds[0]);
+ ftdmchan->fds[0] = -1;
+ }
+ if ((ftdmchan->fds[0] = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) {
+ ftdm_log(FTDM_LOG_DEBUG, "Tracing channel %u:%u to [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, path);
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ break;
+ case FTDM_COMMAND_TRACE_OUTPUT:
+ {
+ char *path = (char *) obj;
+ if (ftdmchan->fds[1] > 0) {
+ close(ftdmchan->fds[1]);
+ ftdmchan->fds[1] = -1;
+ }
+ if ((ftdmchan->fds[1] = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) {
+ ftdm_log(FTDM_LOG_DEBUG, "Tracing channel %u:%u to [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, path);
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ break;
+ case FTDM_COMMAND_SET_INTERVAL:
+ {
+ if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_INTERVAL)) {
+ ftdmchan->effective_interval = FTDM_COMMAND_OBJ_INT;
+ if (ftdmchan->effective_interval == ftdmchan->native_interval) {
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_BUFFER);
+ } else {
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_BUFFER);
+ }
+ ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8);
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ }
+ break;
+ case FTDM_COMMAND_GET_INTERVAL:
+ {
+ if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_INTERVAL)) {
+ FTDM_COMMAND_OBJ_INT = ftdmchan->effective_interval;
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ }
+ break;
+ case FTDM_COMMAND_SET_CODEC:
+ {
+ if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_CODECS)) {
+ ftdmchan->effective_codec = FTDM_COMMAND_OBJ_INT;
+
+ if (ftdmchan->effective_codec == ftdmchan->native_codec) {
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE);
+ } else {
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE);
+ }
+ ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8);
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ }
+ break;
+
+ case FTDM_COMMAND_SET_NATIVE_CODEC:
+ {
+ if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_CODECS)) {
+ ftdmchan->effective_codec = ftdmchan->native_codec;
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE);
+ ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8);
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ }
+ break;
+
+ case FTDM_COMMAND_GET_CODEC:
+ {
+ if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_CODECS)) {
+ FTDM_COMMAND_OBJ_INT = ftdmchan->effective_codec;
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ }
+ break;
+ case FTDM_COMMAND_GET_NATIVE_CODEC:
+ {
+ if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_CODECS)) {
+ FTDM_COMMAND_OBJ_INT = ftdmchan->native_codec;
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ }
+ break;
+ case FTDM_COMMAND_ENABLE_PROGRESS_DETECT:
+ {
+ if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_PROGRESS)) {
+ /* if they don't have thier own, use ours */
+ ftdm_channel_clear_detected_tones(ftdmchan);
+ ftdm_channel_clear_needed_tones(ftdmchan);
+ teletone_multi_tone_init(&ftdmchan->span->tone_finder[FTDM_TONEMAP_DIAL], &ftdmchan->span->tone_detect_map[FTDM_TONEMAP_DIAL]);
+ teletone_multi_tone_init(&ftdmchan->span->tone_finder[FTDM_TONEMAP_RING], &ftdmchan->span->tone_detect_map[FTDM_TONEMAP_RING]);
+ teletone_multi_tone_init(&ftdmchan->span->tone_finder[FTDM_TONEMAP_BUSY], &ftdmchan->span->tone_detect_map[FTDM_TONEMAP_BUSY]);
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS_DETECT);
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ }
+ break;
+ case FTDM_COMMAND_DISABLE_PROGRESS_DETECT:
+ {
+ if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_PROGRESS)) {
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_PROGRESS_DETECT);
+ ftdm_channel_clear_detected_tones(ftdmchan);
+ ftdm_channel_clear_needed_tones(ftdmchan);
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ }
+ break;
+ case FTDM_COMMAND_ENABLE_DTMF_DETECT:
+ {
+ /* if they don't have thier own, use ours */
+ if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_DETECT)) {
+ ftdm_tone_type_t tt = FTDM_COMMAND_OBJ_INT;
+ if (tt == FTDM_TONE_DTMF) {
+ teletone_dtmf_detect_init (&ftdmchan->dtmf_detect, ftdmchan->rate);
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_DTMF_DETECT);
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF);
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ } else {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid command");
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ }
+ }
+ break;
+ case FTDM_COMMAND_DISABLE_DTMF_DETECT:
+ {
+ if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_DETECT)) {
+ ftdm_tone_type_t tt = FTDM_COMMAND_OBJ_INT;
+ if (tt == FTDM_TONE_DTMF) {
+ teletone_dtmf_detect_init (&ftdmchan->dtmf_detect, ftdmchan->rate);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF);
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ } else {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid command");
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ }
+ }
+
+ case FTDM_COMMAND_SET_PRE_BUFFER_SIZE:
+ {
+ int val = FTDM_COMMAND_OBJ_INT;
+
+ if (val < 0) {
+ val = 0;
+ }
+
+ ftdmchan->pre_buffer_size = val * 8;
+
+ ftdm_mutex_lock(ftdmchan->pre_buffer_mutex);
+ if (!ftdmchan->pre_buffer_size) {
+ ftdm_buffer_destroy(&ftdmchan->pre_buffer);
+ } else if (!ftdmchan->pre_buffer) {
+ ftdm_buffer_create(&ftdmchan->pre_buffer, 1024, ftdmchan->pre_buffer_size, 0);
+ }
+ ftdm_mutex_unlock(ftdmchan->pre_buffer_mutex);
+
+ GOTO_STATUS(done, FTDM_SUCCESS);
+
+ }
+ break;
+ case FTDM_COMMAND_GET_DTMF_ON_PERIOD:
+ {
+ if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_GENERATE)) {
+ FTDM_COMMAND_OBJ_INT = ftdmchan->dtmf_on;
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ }
+ break;
+ case FTDM_COMMAND_GET_DTMF_OFF_PERIOD:
+ {
+ if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_GENERATE)) {
+ FTDM_COMMAND_OBJ_INT = ftdmchan->dtmf_on;
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ }
+ break;
+ case FTDM_COMMAND_SET_DTMF_ON_PERIOD:
+ {
+ if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_GENERATE)) {
+ int val = FTDM_COMMAND_OBJ_INT;
+ if (val > 10 && val < 1000) {
+ ftdmchan->dtmf_on = val;
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ } else {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid value %d range 10-1000", val);
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ }
+ }
+ break;
+ case FTDM_COMMAND_SET_DTMF_OFF_PERIOD:
+ {
+ if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_GENERATE)) {
+ int val = FTDM_COMMAND_OBJ_INT;
+ if (val > 10 && val < 1000) {
+ ftdmchan->dtmf_off = val;
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ } else {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid value %d range 10-1000", val);
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ }
+ }
+ break;
+ case FTDM_COMMAND_SEND_DTMF:
+ {
+ if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_GENERATE)) {
+ char *digits = FTDM_COMMAND_OBJ_CHAR_P;
+
+ if ((status = ftdmchan_activate_dtmf_buffer(ftdmchan)) != FTDM_SUCCESS) {
+ GOTO_STATUS(done, status);
+ }
+
+ ftdm_buffer_write(ftdmchan->gen_dtmf_buffer, digits, strlen(digits));
+
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ }
+ break;
+
+ case FTDM_COMMAND_DISABLE_ECHOCANCEL:
+ {
+ ftdm_mutex_lock(ftdmchan->pre_buffer_mutex);
+ ftdm_buffer_destroy(&ftdmchan->pre_buffer);
+ ftdmchan->pre_buffer_size = 0;
+ ftdm_mutex_unlock(ftdmchan->pre_buffer_mutex);
+ }
+ break;
+
+ /* FIXME: validate user gain values */
+ case FTDM_COMMAND_SET_RX_GAIN:
+ {
+ ftdmchan->rxgain = FTDM_COMMAND_OBJ_FLOAT;
+ reset_gain_table(ftdmchan->rxgain_table, ftdmchan->rxgain, ftdmchan->native_codec);
+ if (ftdmchan->rxgain == 0.0) {
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_USE_RX_GAIN);
+ } else {
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_USE_RX_GAIN);
+ }
+ }
+ break;
+ case FTDM_COMMAND_GET_RX_GAIN:
+ {
+ FTDM_COMMAND_OBJ_FLOAT = ftdmchan->rxgain;
+ }
+ break;
+ case FTDM_COMMAND_SET_TX_GAIN:
+ {
+ ftdmchan->txgain = FTDM_COMMAND_OBJ_FLOAT;
+ reset_gain_table(ftdmchan->txgain_table, ftdmchan->txgain, ftdmchan->native_codec);
+ if (ftdmchan->txgain == 0.0) {
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_USE_TX_GAIN);
+ } else {
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_USE_TX_GAIN);
+ }
+ }
+ break;
+ case FTDM_COMMAND_GET_TX_GAIN:
+ {
+ FTDM_COMMAND_OBJ_FLOAT = ftdmchan->txgain;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!ftdmchan->fio->command) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "method not implemented");
+ ftdm_log(FTDM_LOG_ERROR, "no command function defined by the I/O freetdm module!\n");
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+
+ status = ftdmchan->fio->command(ftdmchan, command, obj);
+
+ if (status == FTDM_NOTIMPL) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "I/O command %d not implemented in backend", command);
+ ftdm_log(FTDM_LOG_ERROR, "I/O backend does not support command %d!\n", command);
+ }
+done:
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ return status;
+
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_wait(ftdm_channel_t *ftdmchan, ftdm_wait_flag_t *flags, int32_t to)
+{
+ assert(ftdmchan != NULL);
+ assert(ftdmchan->fio != NULL);
+
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "channel not open");
+ return FTDM_FAIL;
+ }
+
+ if (!ftdmchan->fio->wait) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "method not implemented");
+ return FTDM_FAIL;
+ }
+
+ return ftdmchan->fio->wait(ftdmchan, flags, to);
+
+}
+
+/*******************************/
+FIO_CODEC_FUNCTION(fio_slin2ulaw)
+{
+ int16_t sln_buf[512] = {0}, *sln = sln_buf;
+ uint8_t *lp = data;
+ uint32_t i;
+ ftdm_size_t len = *datalen;
+
+ if (max > len) {
+ max = len;
+ }
+
+ memcpy(sln, data, max);
+
+ for(i = 0; i < max; i++) {
+ *lp++ = linear_to_ulaw(*sln++);
+ }
+
+ *datalen = max / 2;
+
+ return FTDM_SUCCESS;
+
+}
+
+
+FIO_CODEC_FUNCTION(fio_ulaw2slin)
+{
+ int16_t *sln = data;
+ uint8_t law[1024] = {0}, *lp = law;
+ uint32_t i;
+ ftdm_size_t len = *datalen;
+
+ if (max > len) {
+ max = len;
+ }
+
+ memcpy(law, data, max);
+
+ for(i = 0; i < max; i++) {
+ *sln++ = ulaw_to_linear(*lp++);
+ }
+
+ *datalen = max * 2;
+
+ return FTDM_SUCCESS;
+}
+
+FIO_CODEC_FUNCTION(fio_slin2alaw)
+{
+ int16_t sln_buf[512] = {0}, *sln = sln_buf;
+ uint8_t *lp = data;
+ uint32_t i;
+ ftdm_size_t len = *datalen;
+
+ if (max > len) {
+ max = len;
+ }
+
+ memcpy(sln, data, max);
+
+ for(i = 0; i < max; i++) {
+ *lp++ = linear_to_alaw(*sln++);
+ }
+
+ *datalen = max / 2;
+
+ return FTDM_SUCCESS;
+
+}
+
+
+FIO_CODEC_FUNCTION(fio_alaw2slin)
+{
+ int16_t *sln = data;
+ uint8_t law[1024] = {0}, *lp = law;
+ uint32_t i;
+ ftdm_size_t len = *datalen;
+
+ if (max > len) {
+ max = len;
+ }
+
+ memcpy(law, data, max);
+
+ for(i = 0; i < max; i++) {
+ *sln++ = alaw_to_linear(*lp++);
+ }
+
+ *datalen = max * 2;
+
+ return FTDM_SUCCESS;
+}
+
+FIO_CODEC_FUNCTION(fio_ulaw2alaw)
+{
+ ftdm_size_t len = *datalen;
+ uint32_t i;
+ uint8_t *lp = data;
+
+ if (max > len) {
+ max = len;
+ }
+
+ for(i = 0; i < max; i++) {
+ *lp = ulaw_to_alaw(*lp);
+ lp++;
+ }
+
+ return FTDM_SUCCESS;
+}
+
+FIO_CODEC_FUNCTION(fio_alaw2ulaw)
+{
+ ftdm_size_t len = *datalen;
+ uint32_t i;
+ uint8_t *lp = data;
+
+ if (max > len) {
+ max = len;
+ }
+
+ for(i = 0; i < max; i++) {
+ *lp = alaw_to_ulaw(*lp);
+ lp++;
+ }
+
+ return FTDM_SUCCESS;
+}
+
+/******************************/
+
+FT_DECLARE(void) ftdm_channel_clear_detected_tones(ftdm_channel_t *ftdmchan)
+{
+ uint32_t i;
+
+ memset(ftdmchan->detected_tones, 0, sizeof(ftdmchan->detected_tones[0]) * FTDM_TONEMAP_INVALID);
+
+ for (i = 1; i < FTDM_TONEMAP_INVALID; i++) {
+ ftdmchan->span->tone_finder[i].tone_count = 0;
+ }
+}
+
+FT_DECLARE(void) ftdm_channel_clear_needed_tones(ftdm_channel_t *ftdmchan)
+{
+ memset(ftdmchan->needed_tones, 0, sizeof(ftdmchan->needed_tones[0]) * FTDM_TONEMAP_INVALID);
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_channel_dequeue_dtmf(ftdm_channel_t *ftdmchan, char *dtmf, ftdm_size_t len)
+{
+ ftdm_size_t bytes = 0;
+
+ assert(ftdmchan != NULL);
+
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY)) {
+ return FTDM_FAIL;
+ }
+
+ if (ftdmchan->digit_buffer && ftdm_buffer_inuse(ftdmchan->digit_buffer)) {
+ ftdm_mutex_lock(ftdmchan->mutex);
+ if ((bytes = ftdm_buffer_read(ftdmchan->digit_buffer, dtmf, len)) > 0) {
+ *(dtmf + bytes) = '\0';
+ }
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ }
+
+ return bytes;
+}
+
+FT_DECLARE(void) ftdm_channel_flush_dtmf(ftdm_channel_t *ftdmchan)
+{
+ if (ftdmchan->digit_buffer && ftdm_buffer_inuse(ftdmchan->digit_buffer)) {
+ ftdm_mutex_lock(ftdmchan->mutex);
+ ftdm_buffer_zero(ftdmchan->digit_buffer);
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ }
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_queue_dtmf(ftdm_channel_t *ftdmchan, const char *dtmf)
+{
+ ftdm_status_t status;
+ register ftdm_size_t len, inuse;
+ ftdm_size_t wr = 0;
+ const char *p;
+
+ assert(ftdmchan != NULL);
+
+ if (ftdmchan->pre_buffer) {
+ ftdm_buffer_zero(ftdmchan->pre_buffer);
+ }
+
+ ftdm_mutex_lock(ftdmchan->mutex);
+
+ inuse = ftdm_buffer_inuse(ftdmchan->digit_buffer);
+ len = strlen(dtmf);
+
+ if (len + inuse > ftdm_buffer_len(ftdmchan->digit_buffer)) {
+ ftdm_buffer_toss(ftdmchan->digit_buffer, strlen(dtmf));
+ }
+
+ if (ftdmchan->span->dtmf_hangup_len) {
+ for (p = dtmf; ftdm_is_dtmf(*p); p++) {
+ memmove (ftdmchan->dtmf_hangup_buf, ftdmchan->dtmf_hangup_buf + 1, ftdmchan->span->dtmf_hangup_len - 1);
+ ftdmchan->dtmf_hangup_buf[ftdmchan->span->dtmf_hangup_len - 1] = *p;
+ if (!strcmp(ftdmchan->dtmf_hangup_buf, ftdmchan->span->dtmf_hangup)) {
+ ftdm_log(FTDM_LOG_DEBUG, "DTMF hangup detected.\n");
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ break;
+ }
+ }
+ }
+
+ p = dtmf;
+ while (wr < len && p) {
+ if (ftdm_is_dtmf(*p)) {
+ wr++;
+ } else {
+ break;
+ }
+ p++;
+ }
+
+ status = ftdm_buffer_write(ftdmchan->digit_buffer, dtmf, wr) ? FTDM_SUCCESS : FTDM_FAIL;
+ ftdm_mutex_unlock(ftdmchan->mutex);
+
+ return status;
+}
+
+
+static ftdm_status_t handle_dtmf(ftdm_channel_t *ftdmchan, ftdm_size_t datalen)
+{
+ ftdm_buffer_t *buffer = NULL;
+ ftdm_size_t dblen = 0;
+ int wrote = 0;
+
+ if (ftdmchan->gen_dtmf_buffer && (dblen = ftdm_buffer_inuse(ftdmchan->gen_dtmf_buffer))) {
+ char digits[128] = "";
+ char *cur;
+ int x = 0;
+
+ if (dblen > sizeof(digits) - 1) {
+ dblen = sizeof(digits) - 1;
+ }
+
+ if (ftdm_buffer_read(ftdmchan->gen_dtmf_buffer, digits, dblen) && !ftdm_strlen_zero_buf(digits)) {
+ ftdm_log(FTDM_LOG_DEBUG, "%d:%d GENERATE DTMF [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, digits);
+
+ cur = digits;
+
+ if (*cur == 'F') {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_FLASH, NULL);
+ cur++;
+ }
+
+ for (; *cur; cur++) {
+ if ((wrote = teletone_mux_tones(&ftdmchan->tone_session, &ftdmchan->tone_session.TONES[(int)*cur]))) {
+ ftdm_buffer_write(ftdmchan->dtmf_buffer, ftdmchan->tone_session.buffer, wrote * 2);
+ x++;
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "%d:%d Problem Adding DTMF SEQ [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, digits);
+ return FTDM_FAIL;
+ }
+ }
+
+ if (x) {
+ ftdmchan->skip_read_frames = (wrote / (ftdmchan->effective_interval * 8)) + 4;
+ }
+ }
+ }
+
+
+ if (!ftdmchan->buffer_delay || --ftdmchan->buffer_delay == 0) {
+ if (ftdmchan->dtmf_buffer && (dblen = ftdm_buffer_inuse(ftdmchan->dtmf_buffer))) {
+ buffer = ftdmchan->dtmf_buffer;
+ } else if (ftdmchan->fsk_buffer && (dblen = ftdm_buffer_inuse(ftdmchan->fsk_buffer))) {
+ buffer = ftdmchan->fsk_buffer;
+ }
+ }
+
+ if (buffer) {
+ ftdm_size_t dlen = datalen;
+ uint8_t auxbuf[1024];
+ ftdm_size_t len, br, max = sizeof(auxbuf);
+
+ if (ftdmchan->native_codec != FTDM_CODEC_SLIN) {
+ dlen *= 2;
+ }
+
+ len = dblen > dlen ? dlen : dblen;
+
+ br = ftdm_buffer_read(buffer, auxbuf, len);
+ if (br < dlen) {
+ memset(auxbuf + br, 0, dlen - br);
+ }
+
+ if (ftdmchan->native_codec != FTDM_CODEC_SLIN) {
+ if (ftdmchan->native_codec == FTDM_CODEC_ULAW) {
+ fio_slin2ulaw(auxbuf, max, &dlen);
+ } else if (ftdmchan->native_codec == FTDM_CODEC_ALAW) {
+ fio_slin2alaw(auxbuf, max, &dlen);
+ }
+ }
+
+ return ftdmchan->fio->write(ftdmchan, auxbuf, &dlen);
+ }
+
+ return FTDM_SUCCESS;
+
+}
+
+
+FT_DECLARE(void) ftdm_generate_sln_silence(int16_t *data, uint32_t samples, uint32_t divisor)
+{
+ int16_t x;
+ uint32_t i;
+ int sum_rnd = 0;
+ int16_t rnd2 = (int16_t) ftdm_current_time_in_ms() * (int16_t) (intptr_t) data;
+
+ assert(divisor);
+
+ for (i = 0; i < samples; i++, sum_rnd = 0) {
+ for (x = 0; x < 6; x++) {
+ rnd2 = rnd2 * 31821U + 13849U;
+ sum_rnd += rnd2 ;
+ }
+ //switch_normalize_to_16bit(sum_rnd);
+ *data = (int16_t) ((int16_t) sum_rnd / (int) divisor);
+
+ data++;
+ }
+}
+
+
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t *datalen)
+{
+ ftdm_status_t status = FTDM_FAIL;
+ fio_codec_t codec_func = NULL;
+ ftdm_size_t max = *datalen;
+ unsigned i = 0;
+
+ ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "ftdmchan is null\n");
+ ftdm_assert_return(ftdmchan->fio != NULL, FTDM_FAIL, "No I/O module attached to ftdmchan\n");
+
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "channel not open");
+ return FTDM_FAIL;
+ }
+
+ if (!ftdmchan->fio->read) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "method not implemented");
+ return FTDM_FAIL;
+ }
+
+ status = ftdmchan->fio->read(ftdmchan, data, datalen);
+ if (ftdmchan->fds[0] > -1) {
+ int dlen = (int) *datalen;
+ if (write(ftdmchan->fds[0], data, dlen) != dlen) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "file write error!");
+ return FTDM_FAIL;
+ }
+ }
+
+ if (status == FTDM_SUCCESS) {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_USE_RX_GAIN)
+ && (ftdmchan->native_codec == FTDM_CODEC_ALAW || ftdmchan->native_codec == FTDM_CODEC_ULAW)) {
+ unsigned char *rdata = data;
+ for (i = 0; i < *datalen; i++) {
+ rdata[i] = ftdmchan->rxgain_table[rdata[i]];
+ }
+ }
+ handle_dtmf(ftdmchan, *datalen);
+ }
+
+ if (status == FTDM_SUCCESS && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE) && ftdmchan->effective_codec != ftdmchan->native_codec) {
+ if (ftdmchan->native_codec == FTDM_CODEC_ULAW && ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+ codec_func = fio_ulaw2slin;
+ } else if (ftdmchan->native_codec == FTDM_CODEC_ULAW && ftdmchan->effective_codec == FTDM_CODEC_ALAW) {
+ codec_func = fio_ulaw2alaw;
+ } else if (ftdmchan->native_codec == FTDM_CODEC_ALAW && ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+ codec_func = fio_alaw2slin;
+ } else if (ftdmchan->native_codec == FTDM_CODEC_ALAW && ftdmchan->effective_codec == FTDM_CODEC_ULAW) {
+ codec_func = fio_alaw2ulaw;
+ }
+
+ if (codec_func) {
+ status = codec_func(data, max, datalen);
+ } else {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "codec error!");
+ status = FTDM_FAIL;
+ }
+ }
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS_DETECT) ||
+ ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT)) {
+ uint8_t sln_buf[1024] = {0};
+ int16_t *sln;
+ ftdm_size_t slen = 0;
+ char digit_str[80] = "";
+
+ if (ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+ sln = data;
+ slen = *datalen / 2;
+ } else {
+ ftdm_size_t len = *datalen;
+ uint32_t i;
+ uint8_t *lp = data;
+
+ slen = sizeof(sln_buf) / 2;
+ if (len > slen) {
+ len = slen;
+ }
+
+ sln = (int16_t *) sln_buf;
+ for(i = 0; i < len; i++) {
+ if (ftdmchan->effective_codec == FTDM_CODEC_ULAW) {
+ *sln++ = ulaw_to_linear(*lp++);
+ } else if (ftdmchan->effective_codec == FTDM_CODEC_ALAW) {
+ *sln++ = alaw_to_linear(*lp++);
+ } else {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "codec error!");
+ return FTDM_FAIL;
+ }
+ }
+ sln = (int16_t *) sln_buf;
+ slen = len;
+ }
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT)) {
+ if (ftdm_fsk_demod_feed(&ftdmchan->fsk, sln, slen) != FTDM_SUCCESS) {
+ ftdm_size_t type, mlen;
+ char str[128], *sp;
+
+ while(ftdm_fsk_data_parse(&ftdmchan->fsk, &type, &sp, &mlen) == FTDM_SUCCESS) {
+ *(str+mlen) = '\0';
+ ftdm_copy_string(str, sp, ++mlen);
+ ftdm_clean_string(str);
+ ftdm_log(FTDM_LOG_DEBUG, "FSK: TYPE %s LEN %d VAL [%s]\n", ftdm_mdmf_type2str(type), mlen-1, str);
+
+ switch(type) {
+ case MDMF_DDN:
+ case MDMF_PHONE_NUM:
+ {
+ if (mlen > sizeof(ftdmchan->caller_data.ani)) {
+ mlen = sizeof(ftdmchan->caller_data.ani);
+ }
+ ftdm_set_string(ftdmchan->caller_data.ani.digits, str);
+ ftdm_set_string(ftdmchan->caller_data.cid_num.digits, ftdmchan->caller_data.ani.digits);
+ }
+ break;
+ case MDMF_NO_NUM:
+ {
+ ftdm_set_string(ftdmchan->caller_data.ani.digits, *str == 'P' ? "private" : "unknown");
+ ftdm_set_string(ftdmchan->caller_data.cid_name, ftdmchan->caller_data.ani.digits);
+ }
+ break;
+ case MDMF_PHONE_NAME:
+ {
+ if (mlen > sizeof(ftdmchan->caller_data.cid_name)) {
+ mlen = sizeof(ftdmchan->caller_data.cid_name);
+ }
+ ftdm_set_string(ftdmchan->caller_data.cid_name, str);
+ }
+ break;
+ case MDMF_NO_NAME:
+ {
+ ftdm_set_string(ftdmchan->caller_data.cid_name, *str == 'P' ? "private" : "unknown");
+ }
+ case MDMF_DATETIME:
+ {
+ if (mlen > sizeof(ftdmchan->caller_data.cid_date)) {
+ mlen = sizeof(ftdmchan->caller_data.cid_date);
+ }
+ ftdm_set_string(ftdmchan->caller_data.cid_date, str);
+ }
+ break;
+ }
+ }
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_CALLERID_DETECT, NULL);
+ }
+ }
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS_DETECT) && !ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_PROGRESS)) {
+ uint32_t i;
+
+ for (i = 1; i < FTDM_TONEMAP_INVALID; i++) {
+ if (ftdmchan->span->tone_finder[i].tone_count) {
+ if (ftdmchan->needed_tones[i] && teletone_multi_tone_detect(&ftdmchan->span->tone_finder[i], sln, (int)slen)) {
+ if (++ftdmchan->detected_tones[i]) {
+ ftdmchan->needed_tones[i] = 0;
+ ftdmchan->detected_tones[0]++;
+ }
+ }
+ }
+ }
+ }
+
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT) && !ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_DETECT)) {
+ teletone_dtmf_detect(&ftdmchan->dtmf_detect, sln, (int)slen);
+ teletone_dtmf_get(&ftdmchan->dtmf_detect, digit_str, sizeof(digit_str));
+
+ if(*digit_str) {
+ fio_event_cb_t event_callback = NULL;
+
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_CALLWAITING && (*digit_str == 'D' || *digit_str == 'A')) {
+ ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]++;
+ } else {
+ ftdm_channel_queue_dtmf(ftdmchan, digit_str);
+
+ if (ftdmchan->span->event_callback) {
+ event_callback = ftdmchan->span->event_callback;
+ } else if (ftdmchan->event_callback) {
+ event_callback = ftdmchan->event_callback;
+ }
+
+ if (event_callback) {
+ ftdmchan->event_header.channel = ftdmchan;
+ ftdmchan->event_header.e_type = FTDM_EVENT_DTMF;
+ ftdmchan->event_header.data = digit_str;
+ event_callback(ftdmchan, &ftdmchan->event_header);
+ ftdmchan->event_header.e_type = FTDM_EVENT_NONE;
+ ftdmchan->event_header.data = NULL;
+ }
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF)) {
+ ftdmchan->skip_read_frames = 20;
+ }
+ }
+ }
+ }
+ }
+
+ if (ftdmchan->skip_read_frames > 0 || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MUTE)) {
+
+ ftdm_mutex_lock(ftdmchan->pre_buffer_mutex);
+ if (ftdmchan->pre_buffer && ftdm_buffer_inuse(ftdmchan->pre_buffer)) {
+ ftdm_buffer_zero(ftdmchan->pre_buffer);
+ }
+ ftdm_mutex_unlock(ftdmchan->pre_buffer_mutex);
+
+
+ memset(data, 255, *datalen);
+
+ if (ftdmchan->skip_read_frames > 0) {
+ ftdmchan->skip_read_frames--;
+ }
+ } else {
+ ftdm_mutex_lock(ftdmchan->pre_buffer_mutex);
+ if (ftdmchan->pre_buffer_size && ftdmchan->pre_buffer) {
+ ftdm_buffer_write(ftdmchan->pre_buffer, data, *datalen);
+ if (ftdm_buffer_inuse(ftdmchan->pre_buffer) >= ftdmchan->pre_buffer_size) {
+ ftdm_buffer_read(ftdmchan->pre_buffer, data, *datalen);
+ } else {
+ memset(data, 255, *datalen);
+ }
+ }
+ ftdm_mutex_unlock(ftdmchan->pre_buffer_mutex);
+ }
+
+
+ return status;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_write(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t datasize, ftdm_size_t *datalen)
+{
+ ftdm_status_t status = FTDM_FAIL;
+ fio_codec_t codec_func = NULL;
+ ftdm_size_t max = datasize;
+ unsigned int i = 0;
+
+ assert(ftdmchan != NULL);
+ assert(ftdmchan->fio != NULL);
+
+ if (!ftdmchan->buffer_delay &&
+ ((ftdmchan->dtmf_buffer && ftdm_buffer_inuse(ftdmchan->dtmf_buffer)) ||
+ (ftdmchan->fsk_buffer && ftdm_buffer_inuse(ftdmchan->fsk_buffer)))) {
+ /* read size writing DTMF ATM */
+ return FTDM_SUCCESS;
+ }
+
+
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "channel not open");
+ return FTDM_FAIL;
+ }
+
+ if (!ftdmchan->fio->write) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "method not implemented");
+ return FTDM_FAIL;
+ }
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE) && ftdmchan->effective_codec != ftdmchan->native_codec) {
+ if (ftdmchan->native_codec == FTDM_CODEC_ULAW && ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+ codec_func = fio_slin2ulaw;
+ } else if (ftdmchan->native_codec == FTDM_CODEC_ULAW && ftdmchan->effective_codec == FTDM_CODEC_ALAW) {
+ codec_func = fio_alaw2ulaw;
+ } else if (ftdmchan->native_codec == FTDM_CODEC_ALAW && ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+ codec_func = fio_slin2alaw;
+ } else if (ftdmchan->native_codec == FTDM_CODEC_ALAW && ftdmchan->effective_codec == FTDM_CODEC_ULAW) {
+ codec_func = fio_ulaw2alaw;
+ }
+
+ if (codec_func) {
+ status = codec_func(data, max, datalen);
+ } else {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "codec error!");
+ status = FTDM_FAIL;
+ }
+ }
+
+ if (ftdmchan->fds[1] > -1) {
+ int dlen = (int) *datalen;
+ if ((write(ftdmchan->fds[1], data, dlen)) != dlen) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "file write error!");
+ return FTDM_FAIL;
+ }
+ }
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_USE_TX_GAIN)
+ && (ftdmchan->native_codec == FTDM_CODEC_ALAW || ftdmchan->native_codec == FTDM_CODEC_ULAW)) {
+ unsigned char *wdata = data;
+ for (i = 0; i < *datalen; i++) {
+ wdata[i] = ftdmchan->txgain_table[wdata[i]];
+ }
+ }
+ status = ftdmchan->fio->write(ftdmchan, data, datalen);
+
+ return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_clear_vars(ftdm_channel_t *ftdmchan)
+{
+ if(ftdmchan->variable_hash) {
+ hashtable_destroy(ftdmchan->variable_hash);
+ }
+ ftdmchan->variable_hash = create_hashtable(16, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+
+ if(!ftdmchan->variable_hash)
+ return FTDM_FAIL;
+
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_add_var(ftdm_channel_t *ftdmchan, const char *var_name, const char *value)
+{
+ char *t_name = 0, *t_val = 0;
+
+ if(!ftdmchan->variable_hash || !var_name || !value)
+ {
+ return FTDM_FAIL;
+ }
+
+ t_name = ftdm_strdup(var_name);
+ t_val = ftdm_strdup(value);
+
+ if(hashtable_insert(ftdmchan->variable_hash, t_name, t_val, HASHTABLE_FLAG_FREE_KEY | HASHTABLE_FLAG_FREE_VALUE)) {
+ return FTDM_SUCCESS;
+ }
+ return FTDM_FAIL;
+}
+
+FT_DECLARE(const char *) ftdm_channel_get_var(ftdm_channel_t *ftdmchan, const char *var_name)
+{
+ if(!ftdmchan->variable_hash || !var_name)
+ {
+ return NULL;
+ }
+ return (const char *) hashtable_search(ftdmchan->variable_hash, (void *)var_name);
+}
+
+static struct {
+ ftdm_io_interface_t *pika_interface;
+} interfaces;
+
+
+FT_DECLARE(char *) ftdm_api_execute(const char *type, const char *cmd)
+{
+ ftdm_io_interface_t *fio = NULL;
+ char *dup = NULL, *p;
+ char *rval = NULL;
+
+ if (type && !cmd) {
+ dup = ftdm_strdup(type);
+ if ((p = strchr(dup, ' '))) {
+ *p++ = '\0';
+ cmd = p;
+ }
+
+ type = dup;
+ }
+
+ ftdm_mutex_lock(globals.mutex);
+ if (!(fio = (ftdm_io_interface_t *) hashtable_search(globals.interface_hash, (void *)type))) {
+ ftdm_load_module_assume(type);
+ if ((fio = (ftdm_io_interface_t *) hashtable_search(globals.interface_hash, (void *)type))) {
+ ftdm_log(FTDM_LOG_INFO, "auto-loaded '%s'\n", type);
+ }
+ }
+ ftdm_mutex_unlock(globals.mutex);
+
+ if (fio && fio->api) {
+ ftdm_stream_handle_t stream = { 0 };
+ ftdm_status_t status;
+ FTDM_STANDARD_STREAM(stream);
+ status = fio->api(&stream, cmd);
+
+ if (status != FTDM_SUCCESS) {
+ ftdm_safe_free(stream.data);
+ } else {
+ rval = (char *) stream.data;
+ }
+ }
+
+ ftdm_safe_free(dup);
+
+ return rval;
+}
+
+
+static ftdm_status_t ftdm_group_add_channels(const char* name, ftdm_span_t* span, int currindex);
+static ftdm_status_t load_config(void)
+{
+ char cfg_name[] = "freetdm.conf";
+ ftdm_config_t cfg;
+ char *var, *val;
+ int catno = -1;
+ int currindex = 0;
+ ftdm_span_t *span = NULL;
+ unsigned configured = 0, d = 0;
+ char name[80] = "";
+ char number[25] = "";
+ char group_name[80] = "default";
+ ftdm_io_interface_t *fio = NULL;
+ ftdm_analog_start_type_t tmp;
+ ftdm_size_t len = 0;
+
+ if (!ftdm_config_open_file(&cfg, cfg_name)) {
+ return FTDM_FAIL;
+ }
+
+ while (ftdm_config_next_pair(&cfg, &var, &val)) {
+ if (*cfg.category == '#') {
+ if (cfg.catno != catno) {
+ ftdm_log(FTDM_LOG_DEBUG, "Skipping %s\n", cfg.category);
+ catno = cfg.catno;
+ }
+ } else if (!strncasecmp(cfg.category, "span", 4)) {
+ if (cfg.catno != catno) {
+ char *type = cfg.category + 4;
+ char *name;
+
+ if (*type == ' ') {
+ type++;
+ }
+
+ ftdm_log(FTDM_LOG_DEBUG, "found config for span\n");
+ catno = cfg.catno;
+
+ if (ftdm_strlen_zero(type)) {
+ ftdm_log(FTDM_LOG_CRIT, "failure creating span, no type specified.\n");
+ span = NULL;
+ continue;
+ }
+
+ if ((name = strchr(type, ' '))) {
+ *name++ = '\0';
+ }
+
+ ftdm_mutex_lock(globals.mutex);
+ if (!(fio = (ftdm_io_interface_t *) hashtable_search(globals.interface_hash, type))) {
+ ftdm_load_module_assume(type);
+ if ((fio = (ftdm_io_interface_t *) hashtable_search(globals.interface_hash, type))) {
+ ftdm_log(FTDM_LOG_INFO, "auto-loaded '%s'\n", type);
+ }
+ }
+ ftdm_mutex_unlock(globals.mutex);
+
+ if (!fio) {
+ ftdm_log(FTDM_LOG_CRIT, "failure creating span, no such type '%s'\n", type);
+ span = NULL;
+ continue;
+ }
+
+ if (!fio->configure_span) {
+ ftdm_log(FTDM_LOG_CRIT, "failure creating span, no configure_span method for '%s'\n", type);
+ span = NULL;
+ continue;
+ }
+
+ if (ftdm_span_create(fio, &span, name) == FTDM_SUCCESS) {
+ span->type = ftdm_strdup(type);
+ d = 0;
+
+ ftdm_log(FTDM_LOG_DEBUG, "created span %d (%s) of type %s\n", span->span_id, span->name, type);
+
+ } else {
+ ftdm_log(FTDM_LOG_CRIT, "failure creating span of type %s\n", type);
+ span = NULL;
+ continue;
+ }
+ }
+
+ if (!span) {
+ continue;
+ }
+
+ ftdm_log(FTDM_LOG_DEBUG, "span %d [%s]=[%s]\n", span->span_id, var, val);
+
+ if (!strcasecmp(var, "trunk_type")) {
+ span->trunk_type = ftdm_str2ftdm_trunk_type(val);
+ ftdm_log(FTDM_LOG_DEBUG, "setting trunk type to '%s'\n", ftdm_trunk_type2str(span->trunk_type));
+ } else if (!strcasecmp(var, "name")) {
+ if (!strcasecmp(val, "undef")) {
+ *name = '\0';
+ } else {
+ ftdm_copy_string(name, val, sizeof(name));
+ }
+ } else if (!strcasecmp(var, "number")) {
+ if (!strcasecmp(val, "undef")) {
+ *number = '\0';
+ } else {
+ ftdm_copy_string(number, val, sizeof(number));
+ }
+ } else if (!strcasecmp(var, "analog-start-type")) {
+ if (span->trunk_type == FTDM_TRUNK_FXS || span->trunk_type == FTDM_TRUNK_FXO || span->trunk_type == FTDM_TRUNK_EM) {
+ if ((tmp = ftdm_str2ftdm_analog_start_type(val)) != FTDM_ANALOG_START_NA) {
+ span->start_type = tmp;
+ ftdm_log(FTDM_LOG_DEBUG, "changing start type to '%s'\n", ftdm_analog_start_type2str(span->start_type));
+ }
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "This option is only valid on analog trunks!\n");
+ }
+ } else if (!strcasecmp(var, "fxo-channel")) {
+ if (span->trunk_type == FTDM_TRUNK_NONE) {
+ span->trunk_type = FTDM_TRUNK_FXO;
+ ftdm_log(FTDM_LOG_DEBUG, "setting trunk type to '%s' start(%s)\n", ftdm_trunk_type2str(span->trunk_type),
+ ftdm_analog_start_type2str(span->start_type));
+ }
+ if (span->trunk_type == FTDM_TRUNK_FXO) {
+ currindex = span->chan_count;
+ configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_FXO, name, number);
+ ftdm_group_add_channels(group_name, span, currindex);
+ } else {
+ ftdm_log(FTDM_LOG_WARNING, "Cannot add FXO channels to an FXS trunk!\n");
+ }
+ } else if (!strcasecmp(var, "fxs-channel")) {
+ if (span->trunk_type == FTDM_TRUNK_NONE) {
+ span->trunk_type = FTDM_TRUNK_FXS;
+ ftdm_log(FTDM_LOG_DEBUG, "setting trunk type to '%s' start(%s)\n", ftdm_trunk_type2str(span->trunk_type),
+ ftdm_analog_start_type2str(span->start_type));
+ }
+ if (span->trunk_type == FTDM_TRUNK_FXS) {
+ currindex = span->chan_count;
+ configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_FXS, name, number);
+ ftdm_group_add_channels(group_name, span, currindex);
+ } else {
+ ftdm_log(FTDM_LOG_WARNING, "Cannot add FXS channels to an FXO trunk!\n");
+ }
+ } else if (!strcasecmp(var, "em-channel")) {
+ if (span->trunk_type == FTDM_TRUNK_NONE) {
+ span->trunk_type = FTDM_TRUNK_EM;
+ ftdm_log(FTDM_LOG_DEBUG, "setting trunk type to '%s' start(%s)\n", ftdm_trunk_type2str(span->trunk_type),
+ ftdm_analog_start_type2str(span->start_type));
+ }
+ if (span->trunk_type == FTDM_TRUNK_EM) {
+ currindex = span->chan_count;
+ configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_EM, name, number);
+ ftdm_group_add_channels(group_name, span, currindex);
+ } else {
+ ftdm_log(FTDM_LOG_WARNING, "Cannot add EM channels to a non-EM trunk!\n");
+ }
+ } else if (!strcasecmp(var, "b-channel")) {
+ currindex = span->chan_count;
+ configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_B, name, number);
+ ftdm_group_add_channels(group_name, span, currindex);
+ } else if (!strcasecmp(var, "d-channel")) {
+ if (d) {
+ ftdm_log(FTDM_LOG_WARNING, "ignoring extra d-channel\n");
+ } else {
+ ftdm_chan_type_t qtype;
+ if (!strncasecmp(val, "lapd:", 5)) {
+ qtype = FTDM_CHAN_TYPE_DQ931;
+ val += 5;
+ } else {
+ qtype = FTDM_CHAN_TYPE_DQ921;
+ }
+ configured += fio->configure_span(span, val, qtype, name, number);
+ d++;
+ }
+ } else if (!strcasecmp(var, "cas-channel")) {
+ currindex = span->chan_count;
+ configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_CAS, name, number);
+ ftdm_group_add_channels(group_name, span, currindex);
+ } else if (!strcasecmp(var, "dtmf_hangup")) {
+ span->dtmf_hangup = ftdm_strdup(val);
+ span->dtmf_hangup_len = strlen(val);
+ } else if (!strcasecmp(var, "group")) {
+ len = strlen(val);
+ if (len >= sizeof(group_name)) {
+ len = sizeof(group_name) - 1;
+ ftdm_log(FTDM_LOG_WARNING, "Truncating group name %s to %zd length\n", val, len);
+ }
+ memcpy(group_name, val, len);
+ group_name[len] = '\0';
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "unknown span variable '%s'\n", var);
+ }
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "unknown param [%s] '%s' / '%s'\n", cfg.category, var, val);
+ }
+ }
+ ftdm_config_close_file(&cfg);
+
+ ftdm_log(FTDM_LOG_INFO, "Configured %u channel(s)\n", configured);
+
+ return configured ? FTDM_SUCCESS : FTDM_FAIL;
+}
+
+static ftdm_status_t process_module_config(ftdm_io_interface_t *fio)
+{
+ ftdm_config_t cfg;
+ char *var, *val;
+ char filename[256] = "";
+
+ ftdm_assert_return(fio != NULL, FTDM_FAIL, "fio argument is null\n");
+
+ snprintf(filename, sizeof(filename), "%s.conf", fio->name);
+
+ if (!fio->configure) {
+ ftdm_log(FTDM_LOG_DEBUG, "Module %s does not support configuration.\n", fio->name);
+ return FTDM_FAIL;
+ }
+
+ if (!ftdm_config_open_file(&cfg, filename)) {
+ ftdm_log(FTDM_LOG_ERROR, "Cannot open %s\n", filename);
+ return FTDM_FAIL;
+ }
+
+ while (ftdm_config_next_pair(&cfg, &var, &val)) {
+ fio->configure(cfg.category, var, val, cfg.lineno);
+ }
+
+ ftdm_config_close_file(&cfg);
+
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(char *) ftdm_build_dso_path(const char *name, char *path, ftdm_size_t len)
+{
+#ifdef WIN32
+ const char *ext = ".dll";
+ //const char *EXT = ".DLL";
+#define FTDM_MOD_DIR "." //todo
+#elif defined (MACOSX) || defined (DARWIN)
+ const char *ext = ".dylib";
+ //const char *EXT = ".DYLIB";
+#else
+ const char *ext = ".so";
+ //const char *EXT = ".SO";
+#endif
+ if (*name == *FTDM_PATH_SEPARATOR) {
+ snprintf(path, len, "%s%s", name, ext);
+ } else {
+ snprintf(path, len, "%s%s%s%s", FTDM_MOD_DIR, FTDM_PATH_SEPARATOR, name, ext);
+ }
+ return path;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_global_add_io_interface(ftdm_io_interface_t *interface1)
+{
+ ftdm_status_t ret = FTDM_SUCCESS;
+ ftdm_mutex_lock(globals.mutex);
+ if (hashtable_search(globals.interface_hash, (void *)interface1->name)) {
+ ftdm_log(FTDM_LOG_ERROR, "Interface %s already loaded!\n", interface1->name);
+ } else {
+ hashtable_insert(globals.interface_hash, (void *)interface1->name, interface1, HASHTABLE_FLAG_NONE);
+ }
+ ftdm_mutex_unlock(globals.mutex);
+ return ret;
+}
+
+FT_DECLARE(int) ftdm_load_module(const char *name)
+{
+ ftdm_dso_lib_t lib;
+ int count = 0, x = 0;
+ char path[128] = "";
+ char *err;
+ ftdm_module_t *mod;
+
+ ftdm_build_dso_path(name, path, sizeof(path));
+
+ if (!(lib = ftdm_dso_open(path, &err))) {
+ ftdm_log(FTDM_LOG_ERROR, "Error loading %s [%s]\n", path, err);
+ ftdm_safe_free(err);
+ return 0;
+ }
+
+ if (!(mod = (ftdm_module_t *) ftdm_dso_func_sym(lib, "ftdm_module", &err))) {
+ ftdm_log(FTDM_LOG_ERROR, "Error loading %s [%s]\n", path, err);
+ ftdm_safe_free(err);
+ return 0;
+ }
+
+ if (mod->io_load) {
+ ftdm_io_interface_t *interface1 = NULL; /* name conflict w/windows here */
+
+ if (mod->io_load(&interface1) != FTDM_SUCCESS || !interface1 || !interface1->name) {
+ ftdm_log(FTDM_LOG_ERROR, "Error loading %s\n", path);
+ } else {
+ ftdm_log(FTDM_LOG_INFO, "Loading IO from %s [%s]\n", path, interface1->name);
+ if (ftdm_global_add_io_interface(interface1) == FTDM_SUCCESS) {
+ process_module_config(interface1);
+ x++;
+ }
+ }
+ }
+
+ if (mod->sig_load) {
+ if (mod->sig_load() != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error loading %s\n", path);
+ } else {
+ ftdm_log(FTDM_LOG_INFO, "Loading SIG from %s\n", path);
+ x++;
+ }
+ }
+
+ if (x) {
+ char *p;
+ mod->lib = lib;
+ ftdm_set_string(mod->path, path);
+ if (mod->name[0] == '\0') {
+ if (!(p = strrchr(path, *FTDM_PATH_SEPARATOR))) {
+ p = path;
+ }
+ ftdm_set_string(mod->name, p);
+ }
+
+ ftdm_mutex_lock(globals.mutex);
+ if (hashtable_search(globals.module_hash, (void *)mod->name)) {
+ ftdm_log(FTDM_LOG_ERROR, "Module %s already loaded!\n", mod->name);
+ ftdm_dso_destroy(&lib);
+ } else {
+ hashtable_insert(globals.module_hash, (void *)mod->name, mod, HASHTABLE_FLAG_NONE);
+ count++;
+ }
+ ftdm_mutex_unlock(globals.mutex);
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "Unloading %s\n", path);
+ ftdm_dso_destroy(&lib);
+ }
+
+ return count;
+}
+
+FT_DECLARE(int) ftdm_load_module_assume(const char *name)
+{
+ char buf[256] = "";
+
+ snprintf(buf, sizeof(buf), "ftmod_%s", name);
+ return ftdm_load_module(buf);
+}
+
+FT_DECLARE(int) ftdm_load_modules(void)
+{
+ char cfg_name[] = "modules.conf";
+ ftdm_config_t cfg;
+ char *var, *val;
+ int count = 0;
+
+ if (!ftdm_config_open_file(&cfg, cfg_name)) {
+ return FTDM_FAIL;
+ }
+
+ while (ftdm_config_next_pair(&cfg, &var, &val)) {
+ if (!strcasecmp(cfg.category, "modules")) {
+ if (!strcasecmp(var, "load")) {
+ count += ftdm_load_module(val);
+ }
+ }
+ }
+
+ return count;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_unload_modules(void)
+{
+ ftdm_hash_iterator_t *i = NULL;
+ ftdm_dso_lib_t lib = NULL;
+ char modpath[255] = { 0 };
+
+ /* stop signaling interfaces first as signaling depends on I/O and not the other way around */
+ for (i = hashtable_first(globals.module_hash); i; i = hashtable_next(i)) {
+ const void *key = NULL;
+ void *val = NULL;
+ ftdm_module_t *mod = NULL;
+
+ hashtable_this(i, &key, NULL, &val);
+
+ if (!key || !val) {
+ continue;
+ }
+
+ mod = (ftdm_module_t *) val;
+
+ if (!mod->sig_unload) {
+ continue;
+ }
+
+ ftdm_log(FTDM_LOG_INFO, "Unloading signaling interface %s\n", mod->name);
+
+ if (mod->sig_unload() != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error unloading signaling interface %s\n", mod->name);
+ continue;
+ }
+
+ ftdm_log(FTDM_LOG_INFO, "Unloaded signaling interface %s\n", mod->name);
+ }
+
+ /* Now go ahead with I/O interfaces */
+ for (i = hashtable_first(globals.module_hash); i; i = hashtable_next(i)) {
+ const void *key = NULL;
+ void *val = NULL;
+ ftdm_module_t *mod = NULL;
+
+ hashtable_this(i, &key, NULL, &val);
+
+ if (!key || !val) {
+ continue;
+ }
+
+ mod = (ftdm_module_t *) val;
+
+ if (!mod->io_unload) {
+ continue;
+ }
+
+ ftdm_log(FTDM_LOG_INFO, "Unloading I/O interface %s\n", mod->name);
+
+ if (mod->io_unload() != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error unloading I/O interface %s\n", mod->name);
+ continue;
+ }
+
+ ftdm_log(FTDM_LOG_INFO, "Unloaded I/O interface %s\n", mod->name);
+ }
+
+ /* Now unload the actual shared object/dll */
+ for (i = hashtable_first(globals.module_hash); i; i = hashtable_next(i)) {
+ ftdm_module_t *mod = NULL;
+ const void *key = NULL;
+ void *val = NULL;
+
+ hashtable_this(i, &key, NULL, &val);
+
+ if (!key || !val) {
+ continue;
+ }
+
+ mod = (ftdm_module_t *) val;
+
+ lib = mod->lib;
+ snprintf(modpath, sizeof(modpath), "%s", mod->path);
+ ftdm_log(FTDM_LOG_INFO, "Unloading module %s\n", modpath);
+ ftdm_dso_destroy(&lib);
+ ftdm_log(FTDM_LOG_INFO, "Unloaded module %s\n", modpath);
+ }
+
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_configure_span(const char *type, ftdm_span_t *span, fio_signal_cb_t sig_cb, ...)
+{
+ ftdm_module_t *mod = (ftdm_module_t *) hashtable_search(globals.module_hash, (void *)type);
+ ftdm_status_t status = FTDM_FAIL;
+
+ if (!mod) {
+ ftdm_load_module_assume(type);
+ if ((mod = (ftdm_module_t *) hashtable_search(globals.module_hash, (void *)type))) {
+ ftdm_log(FTDM_LOG_INFO, "auto-loaded '%s'\n", type);
+ }
+ }
+
+ if (mod && mod->sig_configure) {
+ va_list ap;
+ va_start(ap, sig_cb);
+ status = mod->sig_configure(span, sig_cb, ap);
+ va_end(ap);
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "can't find '%s'\n", type);
+ status = FTDM_FAIL;
+ }
+
+ return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_configure_span_signaling(const char *type, ftdm_span_t *span, fio_signal_cb_t sig_cb, ftdm_conf_parameter_t *parameters)
+{
+ ftdm_module_t *mod = (ftdm_module_t *) hashtable_search(globals.module_hash, (void *)type);
+ ftdm_status_t status = FTDM_FAIL;
+
+ ftdm_assert_return(type != NULL, FTDM_FAIL, "No signaling type");
+ ftdm_assert_return(span != NULL, FTDM_FAIL, "No span");
+ ftdm_assert_return(sig_cb != NULL, FTDM_FAIL, "No signaling callback");
+ ftdm_assert_return(parameters != NULL, FTDM_FAIL, "No parameters");
+
+ if (!mod) {
+ ftdm_load_module_assume(type);
+ if ((mod = (ftdm_module_t *) hashtable_search(globals.module_hash, (void *)type))) {
+ ftdm_log(FTDM_LOG_INFO, "auto-loaded '%s'\n", type);
+ }
+ }
+
+ if (!mod) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to load module type: %s\n", type);
+ return FTDM_FAIL;
+ }
+
+ if (mod->configure_span_signaling) {
+ status = mod->configure_span_signaling(span, sig_cb, parameters);
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "Module %s did not implement the signaling configuration method\n", type);
+ }
+
+ return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_start(ftdm_span_t *span)
+{
+ if (span->start) {
+ return span->start(span);
+ }
+
+ return FTDM_FAIL;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_add_to_group(const char* name, ftdm_channel_t* ftdmchan)
+{
+ unsigned int i;
+ ftdm_group_t* group = NULL;
+
+ ftdm_mutex_lock(globals.group_mutex);
+
+ ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "Cannot add a null channel to a group\n");
+
+ if (ftdm_group_find_by_name(name, &group) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_DEBUG, "Creating new group:%s\n", name);
+ ftdm_group_create(&group, name);
+ }
+
+ /*verify that group does not already include this channel first */
+ for(i = 0; i < group->chan_count; i++) {
+ if (group->channels[i]->physical_span_id == ftdmchan->physical_span_id &&
+ group->channels[i]->physical_chan_id == ftdmchan->physical_chan_id) {
+
+ ftdm_mutex_unlock(globals.group_mutex);
+ ftdm_log(FTDM_LOG_DEBUG, "Channel %d:%d is already added to group %s\n",
+ group->channels[i]->physical_span_id,
+ group->channels[i]->physical_chan_id,
+ name);
+ return FTDM_SUCCESS;
+ }
+ }
+
+ if (group->chan_count >= FTDM_MAX_CHANNELS_GROUP) {
+ ftdm_log(FTDM_LOG_ERROR, "Max number of channels exceeded (max:%d)\n", FTDM_MAX_CHANNELS_GROUP);
+ ftdm_mutex_unlock(globals.group_mutex);
+ return FTDM_FAIL;
+ }
+
+ group->channels[group->chan_count++] = ftdmchan;
+ ftdm_mutex_unlock(globals.group_mutex);
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_remove_from_group(ftdm_group_t* group, ftdm_channel_t* ftdmchan)
+{
+ unsigned int i, j;
+ //Need to test this function
+ ftdm_mutex_lock(globals.group_mutex);
+
+ for (i=0; i < group->chan_count; i++) {
+ if (group->channels[i]->physical_span_id == ftdmchan->physical_span_id &&
+ group->channels[i]->physical_chan_id == ftdmchan->physical_chan_id) {
+
+ j=i;
+ while(j < group->chan_count-1) {
+ group->channels[j] = group->channels[j+1];
+ j++;
+ }
+ group->channels[group->chan_count--] = NULL;
+ if (group->chan_count <=0) {
+ /* Delete group if it is empty */
+ hashtable_remove(globals.group_hash, (void *)group->name);
+ }
+ ftdm_mutex_unlock(globals.group_mutex);
+ return FTDM_SUCCESS;
+ }
+ }
+
+ ftdm_mutex_unlock(globals.group_mutex);
+ //Group does not contain this channel
+ return FTDM_FAIL;
+}
+
+static ftdm_status_t ftdm_group_add_channels(const char* name, ftdm_span_t* span, int currindex)
+{
+ unsigned chan_index = 0;
+
+ ftdm_assert_return(strlen(name) > 0, FTDM_FAIL, "Invalid group name provided\n");
+ ftdm_assert_return(currindex >= 0, FTDM_FAIL, "Invalid current channel index provided\n");
+
+ if (!span->chan_count) {
+ return FTDM_SUCCESS;
+ }
+
+ for (chan_index = currindex+1; chan_index <= span->chan_count; chan_index++) {
+ if (!FTDM_IS_VOICE_CHANNEL(span->channels[chan_index])) {
+ continue;
+ }
+ if (ftdm_channel_add_to_group(name, span->channels[chan_index])) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to add chan:%d to group:%s\n", chan_index, name);
+ }
+ }
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_group_find(uint32_t id, ftdm_group_t **group)
+{
+ ftdm_group_t *fgroup = NULL, *grp;
+
+ if (id > FTDM_MAX_GROUPS_INTERFACE) {
+ return FTDM_FAIL;
+ }
+
+
+ ftdm_mutex_lock(globals.group_mutex);
+ for (grp = globals.groups; grp; grp = grp->next) {
+ if (grp->group_id == id) {
+ fgroup = grp;
+ break;
+ }
+ }
+ ftdm_mutex_unlock(globals.group_mutex);
+
+ if (!fgroup) {
+ return FTDM_FAIL;
+ }
+
+ *group = fgroup;
+
+ return FTDM_SUCCESS;
+
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_group_find_by_name(const char *name, ftdm_group_t **group)
+{
+ ftdm_status_t status = FTDM_FAIL;
+ *group = NULL;
+ ftdm_mutex_lock(globals.group_mutex);
+ if (!ftdm_strlen_zero(name)) {
+ if ((*group = hashtable_search(globals.group_hash, (void *) name))) {
+ status = FTDM_SUCCESS;
+ }
+ }
+ ftdm_mutex_unlock(globals.group_mutex);
+ return status;
+}
+
+static void ftdm_group_add(ftdm_group_t *group)
+{
+ ftdm_group_t *grp;
+ ftdm_mutex_lock(globals.group_mutex);
+
+ for (grp = globals.groups; grp && grp->next; grp = grp->next);
+
+ if (grp) {
+ grp->next = group;
+ } else {
+ globals.groups = group;
+ }
+ hashtable_insert(globals.group_hash, (void *)group->name, group, HASHTABLE_FLAG_NONE);
+
+ ftdm_mutex_unlock(globals.group_mutex);
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_group_create(ftdm_group_t **group, const char *name)
+{
+ ftdm_group_t *new_group = NULL;
+ ftdm_status_t status = FTDM_FAIL;
+
+ ftdm_mutex_lock(globals.mutex);
+ if (globals.group_index < FTDM_MAX_GROUPS_INTERFACE) {
+ new_group = ftdm_calloc(1, sizeof(*new_group));
+
+ ftdm_assert(new_group != NULL, "Failed to create new ftdm group, expect a crash\n");
+
+ status = ftdm_mutex_create(&new_group->mutex);
+
+ ftdm_assert(status == FTDM_SUCCESS, "Failed to create group mutex, expect a crash\n");
+
+ new_group->group_id = ++globals.group_index;
+ new_group->name = ftdm_strdup(name);
+ ftdm_group_add(new_group);
+ *group = new_group;
+ status = FTDM_SUCCESS;
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "Group %s was not added, we exceeded the max number of groups\n", name);
+ }
+ ftdm_mutex_unlock(globals.mutex);
+ return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t *sigmsg)
+{
+ ftdm_status_t status = FTDM_FAIL;
+
+ if (span->signal_cb) {
+ if (sigmsg->channel) {
+ ftdm_mutex_lock(sigmsg->channel->mutex);
+ }
+
+ status = span->signal_cb(sigmsg);
+
+ if (sigmsg->channel) {
+ ftdm_mutex_unlock(sigmsg->channel->mutex);
+ }
+ }
+
+ return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_global_init(void)
+{
+ memset(&globals, 0, sizeof(globals));
+
+ time_init();
+
+ ftdm_thread_override_default_stacksize(FTDM_THREAD_STACKSIZE);
+
+ memset(&interfaces, 0, sizeof(interfaces));
+ globals.interface_hash = create_hashtable(16, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+ globals.module_hash = create_hashtable(16, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+ globals.span_hash = create_hashtable(16, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+ globals.group_hash = create_hashtable(16, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+ ftdm_mutex_create(&globals.mutex);
+ ftdm_mutex_create(&globals.span_mutex);
+ ftdm_mutex_create(&globals.group_mutex);
+ globals.running = 1;
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_global_configuration(void)
+{
+ int modcount = ftdm_load_modules();
+ ftdm_log(FTDM_LOG_NOTICE, "Modules configured: %d \n", modcount);
+
+ if (load_config() != FTDM_SUCCESS) {
+ globals.running = 0;
+ ftdm_log(FTDM_LOG_ERROR, "FreeTDM global configuration failed!\n");
+ return FTDM_FAIL;
+ }
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(uint32_t) ftdm_running(void)
+{
+ return globals.running;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void)
+{
+ ftdm_span_t *sp;
+
+ time_end();
+
+ globals.running = 0;
+
+ globals.span_index = 0;
+
+ ftdm_span_close_all();
+
+ ftdm_mutex_lock(globals.span_mutex);
+ for (sp = globals.spans; sp;) {
+ ftdm_span_t *cur_span = sp;
+ sp = sp->next;
+
+ if (cur_span) {
+ if (ftdm_test_flag(cur_span, FTDM_SPAN_CONFIGURED)) {
+ ftdm_span_destroy(cur_span);
+ }
+
+ hashtable_remove(globals.span_hash, (void *)cur_span->name);
+ ftdm_safe_free(cur_span->type);
+ ftdm_safe_free(cur_span->name);
+ ftdm_safe_free(cur_span);
+ cur_span = NULL;
+ }
+ }
+ globals.spans = NULL;
+ ftdm_mutex_unlock(globals.span_mutex);
+
+ ftdm_unload_modules();
+
+ ftdm_mutex_lock(globals.mutex);
+ hashtable_destroy(globals.interface_hash);
+ hashtable_destroy(globals.module_hash);
+ hashtable_destroy(globals.span_hash);
+ ftdm_mutex_unlock(globals.mutex);
+ ftdm_mutex_destroy(&globals.mutex);
+ ftdm_mutex_destroy(&globals.span_mutex);
+
+ memset(&globals, 0, sizeof(globals));
+ return FTDM_SUCCESS;
+}
+
+
+FT_DECLARE(uint32_t) ftdm_separate_string(char *buf, char delim, char **array, int arraylen)
+{
+ int argc;
+ char *ptr;
+ int quot = 0;
+ char qc = '\'';
+ int x;
+
+ if (!buf || !array || !arraylen) {
+ return 0;
+ }
+
+ memset(array, 0, arraylen * sizeof(*array));
+
+ ptr = buf;
+
+ for (argc = 0; *ptr && (argc < arraylen - 1); argc++) {
+ array[argc] = ptr;
+ for (; *ptr; ptr++) {
+ if (*ptr == qc) {
+ if (quot) {
+ quot--;
+ } else {
+ quot++;
+ }
+ } else if ((*ptr == delim) && !quot) {
+ *ptr++ = '\0';
+ break;
+ }
+ }
+ }
+
+ if (*ptr) {
+ array[argc++] = ptr;
+ }
+
+ /* strip quotes and leading / trailing spaces */
+ for (x = 0; x < argc; x++) {
+ char *p;
+
+ while(*(array[x]) == ' ') {
+ (array[x])++;
+ }
+ p = array[x];
+ while((p = strchr(array[x], qc))) {
+ memmove(p, p+1, strlen(p));
+ p++;
+ }
+ p = array[x] + (strlen(array[x]) - 1);
+ while(*p == ' ') {
+ *p-- = '\0';
+ }
+ }
+
+ return argc;
+}
+
+FT_DECLARE(void) ftdm_bitstream_init(ftdm_bitstream_t *bsp, uint8_t *data, uint32_t datalen, ftdm_endian_t endian, uint8_t ss)
+{
+ memset(bsp, 0, sizeof(*bsp));
+ bsp->data = data;
+ bsp->datalen = datalen;
+ bsp->endian = endian;
+ bsp->ss = ss;
+
+ if (endian < 0) {
+ bsp->top = bsp->bit_index = 7;
+ bsp->bot = 0;
+ } else {
+ bsp->top = bsp->bit_index = 0;
+ bsp->bot = 7;
+ }
+
+}
+
+FT_DECLARE(int8_t) ftdm_bitstream_get_bit(ftdm_bitstream_t *bsp)
+{
+ int8_t bit = -1;
+
+
+ if (bsp->byte_index >= bsp->datalen) {
+ goto done;
+ }
+
+ if (bsp->ss) {
+ if (!bsp->ssv) {
+ bsp->ssv = 1;
+ return 0;
+ } else if (bsp->ssv == 2) {
+ bsp->byte_index++;
+ bsp->ssv = 0;
+ return 1;
+ }
+ }
+
+
+
+
+ bit = (bsp->data[bsp->byte_index] >> (bsp->bit_index)) & 1;
+
+ if (bsp->bit_index == bsp->bot) {
+ bsp->bit_index = bsp->top;
+ if (bsp->ss) {
+ bsp->ssv = 2;
+ goto done;
+ }
+
+ if (++bsp->byte_index > bsp->datalen) {
+ bit = -1;
+ goto done;
+ }
+
+ } else {
+ bsp->bit_index = bsp->bit_index + bsp->endian;
+ }
+
+
+ done:
+ return bit;
+}
+
+FT_DECLARE(void) print_hex_bytes(uint8_t *data, ftdm_size_t dlen, char *buf, ftdm_size_t blen)
+{
+ char *bp = buf;
+ uint8_t *byte = data;
+ uint32_t i, j = 0;
+
+ if (blen < (dlen * 3) + 2) {
+ return;
+ }
+
+ *bp++ = '[';
+ j++;
+
+ for(i = 0; i < dlen; i++) {
+ snprintf(bp, blen-j, "%02x ", *byte++);
+ bp += 3;
+ j += 3;
+ }
+
+ *--bp = ']';
+
+}
+
+FT_DECLARE(void) print_bits(uint8_t *b, int bl, char *buf, int blen, ftdm_endian_t e, uint8_t ss)
+{
+ ftdm_bitstream_t bs;
+ int j = 0, c = 0;
+ int8_t bit;
+ uint32_t last;
+
+ if (blen < (bl * 10) + 2) {
+ return;
+ }
+
+ ftdm_bitstream_init(&bs, b, bl, e, ss);
+ last = bs.byte_index;
+ while((bit = ftdm_bitstream_get_bit(&bs)) > -1) {
+ buf[j++] = bit ? '1' : '0';
+ if (bs.byte_index != last) {
+ buf[j++] = ' ';
+ last = bs.byte_index;
+ if (++c == 8) {
+ buf[j++] = '\n';
+ c = 0;
+ }
+ }
+ }
+
+}
+
+
+
+FT_DECLARE_NONSTD(ftdm_status_t) ftdm_console_stream_raw_write(ftdm_stream_handle_t *handle, uint8_t *data, ftdm_size_t datalen)
+{
+ ftdm_size_t need = handle->data_len + datalen;
+
+ if (need >= handle->data_size) {
+ void *new_data;
+ need += handle->alloc_chunk;
+
+ if (!(new_data = realloc(handle->data, need))) {
+ return FTDM_MEMERR;
+ }
+
+ handle->data = new_data;
+ handle->data_size = need;
+ }
+
+ memcpy((uint8_t *) (handle->data) + handle->data_len, data, datalen);
+ handle->data_len += datalen;
+ handle->end = (uint8_t *) (handle->data) + handle->data_len;
+ *(uint8_t *)handle->end = '\0';
+
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(int) ftdm_vasprintf(char **ret, const char *fmt, va_list ap) /* code from switch_apr.c */
+{
+#ifdef HAVE_VASPRINTF
+ return vasprintf(ret, fmt, ap);
+#else
+ char *buf;
+ int len;
+ size_t buflen;
+ va_list ap2;
+ char *tmp = NULL;
+
+#ifdef _MSC_VER
+#if _MSC_VER >= 1500
+ /* hack for incorrect assumption in msvc header files for code analysis */
+ __analysis_assume(tmp);
+#endif
+ ap2 = ap;
+#else
+ va_copy(ap2, ap);
+#endif
+
+ len = vsnprintf(tmp, 0, fmt, ap2);
+
+ if (len > 0 && (buf = ftdm_malloc((buflen = (size_t) (len + 1)))) != NULL) {
+ len = vsnprintf(buf, buflen, fmt, ap);
+ *ret = buf;
+ } else {
+ *ret = NULL;
+ len = -1;
+ }
+
+ va_end(ap2);
+ return len;
+#endif
+}
+
+FT_DECLARE_NONSTD(ftdm_status_t) ftdm_console_stream_write(ftdm_stream_handle_t *handle, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf = handle->data;
+ char *end = handle->end;
+ int ret = 0;
+ char *data = NULL;
+
+ if (handle->data_len >= handle->data_size) {
+ return FTDM_FAIL;
+ }
+
+ va_start(ap, fmt);
+ ret = ftdm_vasprintf(&data, fmt, ap);
+ va_end(ap);
+
+ if (data) {
+ ftdm_size_t remaining = handle->data_size - handle->data_len;
+ ftdm_size_t need = strlen(data) + 1;
+
+ if ((remaining < need) && handle->alloc_len) {
+ ftdm_size_t new_len;
+ void *new_data;
+
+ new_len = handle->data_size + need + handle->alloc_chunk;
+ if ((new_data = realloc(handle->data, new_len))) {
+ handle->data_size = handle->alloc_len = new_len;
+ handle->data = new_data;
+ buf = handle->data;
+ remaining = handle->data_size - handle->data_len;
+ handle->end = (uint8_t *) (handle->data) + handle->data_len;
+ end = handle->end;
+ } else {
+ ftdm_log(FTDM_LOG_CRIT, "Memory Error!\n");
+ ftdm_safe_free(data);
+ return FTDM_FAIL;
+ }
+ }
+
+ if (remaining < need) {
+ ret = -1;
+ } else {
+ ret = 0;
+ snprintf(end, remaining, "%s", data);
+ handle->data_len = strlen(buf);
+ handle->end = (uint8_t *) (handle->data) + handle->data_len;
+ }
+ ftdm_safe_free(data);
+ }
+
+ return ret ? FTDM_FAIL : FTDM_SUCCESS;
+}
+
+FT_DECLARE(char *) ftdm_strdup(const char *str)
+{
+ ftdm_size_t len = strlen(str) + 1;
+ void *new = ftdm_malloc(len);
+
+ if (!new) {
+ return NULL;
+ }
+
+ return (char *)memcpy(new, str, len);
+}
+
+FT_DECLARE(char *) ftdm_strndup(const char *str, ftdm_size_t inlen)
+{
+ char *new = NULL;
+ ftdm_size_t len = strlen(str) + 1;
+ if (len > (inlen+1)) {
+ len = inlen+1;
+ }
+ new = (char *)ftdm_malloc(len);
+
+ if (!new) {
+ return NULL;
+ }
+
+ memcpy(new, str, len-1);
+ new[len-1] = 0;
+ return new;
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/ftdm_m3ua.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftdm_m3ua.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftdm_m3ua.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,692 @@
+/*
+ * ftdm_m3ua.c
+ * freetdm
+ *
+ * Created by Shane Burrell on 4/3/08.
+ * Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ *
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic *
+ *
+ * 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.
+ */
+
+
+#include "freetdm.h"
+#include "m3ua_client.h"
+#include "ftdm_m3ua.h"
+
+#define MAX_REQ_ID MAX_PENDING_CALLS
+typedef uint16_t m3ua_request_id_t;
+
+typedef enum {
+ BST_FREE,
+ BST_WAITING,
+ BST_READY,
+ BST_FAIL
+} m3ua_request_status_t;
+
+typedef struct {
+ m3ua_request_status_t status;
+ m3uac_event_t event;
+ ftdm_span_t *span;
+ ftdm_channel_t *ftdmchan;
+} m3ua_request_t;
+
+
+struct general_config {
+ uint32_t region;
+};
+typedef struct general_config general_config_t;
+
+
+struct m3ua_channel_profile {
+ char name[80];
+ int cust_span;
+ unsigned char opc[3];
+ unsigned char dpc[3];
+ int local_ip[4];
+ int local_port;
+ int remote_ip[4];
+ int remote_port;
+ int m3ua_mode;
+};
+typedef struct m3ua_channel_profile m3ua_channel_profile_t;
+
+static struct {
+ ftdm_hash_t *profile_hash;
+ general_config_t general_config;
+} globals;
+
+struct m3ua_span_data {
+ uint32_t boardno;
+ uint32_t flags;
+};
+typedef struct m3ua_span_data m3ua_span_data_t;
+
+struct m3ua_chan_data {
+ ftdm_buffer_t *digit_buffer;
+ ftdm_mutex_t *digit_mutex;
+ ftdm_size_t dtmf_len;
+ uint32_t flags;
+ uint32_t hdlc_bytes;
+};
+typedef struct m3ua_chan_data m3ua_chan_data_t;
+
+static ftdm_mutex_t *request_mutex = NULL;
+static ftdm_mutex_t *signal_mutex = NULL;
+
+static uint8_t req_map[MAX_REQ_ID+1] = { 0 };
+
+static void release_request_id(m3ua_request_id_t r)
+{
+ ftdm_mutex_lock(request_mutex);
+ req_map[r] = 0;
+ ftdm_mutex_unlock(request_mutex);
+}
+
+/*static m3ua_request_id_t next_request_id(void)
+{
+ m3ua_request_id_t r = 0;
+ int ok = 0;
+
+ while(!ok) {
+ ftdm_mutex_lock(request_mutex);
+ for (r = 1; r <= MAX_REQ_ID; r++) {
+ if (!req_map[r]) {
+ ok = 1;
+ req_map[r] = 1;
+ break;
+ }
+ }
+ ftdm_mutex_unlock(request_mutex);
+ if (!ok) {
+ ftdm_sleep(5);
+ }
+ }
+ return r;
+}
+*/
+
+static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
+{
+
+ m3ua_data_t *m3ua_data = ftdmchan->span->signal_data;
+ m3uac_connection_t *mcon = &m3ua_data->mcon;
+ ftdm_sigmsg_t sig;
+ ftdm_status_t status;
+
+ ftdm_log(FTDM_LOG_DEBUG, "%d:%d STATE [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = ftdmchan->chan_id;
+ sig.span_id = ftdmchan->span_id;
+ sig.channel = ftdmchan;
+
+ switch (ftdmchan->state) {
+ case FTDM_CHANNEL_STATE_DOWN:
+ {
+ if (ftdmchan->extra_id) {
+ release_request_id((m3ua_request_id_t)ftdmchan->extra_id);
+ ftdmchan->extra_id = 0;
+ }
+ ftdm_channel_done(ftdmchan);
+ }
+ break;
+ case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+ case FTDM_CHANNEL_STATE_PROGRESS:
+ {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ sig.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
+ if ((status = m3ua_data->signal_cb(&sig) != FTDM_SUCCESS)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ } else {
+ m3uac_exec_command(mcon,
+ ftdmchan->physical_span_id-1,
+ ftdmchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_START_ACK,
+ 0);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_RING:
+ {
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ sig.event_id = FTDM_SIGEVENT_START;
+ if ((status = m3ua_data->signal_cb(&sig) != FTDM_SUCCESS)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ }
+
+ }
+ break;
+ case FTDM_CHANNEL_STATE_RESTART:
+ {
+ if (ftdmchan->last_state != FTDM_CHANNEL_STATE_HANGUP && ftdmchan->last_state != FTDM_CHANNEL_STATE_DOWN) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ } else {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_UP:
+ {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ sig.event_id = FTDM_SIGEVENT_UP;
+ if ((status = m3ua_data->signal_cb(&sig) != FTDM_SUCCESS)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ } else {
+ if (!(ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MEDIA))) {
+ m3uac_exec_command(mcon,
+ ftdmchan->physical_span_id-1,
+ ftdmchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_START_ACK,
+ 0);
+ }
+
+ m3uac_exec_command(mcon,
+ ftdmchan->physical_span_id-1,
+ ftdmchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_ANSWERED,
+ 0);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_DIALING:
+ {
+ }
+ break;
+ case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
+ {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ }
+ break;
+ case FTDM_CHANNEL_STATE_HANGUP:
+ {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_ANSWERED) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MEDIA)) {
+ m3uac_exec_command(mcon,
+ ftdmchan->physical_span_id-1,
+ ftdmchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_STOPPED,
+ ftdmchan->caller_data.hangup_cause);
+ } else {
+ m3uac_exec_command(mcon,
+ ftdmchan->physical_span_id-1,
+ ftdmchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_START_NACK,
+ ftdmchan->caller_data.hangup_cause);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_CANCEL:
+ {
+ sig.event_id = FTDM_SIGEVENT_STOP;
+ status = m3ua_data->signal_cb(&sig);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ m3uac_exec_command(mcon,
+ ftdmchan->physical_span_id-1,
+ ftdmchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_START_NACK_ACK,
+ 0);
+ }
+ break;
+ case FTDM_CHANNEL_STATE_TERMINATING:
+ {
+ sig.event_id = FTDM_SIGEVENT_STOP;
+ status = m3ua_data->signal_cb(&sig);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ m3uac_exec_command(mcon,
+ ftdmchan->physical_span_id-1,
+ ftdmchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_STOPPED_ACK,
+ 0);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+static __inline__ void check_state(ftdm_span_t *span)
+{
+ if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
+ uint32_t j;
+ ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
+ for(j = 1; j <= span->chan_count; j++) {
+ if (ftdm_test_flag((&span->channels[j]), FTDM_CHANNEL_STATE_CHANGE)) {
+ ftdm_clear_flag_locked((&span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
+ state_advance(&span->channels[j]);
+ ftdm_channel_complete_state(&span->channels[j]);
+ }
+ }
+ }
+}
+
+
+static int parse_ss7_event(ftdm_span_t *span, m3uac_connection_t *mcon, m3uac_event_t *event)
+{
+ ftdm_mutex_lock(signal_mutex);
+
+ if (!ftdm_running()) {
+ ftdm_log(FTDM_LOG_WARNING, "System is shutting down.\n");
+ goto end;
+ }
+
+
+ if (ftdm_test_flag(span, FTDM_SPAN_SUSPENDED) &&
+ event->event_id != SIGBOOST_EVENT_SYSTEM_RESTART_ACK && event->event_id != SIGBOOST_EVENT_HEARTBEAT) {
+
+ ftdm_log(FTDM_LOG_WARNING,
+ "INVALID EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n",
+ m3uac_event_id_name(event->event_id),
+ event->event_id,
+ event->span+1,
+ event->chan+1,
+ event->release_cause,
+ event->call_setup_id,
+ event->fseqno,
+ (event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
+ (event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A")
+ );
+
+ goto end;
+ }
+
+
+ ftdm_log(FTDM_LOG_DEBUG,
+ "RX EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n",
+ m3uac_event_id_name(event->event_id),
+ event->event_id,
+ event->span+1,
+ event->chan+1,
+ event->release_cause,
+ event->call_setup_id,
+ event->fseqno,
+ (event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
+ (event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A")
+ );
+
+
+
+ switch(event->event_id) {
+
+ case SIGBOOST_EVENT_CALL_START:
+ //handle_call_start(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_STOPPED:
+ //handle_call_stop(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_START_ACK:
+ //handle_call_start_ack(mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_START_NACK:
+ //handle_call_start_nack(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_ANSWERED:
+ //handle_call_answer(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_HEARTBEAT:
+ //handle_heartbeat(mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_STOPPED_ACK:
+ case SIGBOOST_EVENT_CALL_START_NACK_ACK:
+ //handle_call_done(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_INSERT_CHECK_LOOP:
+ //handle_call_loop_start(event);
+ break;
+ case SIGBOOST_EVENT_REMOVE_CHECK_LOOP:
+ //handle_call_stop(event);
+ break;
+ case SIGBOOST_EVENT_SYSTEM_RESTART_ACK:
+ //handle_restart_ack(mcon, span, event);
+ break;
+ case SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE:
+ //handle_gap_abate(event);
+ break;
+ default:
+ ftdm_log(FTDM_LOG_WARNING, "No handler implemented for [%s]\n", m3uac_event_id_name(event->event_id));
+ break;
+ }
+
+ end:
+
+ ftdm_mutex_unlock(signal_mutex);
+
+ return 0;
+}
+
+static FIO_CONFIGURE_FUNCTION(m3ua_configure)
+{
+ m3ua_channel_profile_t *profile = NULL;
+
+ int ok = 1;
+
+ if (!(profile = (m3ua_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)category))) {
+ profile = ftdm_malloc(sizeof(*profile));
+ memset(profile, 0, sizeof(*profile));
+ ftdm_set_string(profile->name, category);
+ hashtable_insert(globals.profile_hash, (void *)profile->name, profile);
+ ftdm_log(FTDM_LOG_INFO, "creating profile [%s]\n", category);
+ }
+
+// ftdm_set_string(m3ua_data->mcon. cfg.local_ip, local_ip);
+ if (!strcasecmp(var, "local_sctp_port")) {
+ profile->local_port = 30000 ;
+ profile->remote_port = 30000;
+ profile->cust_span++;
+ }
+ ok = 1;
+
+
+ if (ok) {
+ ftdm_log(FTDM_LOG_INFO, "setting param [%s]=[%s] for profile [%s]\n", var, val, category);
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "unknown param [%s]\n", var);
+ }
+
+ return FTDM_SUCCESS;
+}
+
+static FIO_CONFIGURE_SPAN_FUNCTION(m3ua_configure_span)
+{
+
+ return FTDM_FAIL;
+}
+
+static FIO_OPEN_FUNCTION(m3ua_open)
+{
+
+ return FTDM_FAIL;
+}
+
+static FIO_CLOSE_FUNCTION(m3ua_close)
+{
+
+ return FTDM_FAIL;
+}
+
+/*static FIO_SET_INTERVAL_FUNCTION(m3ua_set_interval)
+{
+
+ return 0;
+}*/
+
+static FIO_WAIT_FUNCTION(m3ua_wait)
+{
+
+ return FTDM_FAIL;
+}
+
+static FIO_READ_FUNCTION(m3ua_read)
+{
+
+ return FTDM_FAIL;
+}
+
+static FIO_WRITE_FUNCTION(m3ua_write)
+{
+
+ return FTDM_FAIL;
+}
+
+static FIO_COMMAND_FUNCTION(m3ua_command)
+{
+ return FTDM_FAIL;
+}
+
+static FIO_SPAN_POLL_EVENT_FUNCTION(m3ua_poll_event)
+{
+ return FTDM_FAIL;
+}
+
+static FIO_SPAN_NEXT_EVENT_FUNCTION(m3ua_next_event)
+{
+ return FTDM_FAIL;
+}
+
+
+static FIO_SPAN_DESTROY_FUNCTION(m3ua_span_destroy)
+{
+ m3ua_span_data_t *span_data = (m3ua_span_data_t *) span->mod_data;
+
+ if (span_data) {
+ ftdm_safe_free(span_data);
+ }
+
+ return FTDM_SUCCESS;
+}
+static FIO_CHANNEL_DESTROY_FUNCTION(m3ua_channel_destroy)
+{
+ m3ua_chan_data_t *chan_data = (m3ua_chan_data_t *) ftdmchan->mod_data;
+ m3ua_span_data_t *span_data = (m3ua_span_data_t *) ftdmchan->span->mod_data;
+
+ if (!chan_data) {
+ return FTDM_FAIL;
+ }
+
+
+
+
+
+
+ ftdm_mutex_destroy(&chan_data->digit_mutex);
+ ftdm_buffer_destroy(&chan_data->digit_buffer);
+
+
+ ftdm_safe_free(chan_data);
+
+ if (span_data) {
+ ftdm_safe_free(span_data);
+ }
+
+
+ return FTDM_SUCCESS;
+}
+
+
+
+static FIO_GET_ALARMS_FUNCTION(m3ua_get_alarms)
+{
+ return FTDM_FAIL;
+}
+
+static ftdm_io_interface_t m3ua_interface;
+
+ftdm_status_t m3ua_init(ftdm_io_interface_t **zint)
+{
+ assert(zint != NULL);
+ memset(&m3ua_interface, 0, sizeof(m3ua_interface));
+
+ m3ua_interface.name = "m3ua";
+ m3ua_interface.configure = m3ua_configure;
+ m3ua_interface.configure_span = m3ua_configure_span;
+ m3ua_interface.open = m3ua_open;
+ m3ua_interface.close = m3ua_close;
+ m3ua_interface.wait = m3ua_wait;
+ m3ua_interface.read = m3ua_read;
+ m3ua_interface.write = m3ua_write;
+ m3ua_interface.command = m3ua_command;
+ m3ua_interface.poll_event = m3ua_poll_event;
+ m3ua_interface.next_event = m3ua_next_event;
+ m3ua_interface.channel_destroy = m3ua_channel_destroy;
+ m3ua_interface.span_destroy = m3ua_span_destroy;
+ m3ua_interface.get_alarms = m3ua_get_alarms;
+ *zint = &m3ua_interface;
+
+ return FTDM_FAIL;
+}
+
+ftdm_status_t m3ua_destroy(void)
+{
+ return FTDM_FAIL;
+}
+
+
+static void *m3ua_run(ftdm_thread_t *me, void *obj)
+{
+ ftdm_span_t *span = (ftdm_span_t *) obj;
+ m3ua_data_t *m3ua_data = span->signal_data;
+ m3uac_connection_t *mcon, *pcon;
+ uint32_t ms = 10, too_long = 60000;
+
+
+ m3ua_data->pcon = m3ua_data->mcon;
+
+ if (m3uac_connection_open(&m3ua_data->mcon,
+ m3ua_data->mcon.cfg.local_ip,
+ m3ua_data->mcon.cfg.local_port,
+ m3ua_data->mcon.cfg.remote_ip,
+ m3ua_data->mcon.cfg.remote_port) < 0) {
+ ftdm_log(FTDM_LOG_DEBUG, "Error: Opening MCON Socket [%d] %s\n", m3ua_data->mcon.socket, strerror(errno));
+ goto end;
+ }
+
+ if (m3uac_connection_open(&m3ua_data->pcon,
+ m3ua_data->pcon.cfg.local_ip,
+ ++m3ua_data->pcon.cfg.local_port,
+ m3ua_data->pcon.cfg.remote_ip,
+ m3ua_data->pcon.cfg.remote_port) < 0) {
+ ftdm_log(FTDM_LOG_DEBUG, "Error: Opening PCON Socket [%d] %s\n", m3ua_data->pcon.socket, strerror(errno));
+ goto end;
+ }
+
+ mcon = &m3ua_data->mcon;
+ pcon = &m3ua_data->pcon;
+
+ top:
+
+ //init_outgoing_array();
+
+ m3uac_exec_command(mcon,
+ 0,
+ 0,
+ -1,
+ SIGBOOST_EVENT_SYSTEM_RESTART,
+ 0);
+
+ while (ftdm_test_flag(m3ua_data, FTDM_M3UA_RUNNING)) {
+ fd_set rfds, efds;
+ struct timeval tv = { 0, ms * 1000 };
+ int max, activity, i = 0;
+ m3uac_event_t *event = NULL;
+
+ if (!ftdm_running()) {
+ m3uac_exec_command(mcon,
+ 0,
+ 0,
+ -1,
+ SIGBOOST_EVENT_SYSTEM_RESTART,
+ 0);
+ break;
+ }
+
+ FD_ZERO(&rfds);
+ FD_ZERO(&efds);
+ FD_SET(mcon->socket, &rfds);
+ FD_SET(mcon->socket, &efds);
+ FD_SET(pcon->socket, &rfds);
+ FD_SET(pcon->socket, &efds);
+
+ max = ((pcon->socket > mcon->socket) ? pcon->socket : mcon->socket) + 1;
+
+ if ((activity = select(max, &rfds, NULL, &efds, &tv)) < 0) {
+ goto error;
+ }
+
+ if (activity) {
+ if (FD_ISSET(pcon->socket, &efds) || FD_ISSET(mcon->socket, &efds)) {
+ goto error;
+ }
+
+ if (FD_ISSET(pcon->socket, &rfds)) {
+ if ((event = m3uac_connection_readp(pcon, i))) {
+ parse_ss7_event(span, mcon, event);
+ } else goto top;
+ }
+
+ if (FD_ISSET(mcon->socket, &rfds)) {
+ if ((event = m3uac_connection_read(mcon, i))) {
+ parse_ss7_event(span, mcon, event);
+ } else goto top;
+ }
+ }
+
+ check_state(span);
+ mcon->hb_elapsed += ms;
+
+ if (mcon->hb_elapsed >= too_long && (mcon->up || !ftdm_test_flag(span, FTDM_SPAN_SUSPENDED))) {
+ ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
+ ftdm_set_flag_locked(span, FTDM_SPAN_SUSPENDED);
+ mcon->up = 0;
+ ftdm_log(FTDM_LOG_CRIT, "Lost Heartbeat!\n");
+ }
+
+ }
+
+ goto end;
+
+ error:
+ ftdm_log(FTDM_LOG_CRIT, "Socket Error!\n");
+
+ end:
+
+ m3uac_connection_close(&m3ua_data->mcon);
+ m3uac_connection_close(&m3ua_data->pcon);
+
+ ftdm_clear_flag(m3ua_data, FTDM_M3UA_RUNNING);
+
+ ftdm_log(FTDM_LOG_DEBUG, "M3UA thread ended.\n");
+ return NULL;
+}
+ftdm_status_t m3ua_start(ftdm_span_t *span)
+{
+ m3ua_data_t *m3ua_data = span->signal_data;
+ ftdm_set_flag(m3ua_data, FTDM_M3UA_RUNNING);
+ return ftdm_thread_create_detached(m3ua_run, span);
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+*/
Added: freeswitch/trunk/libs/freetdm/src/ftdm_queue.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftdm_queue.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftdm_queue.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2009, Sangoma Technologies
+ * Moises Silva <moy@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.
+ */
+
+#include "freetdm.h"
+
+static ftdm_status_t ftdm_std_queue_create(ftdm_queue_t **outqueue, ftdm_size_t capacity);
+static ftdm_status_t ftdm_std_queue_enqueue(ftdm_queue_t *queue, void *obj);
+static void *ftdm_std_queue_dequeue(ftdm_queue_t *queue);
+static ftdm_status_t ftdm_std_queue_wait(ftdm_queue_t *queue, int ms);
+static ftdm_status_t ftdm_std_queue_get_interrupt(ftdm_queue_t *queue, ftdm_interrupt_t **interrupt);
+static ftdm_status_t ftdm_std_queue_destroy(ftdm_queue_t **inqueue);
+
+struct ftdm_queue {
+ ftdm_mutex_t *mutex;
+ ftdm_interrupt_t *interrupt;
+ ftdm_size_t capacity;
+ ftdm_size_t size;
+ unsigned rindex;
+ unsigned windex;
+ void **elements;
+};
+
+FT_DECLARE_DATA ftdm_queue_handler_t g_ftdm_queue_handler =
+{
+ /*.create = */ ftdm_std_queue_create,
+ /*.enqueue = */ ftdm_std_queue_enqueue,
+ /*.dequeue = */ ftdm_std_queue_dequeue,
+ /*.wait = */ ftdm_std_queue_wait,
+ /*.get_interrupt = */ ftdm_std_queue_get_interrupt,
+ /*.destroy = */ ftdm_std_queue_destroy
+};
+
+FT_DECLARE(ftdm_status_t) ftdm_global_set_queue_handler(ftdm_queue_handler_t *handler)
+{
+ if (!handler ||
+ !handler->create ||
+ !handler->enqueue ||
+ !handler->dequeue ||
+ !handler->wait ||
+ !handler->get_interrupt ||
+ !handler->destroy) {
+ return FTDM_FAIL;
+ }
+ memcpy(&g_ftdm_queue_handler, handler, sizeof(*handler));
+ return FTDM_SUCCESS;
+}
+
+static ftdm_status_t ftdm_std_queue_create(ftdm_queue_t **outqueue, ftdm_size_t capacity)
+{
+ ftdm_queue_t *queue = NULL;
+ ftdm_assert_return(outqueue, FTDM_FAIL, "Queue double pointer is null\n");
+ ftdm_assert_return(capacity > 0, FTDM_FAIL, "Queue capacity is not bigger than 0\n");
+
+ *outqueue = NULL;
+ queue = ftdm_calloc(1, sizeof(*queue));
+ if (!queue) {
+ return FTDM_FAIL;
+ }
+
+ queue->elements = ftdm_calloc(1, (sizeof(void*)*capacity));
+ if (!queue->elements) {
+ goto failed;
+ }
+ queue->capacity = capacity;
+
+ if (ftdm_mutex_create(&queue->mutex) != FTDM_SUCCESS) {
+ goto failed;
+ }
+
+ if (ftdm_interrupt_create(&queue->interrupt, FTDM_INVALID_SOCKET) != FTDM_SUCCESS) {
+ goto failed;
+ }
+
+ *outqueue = queue;
+ return FTDM_SUCCESS;
+
+failed:
+ if (queue) {
+ if (queue->interrupt) {
+ ftdm_interrupt_destroy(&queue->interrupt);
+ }
+ if (queue->mutex) {
+ ftdm_mutex_destroy(&queue->mutex);
+ }
+ ftdm_safe_free(queue->elements);
+ ftdm_safe_free(queue);
+ }
+ return FTDM_FAIL;
+}
+
+static ftdm_status_t ftdm_std_queue_enqueue(ftdm_queue_t *queue, void *obj)
+{
+ ftdm_status_t status = FTDM_FAIL;
+
+ ftdm_assert_return(queue != NULL, FTDM_FAIL, "Queue is null!");
+
+ ftdm_mutex_lock(queue->mutex);
+
+ if (queue->windex == queue->capacity) {
+ /* try to see if we can wrap around */
+ queue->windex = 0;
+ }
+
+ if (queue->size != 0 && queue->windex == queue->rindex) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to enqueue obj %p in queue %p, no more room! windex == rindex == %d!\n", obj, queue, queue->windex);
+ goto done;
+ }
+
+ queue->elements[queue->windex++] = obj;
+ queue->size++;
+ status = FTDM_SUCCESS;
+
+ /* wake up queue reader */
+ ftdm_interrupt_signal(queue->interrupt);
+
+done:
+
+ ftdm_mutex_unlock(queue->mutex);
+
+ return status;
+}
+
+static void *ftdm_std_queue_dequeue(ftdm_queue_t *queue)
+{
+ void *obj = NULL;
+
+ ftdm_assert_return(queue != NULL, NULL, "Queue is null!");
+
+ ftdm_mutex_lock(queue->mutex);
+
+ if (queue->size == 0) {
+ goto done;
+ }
+
+ obj = queue->elements[queue->rindex];
+ queue->elements[queue->rindex++] = NULL;
+ queue->size--;
+ if (queue->rindex == queue->capacity) {
+ queue->rindex = 0;
+ }
+
+done:
+
+ ftdm_mutex_unlock(queue->mutex);
+
+ return obj;
+}
+
+static ftdm_status_t ftdm_std_queue_wait(ftdm_queue_t *queue, int ms)
+{
+ ftdm_status_t ret;
+ ftdm_assert_return(queue != NULL, FTDM_FAIL, "Queue is null!");
+
+ ftdm_mutex_lock(queue->mutex);
+
+ /* if there is elements in the queue, no need to wait */
+ if (queue->size != 0) {
+ ftdm_mutex_unlock(queue->mutex);
+ return FTDM_SUCCESS;
+ }
+
+ /* no elements on the queue, wait for someone to write an element */
+ ret = ftdm_interrupt_wait(queue->interrupt, ms);
+
+ /* got an element or timeout, bail out */
+ ftdm_mutex_unlock(queue->mutex);
+
+ return ret;
+}
+
+static ftdm_status_t ftdm_std_queue_get_interrupt(ftdm_queue_t *queue, ftdm_interrupt_t **interrupt)
+{
+ ftdm_assert_return(queue != NULL, FTDM_FAIL, "Queue is null!\n");
+ ftdm_assert_return(interrupt != NULL, FTDM_FAIL, "Queue is null!\n");
+ *interrupt = queue->interrupt;
+ return FTDM_SUCCESS;
+}
+
+static ftdm_status_t ftdm_std_queue_destroy(ftdm_queue_t **inqueue)
+{
+ ftdm_queue_t *queue = NULL;
+ ftdm_assert_return(inqueue != NULL, FTDM_FAIL, "Queue is null!\n");
+ ftdm_assert_return(*inqueue != NULL, FTDM_FAIL, "Queue is null!\n");
+
+ queue = *inqueue;
+ ftdm_interrupt_destroy(&queue->interrupt);
+ ftdm_mutex_destroy(&queue->mutex);
+ ftdm_safe_free(queue->elements);
+ ftdm_safe_free(queue);
+ *inqueue = NULL;
+ return FTDM_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/ftdm_threadmutex.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftdm_threadmutex.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftdm_threadmutex.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,457 @@
+/*
+ * Cross Platform Thread/Mutex abstraction
+ * Copyright(C) 2007 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer.
+ *
+ * Contributors:
+ *
+ * Moises Silva <moy@sangoma.com>
+ *
+ */
+
+#ifdef WIN32
+/* required for TryEnterCriticalSection definition. Must be defined before windows.h include */
+#define _WIN32_WINNT 0x0400
+#endif
+
+#include "freetdm.h"
+#include "ftdm_threadmutex.h"
+
+#ifdef WIN32
+#include <process.h>
+
+#define FTDM_THREAD_CALLING_CONVENTION __stdcall
+
+struct ftdm_mutex {
+ CRITICAL_SECTION mutex;
+};
+
+#else
+#include <pthread.h>
+#include <poll.h>
+
+#define FTDM_THREAD_CALLING_CONVENTION
+
+struct ftdm_mutex {
+ pthread_mutex_t mutex;
+};
+
+#endif
+
+struct ftdm_interrupt {
+ ftdm_socket_t device;
+#ifdef WIN32
+ /* for generic interruption */
+ HANDLE event;
+#else
+ /* for generic interruption */
+ int readfd;
+ int writefd;
+#endif
+};
+
+struct ftdm_thread {
+#ifdef WIN32
+ void *handle;
+#else
+ pthread_t handle;
+#endif
+ void *private_data;
+ ftdm_thread_function_t function;
+ ftdm_size_t stack_size;
+#ifndef WIN32
+ pthread_attr_t attribute;
+#endif
+};
+
+ftdm_size_t thread_default_stacksize = 0;
+
+FT_DECLARE(void) ftdm_thread_override_default_stacksize(ftdm_size_t size)
+{
+ thread_default_stacksize = size;
+}
+
+static void * FTDM_THREAD_CALLING_CONVENTION thread_launch(void *args)
+{
+ void *exit_val;
+ ftdm_thread_t *thread = (ftdm_thread_t *)args;
+ exit_val = thread->function(thread, thread->private_data);
+#ifndef WIN32
+ pthread_attr_destroy(&thread->attribute);
+#endif
+ ftdm_safe_free(thread);
+
+ return exit_val;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_thread_create_detached(ftdm_thread_function_t func, void *data)
+{
+ return ftdm_thread_create_detached_ex(func, data, thread_default_stacksize);
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_thread_create_detached_ex(ftdm_thread_function_t func, void *data, ftdm_size_t stack_size)
+{
+ ftdm_thread_t *thread = NULL;
+ ftdm_status_t status = FTDM_FAIL;
+
+ if (!func || !(thread = (ftdm_thread_t *)ftdm_malloc(sizeof(ftdm_thread_t)))) {
+ goto done;
+ }
+
+ thread->private_data = data;
+ thread->function = func;
+ thread->stack_size = stack_size;
+
+#if defined(WIN32)
+ thread->handle = (void *)_beginthreadex(NULL, (unsigned)thread->stack_size, (unsigned int (__stdcall *)(void *))thread_launch, thread, 0, NULL);
+ if (!thread->handle) {
+ goto fail;
+ }
+ CloseHandle(thread->handle);
+
+ status = FTDM_SUCCESS;
+ goto done;
+#else
+
+ if (pthread_attr_init(&thread->attribute) != 0) goto fail;
+
+ if (pthread_attr_setdetachstate(&thread->attribute, PTHREAD_CREATE_DETACHED) != 0) goto failpthread;
+
+ if (thread->stack_size && pthread_attr_setstacksize(&thread->attribute, thread->stack_size) != 0) goto failpthread;
+
+ if (pthread_create(&thread->handle, &thread->attribute, thread_launch, thread) != 0) goto failpthread;
+
+ status = FTDM_SUCCESS;
+ goto done;
+ failpthread:
+ pthread_attr_destroy(&thread->attribute);
+#endif
+
+ fail:
+ if (thread) {
+ ftdm_safe_free(thread);
+ }
+ done:
+ return status;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_mutex_create(ftdm_mutex_t **mutex)
+{
+ ftdm_status_t status = FTDM_FAIL;
+#ifndef WIN32
+ pthread_mutexattr_t attr;
+#endif
+ ftdm_mutex_t *check = NULL;
+
+ check = (ftdm_mutex_t *)ftdm_malloc(sizeof(**mutex));
+ if (!check)
+ goto done;
+#ifdef WIN32
+ InitializeCriticalSection(&check->mutex);
+#else
+ if (pthread_mutexattr_init(&attr))
+ goto done;
+
+ if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
+ goto fail;
+
+ if (pthread_mutex_init(&check->mutex, &attr))
+ goto fail;
+
+ goto success;
+
+ fail:
+ pthread_mutexattr_destroy(&attr);
+ goto done;
+
+ success:
+#endif
+ *mutex = check;
+ status = FTDM_SUCCESS;
+
+ done:
+ return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_mutex_destroy(ftdm_mutex_t **mutex)
+{
+ ftdm_mutex_t *mp = *mutex;
+ *mutex = NULL;
+ if (!mp) {
+ return FTDM_FAIL;
+ }
+#ifdef WIN32
+ DeleteCriticalSection(&mp->mutex);
+#else
+ if (pthread_mutex_destroy(&mp->mutex))
+ return FTDM_FAIL;
+#endif
+ ftdm_safe_free(mp);
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) _ftdm_mutex_lock(ftdm_mutex_t *mutex)
+{
+#ifdef WIN32
+ EnterCriticalSection(&mutex->mutex);
+#else
+ int err;
+ if ((err = pthread_mutex_lock(&mutex->mutex))) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to lock mutex %d:%s\n", err, strerror(err));
+ return FTDM_FAIL;
+ }
+#endif
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) _ftdm_mutex_trylock(ftdm_mutex_t *mutex)
+{
+#ifdef WIN32
+ if (!TryEnterCriticalSection(&mutex->mutex))
+ return FTDM_FAIL;
+#else
+ if (pthread_mutex_trylock(&mutex->mutex))
+ return FTDM_FAIL;
+#endif
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) _ftdm_mutex_unlock(ftdm_mutex_t *mutex)
+{
+#ifdef WIN32
+ LeaveCriticalSection(&mutex->mutex);
+#else
+ if (pthread_mutex_unlock(&mutex->mutex))
+ return FTDM_FAIL;
+#endif
+ return FTDM_SUCCESS;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_create(ftdm_interrupt_t **ininterrupt, ftdm_socket_t device)
+{
+ ftdm_interrupt_t *interrupt = NULL;
+#ifndef WIN32
+ int fds[2];
+#endif
+
+ ftdm_assert_return(ininterrupt != NULL, FTDM_FAIL, "interrupt double pointer is null!\n");
+
+ interrupt = ftdm_calloc(1, sizeof(*interrupt));
+ if (!interrupt) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt memory\n");
+ return FTDM_FAIL;
+ }
+
+ interrupt->device = device;
+#ifdef WIN32
+ interrupt->interrupt = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!interrupt->interrupt) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt event\n");
+ goto failed;
+ }
+#else
+ if (pipe(fds)) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt pipe: %s\n", strerror(errno));
+ goto failed;
+ }
+ interrupt->readfd = fds[0];
+ interrupt->writefd = fds[1];
+#endif
+
+ *ininterrupt = interrupt;
+ return FTDM_SUCCESS;
+
+failed:
+ if (interrupt) {
+#ifndef WIN32
+ if (interrupt->readfd) {
+ close(interrupt->readfd);
+ close(interrupt->writefd);
+ interrupt->readfd = -1;
+ interrupt->writefd = -1;
+ }
+#endif
+ ftdm_safe_free(interrupt);
+ }
+ return FTDM_FAIL;
+}
+
+#define ONE_BILLION 1000000000
+
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_wait(ftdm_interrupt_t *interrupt, int ms)
+{
+ int num = 1;
+#ifdef WIN32
+ DWORD res = 0;
+ HANDLE ints[2];
+#else
+ int res = 0;
+ struct pollfd ints[2];
+ char pipebuf[255];
+#endif
+
+ ftdm_assert_return(interrupt != NULL, FTDM_FAIL, "Condition is null!\n");
+
+
+ /* start implementation */
+#ifdef WIN32
+ ints[0] = interrupt->event;
+ if (interrupt->device != FTDM_INVALID_SOCKET) {
+ num++;
+ ints[1] = interrupt->device;
+ }
+ res = WaitForMultipleObjects(num, &ints, FALSE, ms >= 0 ? ms : INFINITE);
+ switch (res) {
+ case WAIT_TIMEOUT:
+ return FTDM_TIMEOUT;
+ case WAIT_FAILED:
+ case WAIT_ABANDONED: /* is it right to fail with abandoned? */
+ return FTDM_FAIL;
+ default:
+ if (res >= (sizeof(ints)/sizeof(ints[0]))) {
+ ftdm_log(FTDM_LOG_ERROR, "Error waiting for freetdm interrupt event (WaitForSingleObject returned %d)\n", res);
+ return FTDM_FAIL;
+ }
+ return FTDM_SUCCESS;
+ }
+#else
+ ints[0].fd = interrupt->readfd;
+ ints[0].events = POLLIN;
+ ints[0].revents = 0;
+
+ if (interrupt->device != FTDM_INVALID_SOCKET) {
+ num++;
+ ints[1].fd = interrupt->device;
+ ints[1].events = POLLIN;
+ ints[1].revents = 0;
+ }
+
+ res = poll(ints, num, ms);
+
+ if (res == -1) {
+ ftdm_log(FTDM_LOG_CRIT, "interrupt poll failed (%s)\n", strerror(errno));
+ return FTDM_FAIL;
+ }
+
+ if (res == 0) {
+ return FTDM_TIMEOUT;
+ }
+
+ if (ints[0].revents & POLLIN) {
+ res = read(ints[0].fd, pipebuf, sizeof(pipebuf));
+ if (res == -1) {
+ ftdm_log(FTDM_LOG_CRIT, "reading interrupt descriptor failed (%s)\n", strerror(errno));
+ }
+ }
+
+ return FTDM_SUCCESS;
+#endif
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_signal(ftdm_interrupt_t *interrupt)
+{
+ ftdm_assert_return(interrupt != NULL, FTDM_FAIL, "Interrupt is null!\n");
+#ifdef WIN32
+ if (!SetEvent(interrupt->interrupt)) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to signal interrupt\n");
+ return FTDM_FAIL;
+ }
+#else
+ int err;
+ if ((err = write(interrupt->writefd, "w", 1)) != 1) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to signal interrupt: %s\n", errno, strerror(errno));
+ return FTDM_FAIL;
+ }
+#endif
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_destroy(ftdm_interrupt_t **ininterrupt)
+{
+ ftdm_interrupt_t *interrupt = NULL;
+ ftdm_assert_return(ininterrupt != NULL, FTDM_FAIL, "Interrupt null when destroying!\n");
+ interrupt = *ininterrupt;
+#ifdef WIN32
+ CloseHandle(interrupt->interrupt);
+#else
+ close(interrupt->readfd);
+ close(interrupt->writefd);
+ interrupt->readfd = -1;
+ interrupt->writefd = -1;
+#endif
+ ftdm_safe_free(interrupt);
+ *ininterrupt = NULL;
+ return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_multiple_wait(ftdm_interrupt_t *interrupts[], ftdm_size_t size, int ms)
+{
+#ifndef WIN32
+ int i;
+ int res = 0;
+ int numdevices = 0;
+ char pipebuf[255];
+ struct pollfd ints[size*2];
+
+ memset(&ints, 0, sizeof(ints));
+
+ for (i = 0; i < size; i++) {
+ ints[i].events = POLLIN;
+ ints[i].revents = 0;
+ ints[i].fd = interrupts[i]->readfd;
+ if (interrupts[i]->device != FTDM_INVALID_SOCKET) {
+ ints[i+numdevices].events = POLLIN;
+ ints[i+numdevices].revents = 0;
+ ints[i+numdevices].fd = interrupts[i]->device;
+ numdevices++;
+ }
+ }
+
+ res = poll(ints, size + numdevices, ms);
+
+ if (res == -1) {
+ ftdm_log(FTDM_LOG_CRIT, "interrupt poll failed (%s)\n", strerror(errno));
+ return FTDM_FAIL;
+ }
+
+ if (res == 0) {
+ return FTDM_TIMEOUT;
+ }
+
+ for (i = 0; i < size; i++) {
+ if (ints[i].revents & POLLIN) {
+ res = read(ints[i].fd, pipebuf, sizeof(pipebuf));
+ if (res == -1) {
+ ftdm_log(FTDM_LOG_CRIT, "reading interrupt descriptor failed (%s)\n", strerror(errno));
+ }
+ }
+ }
+
+#endif
+ return FTDM_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#ifndef FTDM_ANALOG_H
+#define FTDM_ANALOG_H
+#include "freetdm.h"
+
+typedef enum {
+ FTDM_ANALOG_RUNNING = (1 << 0),
+ FTDM_ANALOG_CALLERID = (1 << 1)
+} ftdm_analog_flag_t;
+
+#define FTDM_MAX_HOTLINE_STR 20
+#define MAX_DTMF 256
+
+struct ftdm_analog_data {
+ uint32_t flags;
+ uint32_t max_dialstr;
+ uint32_t digit_timeout;
+ char hotline[FTDM_MAX_HOTLINE_STR];
+};
+
+
+
+static void *ftdm_analog_run(ftdm_thread_t *me, void *obj);
+typedef struct ftdm_analog_data ftdm_analog_data_t;
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,353 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="ftmod_analog"
+ ProjectGUID="{37C94798-6E33-4B4F-8EE0-C72A7DC91157}"
+ RootNamespace="ftmod_analog"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="ftmod_analog.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="ftdm_analog.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,975 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#include "freetdm.h"
+#include "ftdm_analog.h"
+
+#ifndef localtime_r
+struct tm * localtime_r(const time_t *clock, struct tm *result);
+#endif
+
+static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj);
+
+/**
+ * \brief Starts an FXO channel thread (outgoing call)
+ * \param ftdmchan Channel to initiate call on
+ * \return Success or failure
+ *
+ * Initialises state, starts tone progress detection and runs the channel in a new a thread.
+ */
+static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxo_outgoing_call)
+{
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
+ ftdm_channel_clear_needed_tones(ftdmchan);
+ ftdm_channel_clear_detected_tones(ftdmchan);
+
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_OFFHOOK, NULL);
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_PROGRESS_DETECT, NULL);
+ ftdmchan->needed_tones[FTDM_TONEMAP_DIAL] = 1;
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
+ ftdm_thread_create_detached(ftdm_analog_channel_run, ftdmchan);
+ return FTDM_SUCCESS;
+ }
+
+ return FTDM_FAIL;
+}
+
+/**
+ * \brief Starts an FXS channel thread (outgoing call)
+ * \param ftdmchan Channel to initiate call on
+ * \return Success or failure
+ *
+ * Indicates call waiting if channel is already in use, otherwise runs the channel in a new thread.
+ */
+static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxs_outgoing_call)
+{
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CALLWAITING);
+ } else {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_GENRING);
+ ftdm_thread_create_detached(ftdm_analog_channel_run, ftdmchan);
+ }
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Starts an analog span thread (monitor)
+ * \param span Span to monitor
+ * \return Success or failure
+ */
+static ftdm_status_t ftdm_analog_start(ftdm_span_t *span)
+{
+ ftdm_analog_data_t *analog_data = span->signal_data;
+ ftdm_set_flag(analog_data, FTDM_ANALOG_RUNNING);
+ return ftdm_thread_create_detached(ftdm_analog_run, span);
+}
+
+/**
+ * \brief Initialises an analog span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span)
+//ftdm_status_t ftdm_analog_configure_span(ftdm_span_t *span, char *tonemap, uint32_t digit_timeout, uint32_t max_dialstr, fio_signal_cb_t sig_cb)
+{
+ ftdm_analog_data_t *analog_data;
+ const char *tonemap = "us";
+ const char *hotline = "";
+ uint32_t digit_timeout = 10;
+ uint32_t max_dialstr = MAX_DTMF;
+ const char *var, *val;
+ int *intval;
+ uint32_t flags = FTDM_ANALOG_CALLERID;
+
+ assert(sig_cb != NULL);
+
+ if (span->signal_type) {
+ snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
+ return FTDM_FAIL;
+ }
+
+ analog_data = ftdm_malloc(sizeof(*analog_data));
+ assert(analog_data != NULL);
+ memset(analog_data, 0, sizeof(*analog_data));
+
+ while ((var = va_arg(ap, char *))) {
+ if (!strcasecmp(var, "tonemap")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ tonemap = val;
+ } else if (!strcasecmp(var, "digit_timeout")) {
+ if (!(intval = va_arg(ap, int *))) {
+ break;
+ }
+ digit_timeout = *intval;
+ } else if (!strcasecmp(var, "enable_callerid")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+
+ if (ftdm_true(val)) {
+ flags |= FTDM_ANALOG_CALLERID;
+ } else {
+ flags &= ~FTDM_ANALOG_CALLERID;
+ }
+ } else if (!strcasecmp(var, "max_dialstr")) {
+ if (!(intval = va_arg(ap, int *))) {
+ break;
+ }
+ max_dialstr = *intval;
+ } else if (!strcasecmp(var, "hotline")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ hotline = val;
+ } else {
+ snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+ return FTDM_FAIL;
+ }
+ }
+
+
+ if (digit_timeout < 2000 || digit_timeout > 10000) {
+ digit_timeout = 2000;
+ }
+
+ if ((max_dialstr < 1 && !strlen(hotline)) || max_dialstr > MAX_DTMF) {
+ max_dialstr = MAX_DTMF;
+ }
+
+ span->start = ftdm_analog_start;
+ analog_data->flags = flags;
+ analog_data->digit_timeout = digit_timeout;
+ analog_data->max_dialstr = max_dialstr;
+ span->signal_cb = sig_cb;
+ strncpy(analog_data->hotline, hotline, sizeof(analog_data->hotline));
+ span->signal_type = FTDM_SIGTYPE_ANALOG;
+ span->signal_data = analog_data;
+ span->outgoing_call = span->trunk_type == FTDM_TRUNK_FXS ? analog_fxs_outgoing_call : analog_fxo_outgoing_call;
+ ftdm_span_load_tones(span, tonemap);
+
+ return FTDM_SUCCESS;
+
+}
+
+/**
+ * \brief Retrieves tone generation output to be sent
+ * \param ts Teletone generator
+ * \param map Tone map
+ * \return -1 on error, 0 on success
+ */
+static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+ ftdm_buffer_t *dt_buffer = ts->user_data;
+ int wrote;
+
+ if (!dt_buffer) {
+ return -1;
+ }
+ wrote = teletone_mux_tones(ts, map);
+ ftdm_buffer_write(dt_buffer, ts->buffer, wrote * 2);
+ return 0;
+}
+
+/**
+ * \brief Sends caller id on an analog channel (FSK coded)
+ * \param ftdmchan Channel to send caller id on
+ */
+static void send_caller_id(ftdm_channel_t *ftdmchan)
+{
+ ftdm_fsk_data_state_t fsk_data;
+ uint8_t databuf[1024] = "";
+ char time_str[9];
+ struct tm tm;
+ time_t now;
+ ftdm_mdmf_type_t mt = MDMF_INVALID;
+
+ time(&now);
+#ifdef WIN32
+ _tzset();
+ _localtime64_s(&tm, &now);
+#else
+ localtime_r(&now, &tm);
+#endif
+ strftime(time_str, sizeof(time_str), "%m%d%H%M", &tm);
+
+ ftdm_fsk_data_init(&fsk_data, databuf, sizeof(databuf));
+ ftdm_fsk_data_add_mdmf(&fsk_data, MDMF_DATETIME, (uint8_t *) time_str, 8);
+
+ if (ftdm_strlen_zero(ftdmchan->caller_data.cid_num.digits)) {
+ mt = MDMF_NO_NUM;
+ ftdm_set_string(ftdmchan->caller_data.cid_num.digits, "O");
+ } else if (!strcasecmp(ftdmchan->caller_data.cid_num.digits, "P") || !strcasecmp(ftdmchan->caller_data.cid_num.digits, "O")) {
+ mt = MDMF_NO_NUM;
+ } else {
+ mt = MDMF_PHONE_NUM;
+ }
+ ftdm_fsk_data_add_mdmf(&fsk_data, mt, (uint8_t *) ftdmchan->caller_data.cid_num.digits, (uint8_t)strlen(ftdmchan->caller_data.cid_num.digits));
+
+ if (ftdm_strlen_zero(ftdmchan->caller_data.cid_name)) {
+ mt = MDMF_NO_NAME;
+ ftdm_set_string(ftdmchan->caller_data.cid_name, "O");
+ } else if (!strcasecmp(ftdmchan->caller_data.cid_name, "P") || !strcasecmp(ftdmchan->caller_data.cid_name, "O")) {
+ mt = MDMF_NO_NAME;
+ } else {
+ mt = MDMF_PHONE_NAME;
+ }
+ ftdm_fsk_data_add_mdmf(&fsk_data, mt, (uint8_t *) ftdmchan->caller_data.cid_name, (uint8_t)strlen(ftdmchan->caller_data.cid_name));
+
+ ftdm_fsk_data_add_checksum(&fsk_data);
+ ftdm_channel_send_fsk_data(ftdmchan, &fsk_data, -14);
+}
+
+/**
+ * \brief Main thread function for analog channel (outgoing call)
+ * \param me Current thread
+ * \param obj Channel to run in this thread
+ */
+static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
+{
+ ftdm_channel_t *ftdmchan = (ftdm_channel_t *) obj;
+ ftdm_buffer_t *dt_buffer = NULL;
+ teletone_generation_session_t ts;
+ uint8_t frame[1024];
+ ftdm_size_t len, rlen;
+ ftdm_tone_type_t tt = FTDM_TONE_DTMF;
+ char dtmf[MAX_DTMF+1] = "";
+ ftdm_size_t dtmf_offset = 0;
+ ftdm_analog_data_t *analog_data = ftdmchan->span->signal_data;
+ ftdm_channel_t *closed_chan;
+ uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = 30000;
+ ftdm_sigmsg_t sig;
+ ftdm_status_t status;
+
+ ftdm_log(FTDM_LOG_DEBUG, "ANALOG CHANNEL thread starting.\n");
+
+ ts.buffer = NULL;
+
+ if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "OPEN ERROR [%s]\n", ftdmchan->last_error);
+ goto done;
+ }
+
+ if (ftdm_buffer_create(&dt_buffer, 1024, 3192, 0) != FTDM_SUCCESS) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "memory error!");
+ ftdm_log(FTDM_LOG_ERROR, "MEM ERROR\n");
+ goto done;
+ }
+
+ if (ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_DTMF_DETECT, &tt) != FTDM_SUCCESS) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "error initilizing tone detector!");
+ ftdm_log(FTDM_LOG_ERROR, "TONE ERROR\n");
+ goto done;
+ }
+
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_INTHREAD);
+ teletone_init_session(&ts, 0, teletone_handler, dt_buffer);
+ ts.rate = 8000;
+#if 0
+ ts.debug = 1;
+ ts.debug_stream = stdout;
+#endif
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
+ ftdm_buffer_set_loops(dt_buffer, -1);
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = ftdmchan->chan_id;
+ sig.span_id = ftdmchan->span_id;
+ sig.channel = ftdmchan;
+
+ assert(interval != 0);
+
+ while (ftdm_running() && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
+ ftdm_wait_flag_t flags = FTDM_READ;
+ ftdm_size_t dlen = 0;
+
+ len = sizeof(frame);
+
+ elapsed += interval;
+ state_counter += interval;
+
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
+ switch(ftdmchan->state) {
+ case FTDM_CHANNEL_STATE_GET_CALLERID:
+ {
+ if (state_counter > 5000 || !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT)) {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_CALLERID_DETECT, NULL);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_DIALING:
+ {
+ if (state_counter > dial_timeout) {
+ if (ftdmchan->needed_tones[FTDM_TONEMAP_DIAL]) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+ } else {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
+ }
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_GENRING:
+ {
+ if (state_counter > 60000) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ } else if (!ftdmchan->fsk_buffer || !ftdm_buffer_inuse(ftdmchan->fsk_buffer)) {
+ ftdm_sleep(interval);
+ continue;
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_DIALTONE:
+ {
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_HOLD) && state_counter > 10000) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_BUSY:
+ {
+ if (state_counter > 20000) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_ATTN);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_ATTN:
+ {
+ if (state_counter > 20000) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_HANGUP:
+ {
+ if (state_counter > 500) {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RINGING)) {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_OFF, NULL);
+ }
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) &&
+ (ftdmchan->last_state == FTDM_CHANNEL_STATE_RING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE
+ || ftdmchan->last_state >= FTDM_CHANNEL_STATE_IDLE)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+ } else {
+ ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING;
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ }
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_CALLWAITING:
+ {
+ int done = 0;
+
+ if (ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] == 1) {
+ send_caller_id(ftdmchan);
+ ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]++;
+ } else if (state_counter > 600 && !ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]) {
+ send_caller_id(ftdmchan);
+ ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]++;
+ } else if (state_counter > 1000 && !ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]) {
+ done = 1;
+ } else if (state_counter > 10000) {
+ if (ftdmchan->fsk_buffer) {
+ ftdm_buffer_zero(ftdmchan->fsk_buffer);
+ } else {
+ ftdm_buffer_create(&ftdmchan->fsk_buffer, 128, 128, 0);
+ }
+
+ ts.user_data = ftdmchan->fsk_buffer;
+ teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_CALLWAITING_SAS]);
+ ts.user_data = dt_buffer;
+ done = 1;
+ }
+
+ if (done) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+ ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
+ ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] = 0;
+ }
+ }
+ case FTDM_CHANNEL_STATE_UP:
+ case FTDM_CHANNEL_STATE_IDLE:
+ {
+ ftdm_sleep(interval);
+ continue;
+ }
+ break;
+ case FTDM_CHANNEL_STATE_DOWN:
+ {
+ goto done;
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+ ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
+ ftdm_channel_complete_state(ftdmchan);
+ indicate = 0;
+ state_counter = 0;
+
+ ftdm_log(FTDM_LOG_DEBUG, "Executing state handler on %d:%d for %s\n",
+ ftdmchan->span_id, ftdmchan->chan_id,
+ ftdm_channel_state2str(ftdmchan->state));
+ switch(ftdmchan->state) {
+ case FTDM_CHANNEL_STATE_UP:
+ {
+ ftdm_channel_use(ftdmchan);
+ ftdm_channel_clear_needed_tones(ftdmchan);
+ ftdm_channel_flush_dtmf(ftdmchan);
+
+ if (ftdmchan->type == FTDM_CHAN_TYPE_FXO && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_OFFHOOK, NULL);
+ }
+
+ if (ftdmchan->fsk_buffer && ftdm_buffer_inuse(ftdmchan->fsk_buffer)) {
+ ftdm_log(FTDM_LOG_DEBUG, "Cancel FSK transmit due to early answer.\n");
+ ftdm_buffer_zero(ftdmchan->fsk_buffer);
+ }
+
+ if (ftdmchan->type == FTDM_CHAN_TYPE_FXS && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RINGING)) {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_OFF, NULL);
+ }
+
+ if (ftdmchan->token_count == 1) {
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_HOLD);
+ }
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_HOLD)) {
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_HOLD);
+ sig.event_id = FTDM_SIGEVENT_ADD_CALL;
+ } else {
+ sig.event_id = FTDM_SIGEVENT_UP;
+ }
+
+ ftdm_span_send_signal(ftdmchan->span, &sig);
+ continue;
+ }
+ break;
+ case FTDM_CHANNEL_STATE_DIALING:
+ {
+ ftdm_channel_use(ftdmchan);
+ }
+ break;
+ case FTDM_CHANNEL_STATE_IDLE:
+ {
+ ftdm_channel_use(ftdmchan);
+ sig.event_id = FTDM_SIGEVENT_START;
+
+ if (ftdmchan->type == FTDM_CHAN_TYPE_FXO) {
+ ftdm_set_string(ftdmchan->caller_data.dnis.digits, ftdmchan->chan_number);
+ } else {
+ ftdm_set_string(ftdmchan->caller_data.dnis.digits, dtmf);
+ }
+
+ ftdm_span_send_signal(ftdmchan->span, &sig);
+ continue;
+ }
+ break;
+ case FTDM_CHANNEL_STATE_DOWN:
+ {
+ sig.event_id = FTDM_SIGEVENT_STOP;
+ ftdm_span_send_signal(ftdmchan->span, &sig);
+ goto done;
+ }
+ break;
+ case FTDM_CHANNEL_STATE_DIALTONE:
+ {
+ memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data));
+ *dtmf = '\0';
+ dtmf_offset = 0;
+ ftdm_buffer_zero(dt_buffer);
+ teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_DIAL]);
+ indicate = 1;
+ }
+ break;
+ case FTDM_CHANNEL_STATE_CALLWAITING:
+ {
+ ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] = 0;
+ if (ftdmchan->fsk_buffer) {
+ ftdm_buffer_zero(ftdmchan->fsk_buffer);
+ } else {
+ ftdm_buffer_create(&ftdmchan->fsk_buffer, 128, 128, 0);
+ }
+
+ ts.user_data = ftdmchan->fsk_buffer;
+ teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_CALLWAITING_SAS]);
+ teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_CALLWAITING_CAS]);
+ ts.user_data = dt_buffer;
+ }
+ break;
+ case FTDM_CHANNEL_STATE_GENRING:
+ {
+ ftdm_sigmsg_t sig;
+
+ send_caller_id(ftdmchan);
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_ON, NULL);
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = ftdmchan->chan_id;
+ sig.span_id = ftdmchan->span_id;
+ sig.channel = ftdmchan;
+ sig.event_id = FTDM_SIGEVENT_PROGRESS;
+ ftdm_span_send_signal(ftdmchan->span, &sig);
+
+ }
+ break;
+ case FTDM_CHANNEL_STATE_GET_CALLERID:
+ {
+ memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data));
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_CALLERID_DETECT, NULL);
+ continue;
+ }
+ break;
+ case FTDM_CHANNEL_STATE_RING:
+ {
+ ftdm_buffer_zero(dt_buffer);
+ teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_RING]);
+ indicate = 1;
+
+ }
+ break;
+ case FTDM_CHANNEL_STATE_BUSY:
+ {
+ ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ ftdm_buffer_zero(dt_buffer);
+ teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_BUSY]);
+ indicate = 1;
+ } else {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_ATTN:
+ {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ ftdm_buffer_zero(dt_buffer);
+ teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_ATTN]);
+ indicate = 1;
+ } else {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALTONE || ftdmchan->state == FTDM_CHANNEL_STATE_COLLECT) {
+ if ((dlen = ftdm_channel_dequeue_dtmf(ftdmchan, dtmf + dtmf_offset, sizeof(dtmf) - strlen(dtmf)))) {
+
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALTONE) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
+ collecting = 1;
+ }
+ dtmf_offset = strlen(dtmf);
+ last_digit = elapsed;
+ sig.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT;
+ sig.raw_data = dtmf;
+ if (ftdm_span_send_signal(ftdmchan->span, &sig) == FTDM_BREAK) {
+ collecting = 0;
+ }
+ }
+ else if(!analog_data->max_dialstr)
+ {
+ last_digit = elapsed;
+ collecting = 0;
+ strcpy(dtmf, analog_data->hotline);
+ }
+ }
+
+
+ if (last_digit && (!collecting || ((elapsed - last_digit > analog_data->digit_timeout) || strlen(dtmf) >= analog_data->max_dialstr))) {
+ ftdm_log(FTDM_LOG_DEBUG, "Number obtained [%s]\n", dtmf);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE);
+ last_digit = 0;
+ collecting = 0;
+ }
+
+ if (ftdm_channel_wait(ftdmchan, &flags, interval * 2) != FTDM_SUCCESS) {
+ continue;
+ }
+
+ if (!(flags & FTDM_READ)) {
+ continue;
+ }
+
+ if (ftdm_channel_read(ftdmchan, frame, &len) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "READ ERROR [%s]\n", ftdmchan->last_error);
+ goto done;
+ }
+
+ if (ftdmchan->type == FTDM_CHAN_TYPE_FXO && ftdmchan->detected_tones[0]) {
+ ftdm_sigmsg_t sig;
+ int i;
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = ftdmchan->chan_id;
+ sig.span_id = ftdmchan->span_id;
+ sig.channel = ftdmchan;
+ sig.event_id = FTDM_SIGEVENT_TONE_DETECTED;
+
+ for (i = 1; i < FTDM_TONEMAP_INVALID; i++) {
+ if (ftdmchan->detected_tones[i]) {
+ ftdm_log(FTDM_LOG_DEBUG, "Detected tone %s on %d:%d\n", ftdm_tonemap2str(i), ftdmchan->span_id, ftdmchan->chan_id);
+ sig.raw_data = &i;
+ ftdm_span_send_signal(ftdmchan->span, &sig);
+ }
+ }
+
+ if (ftdmchan->detected_tones[FTDM_TONEMAP_BUSY] ||
+ ftdmchan->detected_tones[FTDM_TONEMAP_FAIL1] ||
+ ftdmchan->detected_tones[FTDM_TONEMAP_FAIL2] ||
+ ftdmchan->detected_tones[FTDM_TONEMAP_FAIL3] ||
+ ftdmchan->detected_tones[FTDM_TONEMAP_ATTN]
+ ) {
+ ftdm_log(FTDM_LOG_ERROR, "Failure indication detected!\n");
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+ } else if (ftdmchan->detected_tones[FTDM_TONEMAP_DIAL]) {
+ if (ftdm_strlen_zero(ftdmchan->caller_data.dnis.digits)) {
+ ftdm_log(FTDM_LOG_ERROR, "No Digits to send!\n");
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+ } else {
+ if (ftdm_channel_command(ftdmchan, FTDM_COMMAND_SEND_DTMF, ftdmchan->caller_data.dnis.digits) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Send Digits Failed [%s]\n", ftdmchan->last_error);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+ } else {
+ state_counter = 0;
+ ftdmchan->needed_tones[FTDM_TONEMAP_RING] = 1;
+ ftdmchan->needed_tones[FTDM_TONEMAP_BUSY] = 1;
+ ftdmchan->needed_tones[FTDM_TONEMAP_FAIL1] = 1;
+ ftdmchan->needed_tones[FTDM_TONEMAP_FAIL2] = 1;
+ ftdmchan->needed_tones[FTDM_TONEMAP_FAIL3] = 1;
+ dial_timeout = ((ftdmchan->dtmf_on + ftdmchan->dtmf_off) * strlen(ftdmchan->caller_data.dnis.digits)) + 2000;
+ }
+ }
+ } else if (ftdmchan->detected_tones[FTDM_TONEMAP_RING]) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
+ }
+
+ ftdm_channel_clear_detected_tones(ftdmchan);
+ }
+
+ if ((ftdmchan->dtmf_buffer && ftdm_buffer_inuse(ftdmchan->dtmf_buffer)) || (ftdmchan->fsk_buffer && ftdm_buffer_inuse(ftdmchan->fsk_buffer))) {
+ //rlen = len;
+ //memset(frame, 0, len);
+ //ftdm_channel_write(ftdmchan, frame, sizeof(frame), &rlen);
+ continue;
+ }
+
+ if (!indicate) {
+ continue;
+ }
+
+ if (ftdmchan->type == FTDM_CHAN_TYPE_FXO && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_OFFHOOK, NULL);
+ }
+
+ if (ftdmchan->effective_codec != FTDM_CODEC_SLIN) {
+ len *= 2;
+ }
+
+ rlen = ftdm_buffer_read_loop(dt_buffer, frame, len);
+
+ if (ftdmchan->effective_codec != FTDM_CODEC_SLIN) {
+ fio_codec_t codec_func = NULL;
+
+ if (ftdmchan->native_codec == FTDM_CODEC_ULAW) {
+ codec_func = fio_slin2ulaw;
+ } else if (ftdmchan->native_codec == FTDM_CODEC_ALAW) {
+ codec_func = fio_slin2alaw;
+ }
+
+ if (codec_func) {
+ status = codec_func(frame, sizeof(frame), &rlen);
+ } else {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "codec error!");
+ goto done;
+ }
+ }
+
+ ftdm_channel_write(ftdmchan, frame, sizeof(frame), &rlen);
+ }
+
+ done:
+
+
+ if (ftdmchan->type == FTDM_CHAN_TYPE_FXO && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL);
+ }
+
+ if (ftdmchan->type == FTDM_CHAN_TYPE_FXS && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RINGING)) {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_OFF, NULL);
+ }
+
+
+ closed_chan = ftdmchan;
+ ftdm_channel_close(&ftdmchan);
+
+ ftdm_channel_command(closed_chan, FTDM_COMMAND_SET_NATIVE_CODEC, NULL);
+
+ if (ts.buffer) {
+ teletone_destroy_session(&ts);
+ }
+
+ if (dt_buffer) {
+ ftdm_buffer_destroy(&dt_buffer);
+ }
+
+ if (closed_chan->state != FTDM_CHANNEL_STATE_DOWN) {
+ ftdm_set_state_locked(closed_chan, FTDM_CHANNEL_STATE_DOWN);
+ }
+
+ ftdm_log(FTDM_LOG_DEBUG, "ANALOG CHANNEL %d:%d thread ended.\n", closed_chan->span_id, closed_chan->chan_id);
+ ftdm_clear_flag(closed_chan, FTDM_CHANNEL_INTHREAD);
+
+ return NULL;
+}
+
+/**
+ * \brief Processes freetdm event
+ * \param span Span on which the event was fired
+ * \param event Event to be treated
+ * \return Success or failure
+ */
+static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *event)
+{
+ ftdm_sigmsg_t sig;
+ ftdm_analog_data_t *analog_data = event->channel->span->signal_data;
+ int locked = 0;
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = event->channel->chan_id;
+ sig.span_id = event->channel->span_id;
+ sig.channel = event->channel;
+
+
+ ftdm_log(FTDM_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n",
+ ftdm_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, ftdm_channel_state2str(event->channel->state));
+
+ ftdm_mutex_lock(event->channel->mutex);
+ locked++;
+
+ switch(event->enum_id) {
+ case FTDM_OOB_RING_START:
+ {
+ if (event->channel->type != FTDM_CHAN_TYPE_FXO) {
+ ftdm_log(FTDM_LOG_ERROR, "Cannot get a RING_START event on a non-fxo channel, please check your config.\n");
+ ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
+ goto end;
+ }
+ if (!event->channel->ring_count && (event->channel->state == FTDM_CHANNEL_STATE_DOWN && !ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD))) {
+ if (ftdm_test_flag(analog_data, FTDM_ANALOG_CALLERID)) {
+ ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_GET_CALLERID);
+ } else {
+ ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_IDLE);
+ }
+ event->channel->ring_count = 1;
+ ftdm_mutex_unlock(event->channel->mutex);
+ locked = 0;
+ ftdm_thread_create_detached(ftdm_analog_channel_run, event->channel);
+ } else {
+ event->channel->ring_count++;
+ }
+ }
+ break;
+ case FTDM_OOB_ONHOOK:
+ {
+ if (ftdm_test_flag(event->channel, FTDM_CHANNEL_RINGING)) {
+ ftdm_channel_command(event->channel, FTDM_COMMAND_GENERATE_RING_OFF, NULL);
+ }
+
+ if (event->channel->state != FTDM_CHANNEL_STATE_DOWN) {
+ ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
+ }
+
+ }
+ break;
+ case FTDM_OOB_FLASH:
+ {
+ if (event->channel->state == FTDM_CHANNEL_STATE_CALLWAITING) {
+ ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
+ ftdm_clear_flag_locked(event->channel, FTDM_CHANNEL_STATE_CHANGE);
+ ftdm_clear_flag_locked(event->channel->span, FTDM_SPAN_STATE_CHANGE);
+ event->channel->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] = 0;
+ }
+
+ ftdm_channel_rotate_tokens(event->channel);
+
+ if (ftdm_test_flag(event->channel, FTDM_CHANNEL_HOLD) && event->channel->token_count != 1) {
+ ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
+ } else {
+ sig.event_id = FTDM_SIGEVENT_FLASH;
+ ftdm_span_send_signal(span, &sig);
+ }
+ }
+ break;
+ case FTDM_OOB_OFFHOOK:
+ {
+ if (event->channel->type == FTDM_CHAN_TYPE_FXS) {
+ if (ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD)) {
+ if (ftdm_test_flag(event->channel, FTDM_CHANNEL_RINGING)) {
+ ftdm_channel_command(event->channel, FTDM_COMMAND_GENERATE_RING_OFF, NULL);
+ }
+ ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
+ } else {
+ if(!analog_data->max_dialstr) {
+ ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_COLLECT);
+ } else {
+ ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DIALTONE);
+ }
+ ftdm_mutex_unlock(event->channel->mutex);
+ locked = 0;
+ ftdm_thread_create_detached(ftdm_analog_channel_run, event->channel);
+ }
+ } else {
+ if (!ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD)) {
+ if (ftdm_test_flag(event->channel, FTDM_CHANNEL_OFFHOOK)) {
+ ftdm_channel_command(event->channel, FTDM_COMMAND_ONHOOK, NULL);
+ }
+ }
+ ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
+ }
+ }
+ }
+
+ end:
+
+ if (locked) {
+ ftdm_mutex_unlock(event->channel->mutex);
+ }
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Main thread function for analog span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *ftdm_analog_run(ftdm_thread_t *me, void *obj)
+{
+ ftdm_span_t *span = (ftdm_span_t *) obj;
+ ftdm_analog_data_t *analog_data = span->signal_data;
+ int errs = 0;
+
+ ftdm_log(FTDM_LOG_DEBUG, "ANALOG thread starting.\n");
+
+ while(ftdm_running() && ftdm_test_flag(analog_data, FTDM_ANALOG_RUNNING)) {
+ int waitms = 1000;
+ ftdm_status_t status;
+
+ if ((status = ftdm_span_poll_event(span, waitms)) != FTDM_FAIL) {
+ errs = 0;
+ }
+
+ switch(status) {
+ case FTDM_SUCCESS:
+ {
+ ftdm_event_t *event;
+ while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
+ if (event->enum_id == FTDM_OOB_NOOP) {
+ continue;
+ }
+ if (process_event(span, event) != FTDM_SUCCESS) {
+ goto end;
+ }
+ }
+ }
+ break;
+ case FTDM_FAIL:
+ {
+ ftdm_log(FTDM_LOG_ERROR, "Failure Polling event! [%s]\n", span->last_error);
+ if (++errs > 300) {
+ ftdm_log(FTDM_LOG_CRIT, "Too Many Errors!\n");
+ goto end;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ end:
+
+ ftdm_clear_flag(analog_data, FTDM_ANALOG_RUNNING);
+
+ ftdm_log(FTDM_LOG_DEBUG, "ANALOG thread ending.\n");
+
+ return NULL;
+}
+
+/**
+ * \brief FreeTDM analog signaling module initialisation
+ * \return Success
+ */
+static FIO_SIG_LOAD_FUNCTION(ftdm_analog_init)
+{
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief FreeTDM analog signaling module definition
+ */
+EX_DECLARE_DATA ftdm_module_t ftdm_module = {
+ "analog",
+ NULL,
+ NULL,
+ ftdm_analog_init,
+ ftdm_analog_configure_span,
+ NULL
+};
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ozmod_analog.2005.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ozmod_analog.2005.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ozmod_analog.2005.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ftmod_analog"
+ ProjectGUID="{37C94798-6E33-4B4F-8EE0-C72A7DC91157}"
+ RootNamespace="ftmod_analog"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="ftmod_analog.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="ftdm_analog.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2008, Anthony Minessale II
+ * 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.
+ *
+ * Contributor(s):
+ *
+ * John Wehle (john@feith.com)
+ *
+ */
+
+#ifndef FTDM_ANALOG_EM_H
+#define FTDM_ANALOG_EM_H
+#include "freetdm.h"
+
+#define MAX_DIALSTRING 256
+
+typedef enum {
+ FTDM_ANALOG_EM_RUNNING = (1 << 0)
+} ftdm_analog_em_flag_t;
+
+
+struct ftdm_analog_data {
+ uint32_t flags;
+ uint32_t max_dialstr;
+ uint32_t digit_timeout;
+};
+
+static void *ftdm_analog_em_run(ftdm_thread_t *me, void *obj);
+typedef struct ftdm_analog_data ftdm_analog_em_data_t;
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,353 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="ftmod_analog_em"
+ ProjectGUID="{B3F49375-2834-4937-9D8C-4AC2EC911010}"
+ RootNamespace="ftmod_analog_em"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="ftmod_analog_em.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="ftdm_analog_em.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,707 @@
+/*
+ * Copyright (c) 2008, Anthony Minessale II
+ * 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.
+ *
+ * Contributor(s):
+ *
+ * John Wehle (john@feith.com)
+ *
+ */
+
+#include "freetdm.h"
+#include "ftdm_analog_em.h"
+
+#ifndef localtime_r
+struct tm * localtime_r(const time_t *clock, struct tm *result);
+#endif
+
+static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj);
+
+/**
+ * \brief Starts an EM channel thread (outgoing call)
+ * \param ftdmchan Channel to initiate call on
+ * \return Success or failure
+ *
+ * Initialises state, starts tone progress detection and runs the channel in a new a thread.
+ */
+static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_em_outgoing_call)
+{
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
+ ftdm_channel_clear_needed_tones(ftdmchan);
+ ftdm_channel_clear_detected_tones(ftdmchan);
+
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
+
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_OFFHOOK, NULL);
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_PROGRESS_DETECT, NULL);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
+ ftdm_thread_create_detached(ftdm_analog_em_channel_run, ftdmchan);
+ return FTDM_SUCCESS;
+ }
+
+ return FTDM_FAIL;
+}
+
+/**
+ * \brief Starts an EM span thread (monitor)
+ * \param span Span to monitor
+ * \return Success or failure
+ */
+static ftdm_status_t ftdm_analog_em_start(ftdm_span_t *span)
+{
+ ftdm_analog_em_data_t *analog_data = span->signal_data;
+ ftdm_set_flag(analog_data, FTDM_ANALOG_EM_RUNNING);
+ return ftdm_thread_create_detached(ftdm_analog_em_run, span);
+}
+
+/**
+ * \brief Initialises an EM span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span)
+//ftdm_status_t ftdm_analog_em_configure_span(ftdm_span_t *span, char *tonemap, uint32_t digit_timeout, uint32_t max_dialstr, fio_signal_cb_t sig_cb)
+{
+ ftdm_analog_em_data_t *analog_data;
+ const char *tonemap = "us";
+ uint32_t digit_timeout = 10;
+ uint32_t max_dialstr = 11;
+ const char *var, *val;
+ int *intval;
+
+ assert(sig_cb != NULL);
+
+ if (span->signal_type) {
+ snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
+ return FTDM_FAIL;
+ }
+
+ analog_data = ftdm_malloc(sizeof(*analog_data));
+ assert(analog_data != NULL);
+ memset(analog_data, 0, sizeof(*analog_data));
+
+ while((var = va_arg(ap, char *))) {
+ if (!strcasecmp(var, "tonemap")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ tonemap = val;
+ } else if (!strcasecmp(var, "digit_timeout")) {
+ if (!(intval = va_arg(ap, int *))) {
+ break;
+ }
+ digit_timeout = *intval;
+ } else if (!strcasecmp(var, "max_dialstr")) {
+ if (!(intval = va_arg(ap, int *))) {
+ break;
+ }
+ max_dialstr = *intval;
+ } else {
+ snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+ return FTDM_FAIL;
+ }
+ }
+
+
+ if (digit_timeout < 2000 || digit_timeout > 10000) {
+ digit_timeout = 2000;
+ }
+
+ if (max_dialstr < 2 || max_dialstr > MAX_DIALSTRING) {
+ ftdm_log(FTDM_LOG_ERROR, "Invalid max_dialstr, setting to %d\n", MAX_DIALSTRING);
+ max_dialstr = MAX_DIALSTRING;
+ }
+
+ span->start = ftdm_analog_em_start;
+ analog_data->digit_timeout = digit_timeout;
+ analog_data->max_dialstr = max_dialstr;
+ span->signal_cb = sig_cb;
+ span->signal_type = FTDM_SIGTYPE_ANALOG;
+ span->signal_data = analog_data;
+ span->outgoing_call = analog_em_outgoing_call;
+ ftdm_span_load_tones(span, tonemap);
+
+ return FTDM_SUCCESS;
+
+}
+
+/**
+ * \brief Retrieves tone generation output to be sent
+ * \param ts Teletone generator
+ * \param map Tone map
+ * \return -1 on error, 0 on success
+ */
+static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+ ftdm_buffer_t *dt_buffer = ts->user_data;
+ int wrote;
+
+ if (!dt_buffer) {
+ return -1;
+ }
+ wrote = teletone_mux_tones(ts, map);
+ ftdm_buffer_write(dt_buffer, ts->buffer, wrote * 2);
+ return 0;
+}
+
+/**
+ * \brief Main thread function for EM channel (outgoing call)
+ * \param me Current thread
+ * \param obj Channel to run in this thread
+ */
+static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
+{
+ ftdm_channel_t *ftdmchan = (ftdm_channel_t *) obj;
+ ftdm_buffer_t *dt_buffer = NULL;
+ teletone_generation_session_t ts;
+ uint8_t frame[1024];
+ ftdm_size_t len, rlen;
+ ftdm_tone_type_t tt = FTDM_TONE_DTMF;
+ char dtmf[128] = "";
+ ftdm_size_t dtmf_offset = 0;
+ ftdm_analog_em_data_t *analog_data = ftdmchan->span->signal_data;
+ ftdm_channel_t *closed_chan;
+ uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = 30000;
+ ftdm_sigmsg_t sig;
+ ftdm_status_t status;
+
+ ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM CHANNEL thread starting.\n");
+
+ ts.buffer = NULL;
+
+ if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "OPEN ERROR [%s]\n", ftdmchan->last_error);
+ goto done;
+ }
+
+ if (ftdm_buffer_create(&dt_buffer, 1024, 3192, 0) != FTDM_SUCCESS) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "memory error!");
+ ftdm_log(FTDM_LOG_ERROR, "MEM ERROR\n");
+ goto done;
+ }
+
+ if (ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_DTMF_DETECT, &tt) != FTDM_SUCCESS) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "error initilizing tone detector!");
+ ftdm_log(FTDM_LOG_ERROR, "TONE ERROR\n");
+ goto done;
+ }
+
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_INTHREAD);
+ teletone_init_session(&ts, 0, teletone_handler, dt_buffer);
+ ts.rate = 8000;
+#if 0
+ ts.debug = 1;
+ ts.debug_stream = stdout;
+#endif
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
+ ftdm_buffer_set_loops(dt_buffer, -1);
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = ftdmchan->chan_id;
+ sig.span_id = ftdmchan->span_id;
+ sig.channel = ftdmchan;
+
+ assert(interval != 0);
+
+ while (ftdm_running() && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
+ ftdm_wait_flag_t flags = FTDM_READ;
+ ftdm_size_t dlen = 0;
+
+ len = sizeof(frame);
+
+ elapsed += interval;
+ state_counter += interval;
+
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
+ switch(ftdmchan->state) {
+ case FTDM_CHANNEL_STATE_DIALING:
+ {
+ if (! ftdmchan->needed_tones[FTDM_TONEMAP_RING]
+ && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) {
+ if (ftdm_strlen_zero(ftdmchan->caller_data.dnis.digits)) {
+ ftdm_log(FTDM_LOG_ERROR, "No Digits to send!\n");
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+ } else {
+ if (ftdm_channel_command(ftdmchan, FTDM_COMMAND_SEND_DTMF, ftdmchan->caller_data.dnis.digits) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Send Digits Failed [%s]\n", ftdmchan->last_error);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+ } else {
+ state_counter = 0;
+ ftdmchan->needed_tones[FTDM_TONEMAP_RING] = 1;
+ ftdmchan->needed_tones[FTDM_TONEMAP_BUSY] = 1;
+ ftdmchan->needed_tones[FTDM_TONEMAP_FAIL1] = 1;
+ ftdmchan->needed_tones[FTDM_TONEMAP_FAIL2] = 1;
+ ftdmchan->needed_tones[FTDM_TONEMAP_FAIL3] = 1;
+ dial_timeout = ((ftdmchan->dtmf_on + ftdmchan->dtmf_off) * strlen(ftdmchan->caller_data.dnis.digits)) + 2000;
+ }
+ }
+ break;
+ }
+ if (state_counter > dial_timeout) {
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+ } else {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
+ }
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_DIALTONE:
+ {
+ if (state_counter > 10000) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_BUSY:
+ {
+ if (state_counter > 20000) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_ATTN);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_ATTN:
+ {
+ if (state_counter > 20000) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_HANGUP:
+ {
+ if (state_counter > 500) {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) &&
+ (ftdmchan->last_state == FTDM_CHANNEL_STATE_RING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE
+ || ftdmchan->last_state >= FTDM_CHANNEL_STATE_IDLE)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+ } else {
+ ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING;
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ }
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_UP:
+ case FTDM_CHANNEL_STATE_IDLE:
+ {
+ ftdm_sleep(interval);
+ continue;
+ }
+ break;
+ case FTDM_CHANNEL_STATE_DOWN:
+ {
+ goto done;
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+ ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
+ ftdm_channel_complete_state(ftdmchan);
+ indicate = 0;
+ state_counter = 0;
+
+ ftdm_log(FTDM_LOG_DEBUG, "Executing state handler on %d:%d for %s\n",
+ ftdmchan->span_id, ftdmchan->chan_id,
+ ftdm_channel_state2str(ftdmchan->state));
+ switch(ftdmchan->state) {
+ case FTDM_CHANNEL_STATE_UP:
+ {
+ ftdm_channel_use(ftdmchan);
+ ftdm_channel_clear_needed_tones(ftdmchan);
+ ftdm_channel_flush_dtmf(ftdmchan);
+
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_OFFHOOK, NULL);
+ }
+
+ sig.event_id = FTDM_SIGEVENT_UP;
+
+ ftdm_span_send_signal(ftdmchan->span, &sig);
+ continue;
+ }
+ break;
+ case FTDM_CHANNEL_STATE_DIALING:
+ {
+ ftdm_channel_use(ftdmchan);
+ }
+ break;
+ case FTDM_CHANNEL_STATE_IDLE:
+ {
+ ftdm_channel_use(ftdmchan);
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ ftdm_set_string(ftdmchan->caller_data.dnis.digits, ftdmchan->chan_number);
+ } else {
+ ftdm_set_string(ftdmchan->caller_data.dnis.digits, dtmf);
+ }
+
+ sig.event_id = FTDM_SIGEVENT_START;
+
+ ftdm_span_send_signal(ftdmchan->span, &sig);
+ continue;
+ }
+ break;
+ case FTDM_CHANNEL_STATE_DOWN:
+ {
+ sig.event_id = FTDM_SIGEVENT_STOP;
+ ftdm_span_send_signal(ftdmchan->span, &sig);
+ goto done;
+ }
+ break;
+ case FTDM_CHANNEL_STATE_DIALTONE:
+ {
+ memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data));
+ *dtmf = '\0';
+ dtmf_offset = 0;
+ ftdm_buffer_zero(dt_buffer);
+ teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_DIAL]);
+ indicate = 1;
+
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_WINK, NULL);
+ }
+ break;
+ case FTDM_CHANNEL_STATE_RING:
+ {
+ ftdm_buffer_zero(dt_buffer);
+ teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_RING]);
+ indicate = 1;
+ }
+ break;
+ case FTDM_CHANNEL_STATE_BUSY:
+ {
+ ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ ftdm_buffer_zero(dt_buffer);
+ teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_BUSY]);
+ indicate = 1;
+ } else {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_ATTN:
+ {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ ftdm_buffer_zero(dt_buffer);
+ teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_ATTN]);
+ indicate = 1;
+ } else {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALTONE || ftdmchan->state == FTDM_CHANNEL_STATE_COLLECT) {
+ if ((dlen = ftdm_channel_dequeue_dtmf(ftdmchan, dtmf + dtmf_offset, sizeof(dtmf) - strlen(dtmf)))) {
+
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALTONE) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
+ collecting = 1;
+ }
+ dtmf_offset = strlen(dtmf);
+ last_digit = elapsed;
+ sig.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT;
+ sig.raw_data = dtmf;
+ if (ftdm_span_send_signal(ftdmchan->span, &sig) == FTDM_BREAK) {
+ collecting = 0;
+ }
+ }
+ }
+
+
+ if (last_digit && (!collecting || ((elapsed - last_digit > analog_data->digit_timeout) || strlen(dtmf) > analog_data->max_dialstr))) {
+ ftdm_log(FTDM_LOG_DEBUG, "Number obtained [%s]\n", dtmf);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE);
+ last_digit = 0;
+ collecting = 0;
+ }
+
+ if (ftdm_channel_wait(ftdmchan, &flags, interval * 2) != FTDM_SUCCESS) {
+ continue;
+ }
+
+ if (!(flags & FTDM_READ)) {
+ continue;
+ }
+
+ if (ftdm_channel_read(ftdmchan, frame, &len) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "READ ERROR [%s]\n", ftdmchan->last_error);
+ goto done;
+ }
+
+ if (ftdmchan->detected_tones[0]) {
+ ftdm_sigmsg_t sig;
+ int i;
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = ftdmchan->chan_id;
+ sig.span_id = ftdmchan->span_id;
+ sig.channel = ftdmchan;
+ sig.event_id = FTDM_SIGEVENT_TONE_DETECTED;
+
+ for (i = 1; i < FTDM_TONEMAP_INVALID; i++) {
+ if (ftdmchan->detected_tones[i]) {
+ ftdm_log(FTDM_LOG_DEBUG, "Detected tone %s on %d:%d\n", ftdm_tonemap2str(i), ftdmchan->span_id, ftdmchan->chan_id);
+ sig.raw_data = &i;
+ ftdm_span_send_signal(ftdmchan->span, &sig);
+ }
+ }
+
+ if (ftdmchan->detected_tones[FTDM_TONEMAP_BUSY] ||
+ ftdmchan->detected_tones[FTDM_TONEMAP_FAIL1] ||
+ ftdmchan->detected_tones[FTDM_TONEMAP_FAIL2] ||
+ ftdmchan->detected_tones[FTDM_TONEMAP_FAIL3] ||
+ ftdmchan->detected_tones[FTDM_TONEMAP_ATTN]
+ ) {
+ ftdm_log(FTDM_LOG_ERROR, "Failure indication detected!\n");
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+ } else if (ftdmchan->detected_tones[FTDM_TONEMAP_RING]) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
+ }
+
+ ftdm_channel_clear_detected_tones(ftdmchan);
+ }
+
+ if ((ftdmchan->dtmf_buffer && ftdm_buffer_inuse(ftdmchan->dtmf_buffer))) {
+ rlen = len;
+ memset(frame, 0, len);
+ ftdm_channel_write(ftdmchan, frame, sizeof(frame), &rlen);
+ continue;
+ }
+
+ if (!indicate) {
+ continue;
+ }
+
+ if (ftdmchan->effective_codec != FTDM_CODEC_SLIN) {
+ len *= 2;
+ }
+
+ rlen = ftdm_buffer_read_loop(dt_buffer, frame, len);
+
+ if (ftdmchan->effective_codec != FTDM_CODEC_SLIN) {
+ fio_codec_t codec_func = NULL;
+
+ if (ftdmchan->native_codec == FTDM_CODEC_ULAW) {
+ codec_func = fio_slin2ulaw;
+ } else if (ftdmchan->native_codec == FTDM_CODEC_ALAW) {
+ codec_func = fio_slin2alaw;
+ }
+
+ if (codec_func) {
+ status = codec_func(frame, sizeof(frame), &rlen);
+ } else {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "codec error!");
+ goto done;
+ }
+ }
+
+ ftdm_channel_write(ftdmchan, frame, sizeof(frame), &rlen);
+ }
+
+ done:
+
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL);
+
+ closed_chan = ftdmchan;
+ ftdm_channel_close(&ftdmchan);
+
+ ftdm_channel_command(closed_chan, FTDM_COMMAND_SET_NATIVE_CODEC, NULL);
+
+ if (ts.buffer) {
+ teletone_destroy_session(&ts);
+ }
+
+ if (dt_buffer) {
+ ftdm_buffer_destroy(&dt_buffer);
+ }
+
+ ftdm_clear_flag(closed_chan, FTDM_CHANNEL_INTHREAD);
+
+ ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM CHANNEL thread ended.\n");
+
+ return NULL;
+}
+
+/**
+ * \brief Processes EM events coming from ftdmtel/dahdi
+ * \param span Span on which the event was fired
+ * \param event Event to be treated
+ * \return Success or failure
+ */
+static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *event)
+{
+ ftdm_sigmsg_t sig;
+ int locked = 0;
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = event->channel->chan_id;
+ sig.span_id = event->channel->span_id;
+ sig.channel = event->channel;
+
+
+ ftdm_log(FTDM_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n",
+ ftdm_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, ftdm_channel_state2str(event->channel->state));
+
+ ftdm_mutex_lock(event->channel->mutex);
+ locked++;
+
+ switch(event->enum_id) {
+ case FTDM_OOB_ONHOOK:
+ {
+ if (event->channel->state != FTDM_CHANNEL_STATE_DOWN) {
+ ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
+ }
+
+ }
+ break;
+ case FTDM_OOB_OFFHOOK:
+ {
+ if (ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD)) {
+ ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
+ } else {
+ ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DIALTONE);
+ ftdm_mutex_unlock(event->channel->mutex);
+ locked = 0;
+ ftdm_thread_create_detached(ftdm_analog_em_channel_run, event->channel);
+ }
+ break;
+ }
+ case FTDM_OOB_WINK:
+ {
+ if (event->channel->state != FTDM_CHANNEL_STATE_DIALING) {
+ ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
+ } else {
+ ftdm_set_flag_locked(event->channel, FTDM_CHANNEL_WINK);
+ }
+
+ }
+ break;
+ }
+ if (locked) {
+ ftdm_mutex_unlock(event->channel->mutex);
+ }
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Main thread function for EM span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *ftdm_analog_em_run(ftdm_thread_t *me, void *obj)
+{
+ ftdm_span_t *span = (ftdm_span_t *) obj;
+ ftdm_analog_em_data_t *analog_data = span->signal_data;
+
+ ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM thread starting.\n");
+
+ while(ftdm_running() && ftdm_test_flag(analog_data, FTDM_ANALOG_EM_RUNNING)) {
+ int waitms = 10;
+ ftdm_status_t status;
+
+ status = ftdm_span_poll_event(span, waitms);
+
+ switch(status) {
+ case FTDM_SUCCESS:
+ {
+ ftdm_event_t *event;
+ while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
+ if (event->enum_id == FTDM_OOB_NOOP) {
+ continue;
+ }
+ if (process_event(span, event) != FTDM_SUCCESS) {
+ goto end;
+ }
+ }
+ }
+ break;
+ case FTDM_FAIL:
+ {
+ ftdm_log(FTDM_LOG_ERROR, "Failure Polling event! [%s]\n", span->last_error);
+ }
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ end:
+
+ ftdm_clear_flag(analog_data, FTDM_ANALOG_EM_RUNNING);
+
+ ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM thread ending.\n");
+
+ return NULL;
+}
+
+/**
+ * \brief FreeTDM analog EM module initialisation
+ * \return Success
+ */
+static FIO_SIG_LOAD_FUNCTION(ftdm_analog_em_init)
+{
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief FreeTDM analog EM module definition
+ */
+EX_DECLARE_DATA ftdm_module_t ftdm_module = {
+ "analog_em",
+ NULL,
+ NULL,
+ ftdm_analog_em_init,
+ ftdm_analog_em_configure_span,
+ NULL
+};
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ozmod_analog_em.2005.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ozmod_analog_em.2005.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ozmod_analog_em.2005.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ftmod_analog_em"
+ ProjectGUID="{C539D7C8-26A8-4A94-B938-77672165C130}"
+ RootNamespace="ftmod_analog_em"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="ftmod_analog_em.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="ftdm_analog_em.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftdm_isdn.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftdm_isdn.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftdm_isdn.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#ifndef FTDM_ISDN_H
+#define FTDM_ISDN_H
+#include "freetdm.h"
+
+#define DEFAULT_DIGIT_TIMEOUT 10000 /* default overlap timeout: 10 seconds */
+
+
+typedef enum {
+ FTDM_ISDN_OPT_NONE = 0,
+ FTDM_ISDN_OPT_SUGGEST_CHANNEL = (1 << 0),
+ FTDM_ISDN_OPT_OMIT_DISPLAY_IE = (1 << 1), /*!< Do not send Caller name in outgoing SETUP message (= Display IE) */
+ FTDM_ISDN_OPT_DISABLE_TONES = (1 << 2), /*!< Disable tone generating thread (NT mode) */
+
+ FTDM_ISDN_OPT_MAX = (2 << 0)
+} ftdm_isdn_opts_t;
+
+typedef enum {
+ FTDM_ISDN_RUNNING = (1 << 0),
+ FTDM_ISDN_TONES_RUNNING = (1 << 1),
+ FTDM_ISDN_STOP = (1 << 2)
+} ftdm_isdn_flag_t;
+
+
+struct ftdm_isdn_data {
+ Q921Data_t q921;
+ Q931_TrunkInfo_t q931;
+ ftdm_channel_t *dchan;
+ ftdm_channel_t *dchans[2];
+ struct ftdm_sigmsg sigmsg;
+ uint32_t flags;
+ int32_t mode;
+ int32_t digit_timeout;
+ ftdm_isdn_opts_t opts;
+ ftdm_caller_data_t *outbound_crv[32768];
+ ftdm_channel_t *channels_local_crv[32768];
+ ftdm_channel_t *channels_remote_crv[32768];
+};
+
+typedef struct ftdm_isdn_data ftdm_isdn_data_t;
+
+
+/* b-channel private data */
+struct ftdm_isdn_bchan_data
+{
+ L2ULONG digit_timeout;
+};
+
+typedef struct ftdm_isdn_bchan_data ftdm_isdn_bchan_data_t;
+
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,465 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="ftmod_isdn"
+ ProjectGUID="{729344A5-D5E9-434D-8EE8-AF8C6C795D15}"
+ RootNamespace="ftmod_isdn"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\isdn\5ESSmes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\5ESSStateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\5ESSStateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\DMSmes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\DMSStateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\DMSStateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\EuroISDNStateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\EuroISDNStateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\mfifo.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\nationalmes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\nationalStateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\nationalStateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="ftmod_isdn.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q921.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931api.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931ie.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931mes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931StateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931StateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q932mes.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\isdn\include\5ESS.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\DMS.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\mfifo.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\national.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q921.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q921priv.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q931.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q931ie.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q932.h"
+ >
+ </File>
+ <File
+ RelativePath="ftdm_isdn.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,2420 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+/**
+ * Workaround for missing u_int / u_short types on solaris
+ */
+#if defined(HAVE_LIBPCAP) && defined(__SunOS)
+#define __EXTENSIONS__
+#endif
+
+#include "freetdm.h"
+#include "Q931.h"
+#include "Q921.h"
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <sys/time.h>
+#endif
+
+#include "ftdm_isdn.h"
+
+#define LINE "--------------------------------------------------------------------------------"
+//#define IODEBUG
+
+/* helper macros */
+#define FTDM_SPAN_IS_BRI(x) ((x)->trunk_type == FTDM_TRUNK_BRI || (x)->trunk_type == FTDM_TRUNK_BRI_PTMP)
+#define FTDM_SPAN_IS_NT(x) (((ftdm_isdn_data_t *)(x)->signal_data)->mode == Q921_NT)
+
+
+#ifdef HAVE_LIBPCAP
+/*-------------------------------------------------------------------------*/
+/*Q931ToPcap functions*/
+#include <pcap.h>
+#endif
+
+#define SNAPLEN 1522
+#define MAX_ETHER_PAYLOAD_SIZE 1500
+#define MIN_ETHER_PAYLOAD_SIZE 42
+#define SIZE_ETHERNET 18
+#define VLANID_OFFSET 15
+#define SIZE_IP 20
+#define SIZE_TCP 20
+#define SIZE_TPKT 4
+#define SIZE_ETHERNET_CRC 4
+#define OVERHEAD SIZE_ETHERNET+SIZE_IP+SIZE_TCP+SIZE_TPKT
+#define MAX_Q931_SIZE MAX_ETHER_PAYLOAD_SIZE-SIZE_IP-SIZE_TCP-SIZE_TPKT
+#define TPKT_SIZE_OFFSET SIZE_ETHERNET+SIZE_IP+SIZE_TCP+2
+#define IP_SIZE_OFFSET SIZE_ETHERNET+2
+#define TCP_SEQ_OFFSET SIZE_ETHERNET+SIZE_IP+4
+
+#ifdef HAVE_LIBPCAP
+/*Some globals*/
+unsigned long pcapfilesize = 0;
+unsigned long tcp_next_seq_no_send = 0;
+unsigned long tcp_next_seq_no_rec = 0;
+pcap_dumper_t *pcapfile = NULL;
+struct pcap_pkthdr pcaphdr;
+pcap_t *pcaphandle = NULL;
+char *pcapfn = NULL;
+int do_q931ToPcap= 0;
+
+/*Predefined Ethernet Frame with Q931-over-IP encapsulated - From remote TDM host to FreeSWITCH*/
+L3UCHAR recFrame[SNAPLEN]= {
+ /*IEEE 802.3 VLAN 802.1q Ethernet Frame Header*/
+ 2,0,1,0xAA,0xAA,0xAA,2,0,1,0xBB,0xBB,0xBB,0x81,0,0xE0,0,0x08,0,
+ /*IPv4 Header (minimal size; no options)*/
+ 0x45,0,0,44,0,0,0,0,64,6,0,0,2,2,2,2,1,1,1,1,
+ /*TCP-Header*/
+ 0,0x66,0,0x66,0,0,0,0,0,0,0,0,0x50,0,0,1,0,0,0,0,
+ /*TPKT-Header RFC 1006*/
+ 3,0,0,0
+ };
+
+/*Predefined Ethernet Frame with Q931-over-IP encapsulated - Frome FreeSWITCH to remote TDM host*/
+L3UCHAR sendFrame[SNAPLEN]= {
+ /*IEEE 802.3 VLAN 802.1q Ethernet Frame Header*/
+ 2,0,1,0xBB,0xBB,0xBB,2,0,1,0xAA,0xAA,0xAA,0x81,0,0xE0,0,0x08,0,
+ /*IPv4 Header (minimal size; no options)*/
+ 0x45,0,0,44,0,0,0,0,64,6,0,0,1,1,1,1,2,2,2,2,
+ /*TCP-Header*/
+ 0,0x66,0,0x66,0,0,0,0,0,0,0,0,0x50,0,0,1,0,0,0,0,
+ /*TPKT-Header RFC 1006*/
+ 3,0,0,0
+ };
+
+/**
+ * \brief Opens a pcap file for capture
+ * \return Success or failure
+ */
+static ftdm_status_t openPcapFile(void)
+{
+ if(!pcaphandle)
+ {
+ pcaphandle = pcap_open_dead(DLT_EN10MB, SNAPLEN);
+ if (!pcaphandle)
+ {
+ ftdm_log(FTDM_LOG_ERROR, "Can't open pcap session: (%s)\n", pcap_geterr(pcaphandle));
+ return FTDM_FAIL;
+ }
+ }
+
+ if(!pcapfile){
+ /* Open the dump file */
+ if(!(pcapfile=pcap_dump_open(pcaphandle, pcapfn))){
+ ftdm_log(FTDM_LOG_ERROR, "Error opening output file (%s)\n", pcap_geterr(pcaphandle));
+ return FTDM_FAIL;
+ }
+ }
+ else{
+ ftdm_log(FTDM_LOG_WARNING, "Pcap file is already open!\n");
+ return FTDM_FAIL;
+ }
+
+ ftdm_log(FTDM_LOG_DEBUG, "Pcap file '%s' successfully opened!\n", pcapfn);
+
+ pcaphdr.ts.tv_sec = 0;
+ pcaphdr.ts.tv_usec = 0;
+ pcapfilesize = 24; /*current pcap file header seems to be 24 bytes*/
+ tcp_next_seq_no_send = 0;
+ tcp_next_seq_no_rec = 0;
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Closes a pcap file
+ * \return Success
+ */
+static ftdm_status_t closePcapFile(void)
+{
+ if (pcapfile) {
+ pcap_dump_close(pcapfile);
+ if (pcaphandle) pcap_close(pcaphandle);
+
+ ftdm_log(FTDM_LOG_DEBUG, "Pcap file closed! File size is %lu bytes.\n", pcapfilesize);
+
+ pcaphdr.ts.tv_sec = 0;
+ pcaphdr.ts.tv_usec = 0;
+ pcapfile = NULL;
+ pcaphandle = NULL;
+ pcapfilesize = 0;
+ tcp_next_seq_no_send = 0;
+ tcp_next_seq_no_rec = 0;
+ }
+
+ /*We have allways success with this? I think so*/
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Writes a Q931 packet to a pcap file
+ * \return Success or failure
+ */
+static ftdm_status_t writeQ931PacketToPcap(L3UCHAR* q931buf, L3USHORT q931size, L3ULONG span_id, L3USHORT direction)
+{
+ L3UCHAR *frame = NULL;
+ struct timeval ts;
+ u_char spanid = (u_char)span_id;
+ unsigned long *tcp_next_seq_no = NULL;
+
+ spanid=span_id;
+
+ /*The total length of the ethernet frame generated by this function has a min length of 66
+ so we don't have to care about padding :)*/
+
+
+ /*FS is sending the packet*/
+ if(direction==0){
+ frame=sendFrame;
+ tcp_next_seq_no = &tcp_next_seq_no_send;
+ }
+ /*FS is receiving the packet*/
+ else{
+ frame=recFrame;
+ tcp_next_seq_no = &tcp_next_seq_no_rec;
+ }
+
+ /*Set spanid in VLAN-ID tag*/
+ frame[VLANID_OFFSET] = spanid;
+
+ /*** Write sent packet ***/
+ if(q931size > MAX_Q931_SIZE)
+ {
+ /*WARNING*/
+ ftdm_log(FTDM_LOG_WARNING, "Q931 packet size is too big (%u)! Ignoring it!\n", q931size);
+ return FTDM_FAIL;
+ }
+
+ /*Copy q931 buffer into frame*/
+ memcpy(frame+OVERHEAD,q931buf,q931size);
+
+ /*Store TCP sequence number in TCP header*/
+ frame[TCP_SEQ_OFFSET]=(*tcp_next_seq_no>>24)&0xFF;
+ frame[TCP_SEQ_OFFSET+1]=(*tcp_next_seq_no>>16)&0xFF;
+ frame[TCP_SEQ_OFFSET+2]=(*tcp_next_seq_no>>8)&0xFF;
+ frame[TCP_SEQ_OFFSET+3]=*tcp_next_seq_no & 0xFF;
+
+ /*Store size of TPKT packet*/
+ q931size+=4;
+ frame[TPKT_SIZE_OFFSET]=(q931size>>8)&0xFF;
+ frame[TPKT_SIZE_OFFSET+1]=q931size&0xFF;
+
+ /*Calc next TCP sequence number*/
+ *tcp_next_seq_no+=q931size;
+
+ /*Store size of IP packet*/
+ q931size+=SIZE_IP+SIZE_TCP;
+ frame[IP_SIZE_OFFSET]=(q931size>>8)&0xFF;
+ frame[IP_SIZE_OFFSET+1]=q931size&0xFF;
+
+ pcaphdr.caplen = SIZE_ETHERNET+SIZE_ETHERNET_CRC+q931size;
+ pcaphdr.len = pcaphdr.caplen;
+
+ /* Set Timestamp */
+ /* Get Time in ms. usecs would be better ... */
+ gettimeofday(&ts, NULL);
+ /*Write it into packet header*/
+ pcaphdr.ts.tv_sec = ts.tv_sec;
+ pcaphdr.ts.tv_usec = ts.tv_usec;
+
+ pcap_dump((u_char*)pcapfile, &pcaphdr, frame);
+ pcap_dump_flush(pcapfile);
+
+ /*Maintain pcap file size*/
+ pcapfilesize+=pcaphdr.caplen;
+ pcapfilesize+=sizeof(struct pcap_pkthdr);
+
+ ftdm_log(FTDM_LOG_DEBUG, "Added %u bytes to pcap file. File size is now %lu, \n", q931size, pcapfilesize);
+
+ return FTDM_SUCCESS;
+}
+
+#endif
+
+/**
+ * \brief Unloads pcap IO
+ * \return Success or failure
+ */
+static FIO_IO_UNLOAD_FUNCTION(close_pcap)
+{
+#ifdef HAVE_LIBPCAP
+ return closePcapFile();
+#else
+ return FTDM_SUCCESS;
+#endif
+}
+
+/*Q931ToPcap functions DONE*/
+/*-------------------------------------------------------------------------*/
+
+/**
+ * \brief Gets current time
+ * \return Current time (in ms)
+ */
+static L2ULONG ftdm_time_now(void)
+{
+ return (L2ULONG)ftdm_current_time_in_ms();
+}
+
+/**
+ * \brief Initialises an ISDN channel (outgoing call)
+ * \param ftdmchan Channel to initiate call on
+ * \return Success or failure
+ */
+static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(isdn_outgoing_call)
+{
+ ftdm_status_t status = FTDM_SUCCESS;
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
+ return status;
+}
+
+/**
+ * \brief Requests an ISDN channel on a span (outgoing call)
+ * \param span Span where to get a channel
+ * \param chan_id Specific channel to get (0 for any)
+ * \param direction Call direction (inbound, outbound)
+ * \param caller_data Caller information
+ * \param ftdmchan Channel to initialise
+ * \return Success or failure
+ */
+static FIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request)
+{
+ Q931mes_Generic *gen = (Q931mes_Generic *) caller_data->raw_data;
+ Q931ie_BearerCap BearerCap;
+ Q931ie_ChanID ChanID = { 0 };
+ Q931ie_CallingNum CallingNum;
+ Q931ie_CallingNum *ptrCallingNum;
+ Q931ie_CalledNum CalledNum;
+ Q931ie_CalledNum *ptrCalledNum;
+ Q931ie_Display Display, *ptrDisplay;
+ Q931ie_HLComp HLComp; /* High-Layer Compatibility IE */
+ Q931ie_ProgInd Progress; /* Progress Indicator IE */
+ ftdm_status_t status = FTDM_FAIL;
+ ftdm_isdn_data_t *isdn_data = span->signal_data;
+ int sanity = 60000;
+ int codec = 0;
+
+ /*
+ * get codec type
+ */
+ ftdm_channel_command(span->channels[chan_id], FTDM_COMMAND_GET_NATIVE_CODEC, &codec);
+
+ /*
+ * Q.931 Setup Message
+ */
+ Q931InitMesGeneric(gen);
+ gen->MesType = Q931mes_SETUP;
+ gen->CRVFlag = 0; /* outgoing call */
+
+ /*
+ * Bearer Capability IE
+ */
+ Q931InitIEBearerCap(&BearerCap);
+ BearerCap.CodStand = Q931_CODING_ITU; /* ITU-T = 0, ISO/IEC = 1, National = 2, Network = 3 */
+ BearerCap.ITC = Q931_ITC_SPEECH; /* Speech */
+ BearerCap.TransMode = 0; /* Circuit = 0, Packet = 1 */
+ BearerCap.ITR = Q931_ITR_64K; /* 64k */
+ BearerCap.Layer1Ident = 1;
+ BearerCap.UIL1Prot = (codec == FTDM_CODEC_ALAW) ? Q931_UIL1P_G711A : Q931_UIL1P_G711U; /* U-law = 2, A-law = 3 */
+ gen->BearerCap = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &BearerCap);
+
+ /*
+ * Channel ID IE
+ */
+ Q931InitIEChanID(&ChanID);
+ ChanID.IntType = FTDM_SPAN_IS_BRI(span) ? 0 : 1; /* PRI = 1, BRI = 0 */
+
+ if(!FTDM_SPAN_IS_NT(span)) {
+ ChanID.PrefExcl = (isdn_data->opts & FTDM_ISDN_OPT_SUGGEST_CHANNEL) ? 0 : 1; /* 0 = preferred, 1 exclusive */
+ } else {
+ ChanID.PrefExcl = 1; /* always exclusive in NT-mode */
+ }
+
+ if(ChanID.IntType) {
+ ChanID.InfoChanSel = 1; /* None = 0, See Slot = 1, Any = 3 */
+ ChanID.ChanMapType = 3; /* B-Chan */
+ ChanID.ChanSlot = (unsigned char)chan_id;
+ } else {
+ ChanID.InfoChanSel = (unsigned char)chan_id & 0x03; /* None = 0, B1 = 1, B2 = 2, Any = 3 */
+ }
+ gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID);
+
+ /*
+ * Progress IE
+ */
+ Q931InitIEProgInd(&Progress);
+ Progress.CodStand = Q931_CODING_ITU; /* 0 = ITU */
+ Progress.Location = 0; /* 0 = User, 1 = Private Network */
+ Progress.ProgDesc = 3; /* 1 = Not end-to-end ISDN */
+ gen->ProgInd = Q931AppendIE((L3UCHAR *)gen, (L3UCHAR *)&Progress);
+
+ /*
+ * Display IE
+ */
+ if (!(isdn_data->opts & FTDM_ISDN_OPT_OMIT_DISPLAY_IE)) {
+ Q931InitIEDisplay(&Display);
+ Display.Size = Display.Size + (unsigned char)strlen(caller_data->cid_name);
+ gen->Display = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &Display);
+ ptrDisplay = Q931GetIEPtr(gen->Display, gen->buf);
+ ftdm_copy_string((char *)ptrDisplay->Display, caller_data->cid_name, strlen(caller_data->cid_name)+1);
+ }
+
+ /*
+ * Calling Number IE
+ */
+ Q931InitIECallingNum(&CallingNum);
+ CallingNum.TypNum = Q931_TON_UNKNOWN;
+ CallingNum.NumPlanID = Q931_NUMPLAN_E164;
+ CallingNum.PresInd = Q931_PRES_ALLOWED;
+ CallingNum.ScreenInd = Q931_SCREEN_USER_NOT_SCREENED;
+ CallingNum.Size = CallingNum.Size + (unsigned char)strlen(caller_data->cid_num.digits);
+ gen->CallingNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CallingNum);
+ ptrCallingNum = Q931GetIEPtr(gen->CallingNum, gen->buf);
+ ftdm_copy_string((char *)ptrCallingNum->Digit, caller_data->cid_num.digits, strlen(caller_data->cid_num.digits)+1);
+
+
+ /*
+ * Called number IE
+ */
+ Q931InitIECalledNum(&CalledNum);
+ CalledNum.TypNum = Q931_TON_UNKNOWN;
+ CalledNum.NumPlanID = Q931_NUMPLAN_E164;
+ CalledNum.Size = CalledNum.Size + (unsigned char)strlen(caller_data->dnis.digits);
+ gen->CalledNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CalledNum);
+ ptrCalledNum = Q931GetIEPtr(gen->CalledNum, gen->buf);
+ ftdm_copy_string((char *)ptrCalledNum->Digit, caller_data->dnis.digits, strlen(caller_data->dnis.digits)+1);
+
+ /*
+ * High-Layer Compatibility IE (Note: Required for AVM FritzBox)
+ */
+ Q931InitIEHLComp(&HLComp);
+ HLComp.CodStand = Q931_CODING_ITU; /* ITU */
+ HLComp.Interpret = 4; /* only possible value */
+ HLComp.PresMeth = 1; /* High-layer protocol profile */
+ HLComp.HLCharID = 1; /* Telephony = 1, Fax G2+3 = 4, Fax G4 = 65 (Class I)/ 68 (Class II or III) */
+ gen->HLComp = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &HLComp);
+
+ caller_data->call_state = FTDM_CALLER_STATE_DIALING;
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+
+ isdn_data->outbound_crv[gen->CRV] = caller_data;
+ //isdn_data->channels_local_crv[gen->CRV] = ftdmchan;
+
+ while(ftdm_running() && caller_data->call_state == FTDM_CALLER_STATE_DIALING) {
+ ftdm_sleep(1);
+
+ if (!--sanity) {
+ caller_data->call_state = FTDM_CALLER_STATE_FAIL;
+ break;
+ }
+ }
+ isdn_data->outbound_crv[gen->CRV] = NULL;
+
+ if (caller_data->call_state == FTDM_CALLER_STATE_SUCCESS) {
+ ftdm_channel_t *new_chan = NULL;
+ int fail = 1;
+
+ new_chan = NULL;
+ if (caller_data->chan_id < FTDM_MAX_CHANNELS_SPAN && caller_data->chan_id <= span->chan_count) {
+ new_chan = span->channels[caller_data->chan_id];
+ }
+
+ if (new_chan && (status = ftdm_channel_open_chan(new_chan) == FTDM_SUCCESS)) {
+ if (ftdm_test_flag(new_chan, FTDM_CHANNEL_INUSE) || new_chan->state != FTDM_CHANNEL_STATE_DOWN) {
+ if (new_chan->state == FTDM_CHANNEL_STATE_DOWN || new_chan->state >= FTDM_CHANNEL_STATE_TERMINATING) {
+ int x = 0;
+ ftdm_log(FTDM_LOG_WARNING, "Channel %d:%d ~ %d:%d is already in use waiting for it to become available.\n");
+
+ for (x = 0; x < 200; x++) {
+ if (!ftdm_test_flag(new_chan, FTDM_CHANNEL_INUSE)) {
+ break;
+ }
+ ftdm_sleep(5);
+ }
+ }
+ if (ftdm_test_flag(new_chan, FTDM_CHANNEL_INUSE)) {
+ ftdm_log(FTDM_LOG_ERROR, "Channel %d:%d ~ %d:%d is already in use.\n",
+ new_chan->span_id,
+ new_chan->chan_id,
+ new_chan->physical_span_id,
+ new_chan->physical_chan_id
+ );
+ new_chan = NULL;
+ }
+ }
+
+ if (new_chan && new_chan->state == FTDM_CHANNEL_STATE_DOWN) {
+ isdn_data->channels_local_crv[gen->CRV] = new_chan;
+ memset(&new_chan->caller_data, 0, sizeof(new_chan->caller_data));
+ ftdm_set_flag(new_chan, FTDM_CHANNEL_OUTBOUND);
+ ftdm_set_state_locked(new_chan, FTDM_CHANNEL_STATE_DIALING);
+ switch(gen->MesType) {
+ case Q931mes_ALERTING:
+ new_chan->init_state = FTDM_CHANNEL_STATE_PROGRESS_MEDIA;
+ break;
+ case Q931mes_CONNECT:
+ new_chan->init_state = FTDM_CHANNEL_STATE_UP;
+ break;
+ default:
+ new_chan->init_state = FTDM_CHANNEL_STATE_PROGRESS;
+ break;
+ }
+
+ fail = 0;
+ }
+ }
+
+ if (!fail) {
+ *ftdmchan = new_chan;
+ return FTDM_SUCCESS;
+ } else {
+ Q931ie_Cause cause;
+ gen->MesType = Q931mes_DISCONNECT;
+ cause.IEId = Q931ie_CAUSE;
+ cause.Size = sizeof(Q931ie_Cause);
+ cause.CodStand = 0;
+ cause.Location = 1;
+ cause.Recom = 1;
+ //should we be casting here.. or do we need to translate value?
+ cause.Value = (unsigned char) FTDM_CAUSE_WRONG_CALL_STATE;
+ *cause.Diag = '\0';
+ gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+
+ if (gen->CRV) {
+ Q931ReleaseCRV(&isdn_data->q931, gen->CRV);
+ }
+
+ if (new_chan) {
+ ftdm_log(FTDM_LOG_CRIT, "Channel is busy\n");
+ } else {
+ ftdm_log(FTDM_LOG_CRIT, "Failed to open channel for new setup message\n");
+ }
+ }
+ }
+
+ *ftdmchan = NULL;
+ return FTDM_FAIL;
+
+}
+
+/**
+ * \brief Handler for Q931 error
+ * \param pvt Private structure (span?)
+ * \param id Error number
+ * \param p1 ??
+ * \param p2 ??
+ * \return 0
+ */
+static L3INT ftdm_isdn_931_err(void *pvt, L3INT id, L3INT p1, L3INT p2)
+{
+ ftdm_log(FTDM_LOG_ERROR, "ERROR: [%s] [%d] [%d]\n", q931_error_to_name(id), p1, p2);
+ return 0;
+}
+
+/**
+ * \brief Handler for Q931 event message
+ * \param pvt Span to handle
+ * \param msg Message string
+ * \param mlen Message string length
+ * \return 0
+ */
+static L3INT ftdm_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen)
+{
+ ftdm_span_t *span = (ftdm_span_t *) pvt;
+ ftdm_isdn_data_t *isdn_data = span->signal_data;
+ Q931mes_Generic *gen = (Q931mes_Generic *) msg;
+ uint32_t chan_id = 0;
+ int chan_hunt = 0;
+ ftdm_channel_t *ftdmchan = NULL;
+ ftdm_caller_data_t *caller_data = NULL;
+
+ if (Q931IsIEPresent(gen->ChanID)) {
+ Q931ie_ChanID *chanid = Q931GetIEPtr(gen->ChanID, gen->buf);
+
+ if(chanid->IntType)
+ chan_id = chanid->ChanSlot;
+ else
+ chan_id = chanid->InfoChanSel;
+
+ /* "any" channel specified */
+ if(chanid->InfoChanSel == 3) {
+ chan_hunt++;
+ }
+ } else if (FTDM_SPAN_IS_NT(span)) {
+ /* no channel ie */
+ chan_hunt++;
+ }
+
+ assert(span != NULL);
+ assert(isdn_data != NULL);
+
+ ftdm_log(FTDM_LOG_DEBUG, "Yay I got an event! Type:[%02x] Size:[%d] CRV: %d (%#hx, CTX: %s)\n", gen->MesType, gen->Size, gen->CRV, gen->CRV, gen->CRVFlag ? "Terminator" : "Originator");
+
+ if (gen->CRVFlag && (caller_data = isdn_data->outbound_crv[gen->CRV])) {
+ if (chan_id) {
+ caller_data->chan_id = chan_id;
+ }
+
+ switch(gen->MesType) {
+ case Q931mes_STATUS:
+ case Q931mes_CALL_PROCEEDING:
+ break;
+ case Q931mes_ALERTING:
+ case Q931mes_PROGRESS:
+ case Q931mes_CONNECT:
+ {
+ caller_data->call_state = FTDM_CALLER_STATE_SUCCESS;
+ }
+ break;
+ default:
+ caller_data->call_state = FTDM_CALLER_STATE_FAIL;
+ break;
+ }
+
+ return 0;
+ }
+
+ if (gen->CRVFlag) {
+ ftdmchan = isdn_data->channels_local_crv[gen->CRV];
+ } else {
+ ftdmchan = isdn_data->channels_remote_crv[gen->CRV];
+ }
+
+ ftdm_log(FTDM_LOG_DEBUG, "ftdmchan %x (%d:%d) source isdn_data->channels_%s_crv[%#hx]\n", ftdmchan, ftdmchan ? ftdmchan->span_id : -1, ftdmchan ? ftdmchan->chan_id : -1, gen->CRVFlag ? "local" : "remote", gen->CRV);
+
+
+ if (gen->ProtDisc == 3) {
+ switch(gen->MesType) {
+ case Q931mes_SERVICE:
+ {
+ Q931ie_ChangeStatus *changestatus = Q931GetIEPtr(gen->ChangeStatus, gen->buf);
+ if (ftdmchan) {
+ switch (changestatus->NewStatus) {
+ case 0: /* change status to "in service" */
+ {
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_SUSPENDED);
+ ftdm_log(FTDM_LOG_DEBUG, "Channel %d:%d in service\n", ftdmchan->span_id, ftdmchan->chan_id);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+ }
+ break;
+ case 1:
+ { /* change status to "maintenance" */
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_SUSPENDED);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
+ }
+ break;
+ case 2:
+ { /* change status to "out of service" */
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_SUSPENDED);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
+ }
+ break;
+ default: /* unknown */
+ {
+ break;
+ }
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch(gen->MesType) {
+ case Q931mes_RESTART:
+ {
+ if (chan_id) {
+ ftdmchan = span->channels[chan_id];
+ }
+ if (ftdmchan) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+ } else {
+ uint32_t i;
+ for (i = 1; i < span->chan_count; i++) {
+ ftdm_set_state_locked((span->channels[i]), FTDM_CHANNEL_STATE_RESTART);
+ }
+ }
+ }
+ break;
+ case Q931mes_RELEASE:
+ case Q931mes_RELEASE_COMPLETE:
+ {
+ const char *what = gen->MesType == Q931mes_RELEASE ? "Release" : "Release Complete";
+ if (ftdmchan) {
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING || ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP) {
+ if (gen->MesType == Q931mes_RELEASE) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
+ } else {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ }
+ }
+ else if((gen->MesType == Q931mes_RELEASE && ftdmchan->state <= FTDM_CHANNEL_STATE_UP) ||
+ (gen->MesType == Q931mes_RELEASE_COMPLETE && ftdmchan->state == FTDM_CHANNEL_STATE_DIALING)) {
+
+ /*
+ * Don't keep inbound channels open if the remote side hangs up before we answered
+ */
+ Q931ie_Cause *cause = Q931GetIEPtr(gen->Cause, gen->buf);
+ ftdm_sigmsg_t sig;
+ ftdm_status_t status;
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = ftdmchan->chan_id;
+ sig.span_id = ftdmchan->span_id;
+ sig.channel = ftdmchan;
+ sig.channel->caller_data.hangup_cause = (cause) ? cause->Value : FTDM_CAUSE_NORMAL_UNSPECIFIED;
+
+ sig.event_id = FTDM_SIGEVENT_STOP;
+ status = ftdm_span_send_signal(ftdmchan->span, &sig);
+
+ ftdm_log(FTDM_LOG_DEBUG, "Received %s in state %s, requested hangup for channel %d:%d\n", what, ftdm_channel_state2str(ftdmchan->state), ftdmchan->span_id, chan_id);
+ }
+ else {
+ ftdm_log(FTDM_LOG_DEBUG, "Ignoring %s on channel %d\n", what, chan_id);
+ }
+ } else {
+ ftdm_log(FTDM_LOG_CRIT, "Received %s with no matching channel %d\n", what, chan_id);
+ }
+ }
+ break;
+ case Q931mes_DISCONNECT:
+ {
+ if (ftdmchan) {
+ Q931ie_Cause *cause = Q931GetIEPtr(gen->Cause, gen->buf);
+ ftdmchan->caller_data.hangup_cause = cause->Value;
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+ } else {
+ ftdm_log(FTDM_LOG_CRIT, "Received Disconnect with no matching channel %d\n", chan_id);
+ }
+ }
+ break;
+ case Q931mes_ALERTING:
+ {
+ if (ftdmchan) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+ } else {
+ ftdm_log(FTDM_LOG_CRIT, "Received Alerting with no matching channel %d\n", chan_id);
+ }
+ }
+ break;
+ case Q931mes_PROGRESS:
+ {
+ if (ftdmchan) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+ } else {
+ ftdm_log(FTDM_LOG_CRIT, "Received Progress with no matching channel %d\n", chan_id);
+ }
+ }
+ break;
+ case Q931mes_CONNECT:
+ {
+ if (ftdmchan) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
+
+ gen->MesType = Q931mes_CONNECT_ACKNOWLEDGE;
+ gen->CRVFlag = 0; /* outbound */
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+ } else {
+ ftdm_log(FTDM_LOG_CRIT, "Received Connect with no matching channel %d\n", chan_id);
+ }
+ }
+ break;
+ case Q931mes_SETUP:
+ {
+ Q931ie_CallingNum *callingnum = Q931GetIEPtr(gen->CallingNum, gen->buf);
+ Q931ie_CalledNum *callednum = Q931GetIEPtr(gen->CalledNum, gen->buf);
+ int fail = 1;
+ int fail_cause = 0;
+ int overlap_dial = 0;
+ uint32_t cplen = mlen;
+
+ if(ftdmchan && ftdmchan == isdn_data->channels_remote_crv[gen->CRV]) {
+ ftdm_log(FTDM_LOG_INFO, "Duplicate SETUP message(?) for Channel %d:%d ~ %d:%d in state %s [ignoring]\n",
+ ftdmchan->span_id,
+ ftdmchan->chan_id,
+ ftdmchan->physical_span_id,
+ ftdmchan->physical_chan_id,
+ ftdm_channel_state2str(ftdmchan->state));
+ break;
+ }
+
+ ftdmchan = NULL;
+ /*
+ * Channel selection for incoming calls:
+ */
+ if (FTDM_SPAN_IS_NT(span) && chan_hunt) {
+ uint32_t x;
+
+ /*
+ * In NT-mode with channel selection "any",
+ * try to find a free channel
+ */
+ for (x = 1; x <= span->chan_count; x++) {
+ ftdm_channel_t *zc = span->channels[x];
+
+ if (!ftdm_test_flag(zc, FTDM_CHANNEL_INUSE) && zc->state == FTDM_CHANNEL_STATE_DOWN) {
+ ftdmchan = zc;
+ break;
+ }
+ }
+ }
+ else if (!FTDM_SPAN_IS_NT(span) && chan_hunt) {
+ /*
+ * In TE-mode this ("any") is invalid
+ */
+ fail_cause = FTDM_CAUSE_CHANNEL_UNACCEPTABLE;
+
+ ftdm_log(FTDM_LOG_ERROR, "Invalid channel selection in incoming call (network side didn't specify a channel)\n");
+ }
+ else {
+ /*
+ * Otherwise simply try to select the channel we've been told
+ *
+ * TODO: NT mode is abled to select a different channel if the one chosen
+ * by the TE side is already in use
+ */
+ if (chan_id > 0 && chan_id < FTDM_MAX_CHANNELS_SPAN && chan_id <= span->chan_count) {
+ ftdmchan = span->channels[chan_id];
+ }
+ else {
+ /* invalid channel id */
+ fail_cause = FTDM_CAUSE_CHANNEL_UNACCEPTABLE;
+
+ ftdm_log(FTDM_LOG_ERROR, "Invalid channel selection in incoming call (none selected or out of bounds)\n");
+ }
+ }
+
+ if (!callednum || !strlen((char *)callednum->Digit)) {
+ if (FTDM_SPAN_IS_NT(span)) {
+ ftdm_log(FTDM_LOG_NOTICE, "No destination number found, assuming overlap dial\n");
+ overlap_dial++;
+ }
+ else {
+ ftdm_log(FTDM_LOG_ERROR, "No destination number found\n");
+ ftdmchan = NULL;
+ }
+ }
+
+ if (ftdmchan) {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE) || ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) {
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN || ftdmchan->state >= FTDM_CHANNEL_STATE_TERMINATING) {
+ int x = 0;
+ ftdm_log(FTDM_LOG_WARNING, "Channel %d:%d ~ %d:%d is already in use waiting for it to become available.\n",
+ ftdmchan->span_id,
+ ftdmchan->chan_id,
+ ftdmchan->physical_span_id,
+ ftdmchan->physical_chan_id);
+
+ for (x = 0; x < 200; x++) {
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
+ break;
+ }
+ ftdm_sleep(5);
+ }
+ }
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
+ ftdm_log(FTDM_LOG_ERROR, "Channel %d:%d ~ %d:%d is already in use.\n",
+ ftdmchan->span_id,
+ ftdmchan->chan_id,
+ ftdmchan->physical_span_id,
+ ftdmchan->physical_chan_id
+ );
+ ftdmchan = NULL;
+ }
+ }
+
+ if (ftdmchan && ftdmchan->state == FTDM_CHANNEL_STATE_DOWN) {
+ isdn_data->channels_remote_crv[gen->CRV] = ftdmchan;
+ memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data));
+
+ if (ftdmchan->mod_data) {
+ memset(ftdmchan->mod_data, 0, sizeof(ftdm_isdn_bchan_data_t));
+ }
+
+ ftdm_set_string(ftdmchan->caller_data.cid_num.digits, (char *)callingnum->Digit);
+ ftdm_set_string(ftdmchan->caller_data.cid_name, (char *)callingnum->Digit);
+ ftdm_set_string(ftdmchan->caller_data.ani.digits, (char *)callingnum->Digit);
+ if (!overlap_dial) {
+ ftdm_set_string(ftdmchan->caller_data.dnis.digits, (char *)callednum->Digit);
+ }
+
+ ftdmchan->caller_data.CRV = gen->CRV;
+ if (cplen > sizeof(ftdmchan->caller_data.raw_data)) {
+ cplen = sizeof(ftdmchan->caller_data.raw_data);
+ }
+ gen->CRVFlag = !(gen->CRVFlag);
+ memcpy(ftdmchan->caller_data.raw_data, msg, cplen);
+ ftdmchan->caller_data.raw_data_len = cplen;
+ fail = 0;
+ }
+ }
+
+ if (fail) {
+ Q931ie_Cause cause;
+ gen->MesType = Q931mes_DISCONNECT;
+ gen->CRVFlag = 1; /* inbound call */
+ cause.IEId = Q931ie_CAUSE;
+ cause.Size = sizeof(Q931ie_Cause);
+ cause.CodStand = Q931_CODING_ITU;
+ cause.Location = 1;
+ cause.Recom = 1;
+ //should we be casting here.. or do we need to translate value?
+ cause.Value = (unsigned char)((fail_cause) ? fail_cause : FTDM_CAUSE_WRONG_CALL_STATE);
+ *cause.Diag = '\0';
+ gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+
+ if (gen->CRV) {
+ Q931ReleaseCRV(&isdn_data->q931, gen->CRV);
+ }
+
+ if (ftdmchan) {
+ ftdm_log(FTDM_LOG_CRIT, "Channel is busy\n");
+ } else {
+ ftdm_log(FTDM_LOG_CRIT, "Failed to open channel for new setup message\n");
+ }
+
+ } else {
+ Q931ie_ChanID ChanID;
+
+ /*
+ * Update Channel ID IE
+ */
+ Q931InitIEChanID(&ChanID);
+ ChanID.IntType = FTDM_SPAN_IS_BRI(ftdmchan->span) ? 0 : 1; /* PRI = 1, BRI = 0 */
+ ChanID.PrefExcl = FTDM_SPAN_IS_NT(ftdmchan->span) ? 1 : 0; /* Exclusive in NT-mode = 1, Preferred otherwise = 0 */
+ if(ChanID.IntType) {
+ ChanID.InfoChanSel = 1; /* None = 0, See Slot = 1, Any = 3 */
+ ChanID.ChanMapType = 3; /* B-Chan */
+ ChanID.ChanSlot = (unsigned char)ftdmchan->chan_id;
+ } else {
+ ChanID.InfoChanSel = (unsigned char)ftdmchan->chan_id & 0x03; /* None = 0, B1 = 1, B2 = 2, Any = 3 */
+ }
+ gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID);
+
+ if (overlap_dial) {
+ Q931ie_ProgInd progress;
+
+ /*
+ * Setup Progress indicator
+ */
+ progress.IEId = Q931ie_PROGRESS_INDICATOR;
+ progress.Size = sizeof(Q931ie_ProgInd);
+ progress.CodStand = Q931_CODING_ITU; /* ITU */
+ progress.Location = 1; /* private network serving the local user */
+ progress.ProgDesc = 8; /* call is not end-to-end isdn = 1, in-band information available = 8 */
+ gen->ProgInd = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &progress);
+
+ /*
+ * Send SETUP ACK
+ */
+ gen->MesType = Q931mes_SETUP_ACKNOWLEDGE;
+ gen->CRVFlag = 1; /* inbound call */
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DIALTONE);
+ } else {
+ /*
+ * Advance to RING state
+ */
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
+ }
+ }
+ }
+ break;
+
+ case Q931mes_CALL_PROCEEDING:
+ {
+ if (ftdmchan) {
+ ftdm_log(FTDM_LOG_CRIT, "Received CALL PROCEEDING message for channel %d\n", chan_id);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+ } else {
+ ftdm_log(FTDM_LOG_CRIT, "Received CALL PROCEEDING with no matching channel %d\n", chan_id);
+ }
+ }
+ break;
+ case Q931mes_CONNECT_ACKNOWLEDGE:
+ {
+ if (ftdmchan) {
+ ftdm_log(FTDM_LOG_DEBUG, "Received CONNECT_ACK message for channel %d\n", chan_id);
+ } else {
+ ftdm_log(FTDM_LOG_DEBUG, "Received CONNECT_ACK with no matching channel %d\n", chan_id);
+ }
+ }
+ break;
+
+ case Q931mes_INFORMATION:
+ {
+ if (ftdmchan) {
+ ftdm_log(FTDM_LOG_CRIT, "Received INFORMATION message for channel %d\n", ftdmchan->chan_id);
+
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALTONE) {
+ char digit = '\0';
+
+ /*
+ * overlap dial digit indication
+ */
+ if (Q931IsIEPresent(gen->CalledNum)) {
+ ftdm_isdn_bchan_data_t *data = (ftdm_isdn_bchan_data_t *)ftdmchan->mod_data;
+ Q931ie_CalledNum *callednum = Q931GetIEPtr(gen->CalledNum, gen->buf);
+ int pos;
+
+ digit = callednum->Digit[strlen((char *)callednum->Digit) - 1];
+ if (digit == '#') {
+ callednum->Digit[strlen((char *)callednum->Digit) - 1] = '\0';
+ }
+
+ /* TODO: make this more safe with strncat() */
+ pos = (int)strlen(ftdmchan->caller_data.dnis.digits);
+ strcat(&ftdmchan->caller_data.dnis.digits[pos], (char *)callednum->Digit);
+
+ /* update timer */
+ data->digit_timeout = ftdm_time_now() + isdn_data->digit_timeout;
+
+ ftdm_log(FTDM_LOG_DEBUG, "Received new overlap digit (%s), destination number: %s\n", callednum->Digit, ftdmchan->caller_data.dnis.digits);
+ }
+
+ if (Q931IsIEPresent(gen->SendComplete) || digit == '#') {
+ ftdm_log(FTDM_LOG_DEBUG, "Leaving overlap dial mode\n");
+
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
+ }
+ }
+ } else {
+ ftdm_log(FTDM_LOG_CRIT, "Received INFORMATION message with no matching channel\n");
+ }
+ }
+ break;
+
+ case Q931mes_STATUS_ENQUIRY:
+ {
+ /*
+ * !! HACK ALERT !!
+ *
+ * Map FreeTDM channel states to Q.931 states
+ */
+ Q931ie_CallState state;
+ Q931ie_Cause cause;
+
+ gen->MesType = Q931mes_STATUS;
+ gen->CRVFlag = gen->CRVFlag ? 0 : 1;
+
+ state.CodStand = Q931_CODING_ITU; /* ITU-T */
+ state.CallState = Q931_U0; /* Default: Null */
+
+ cause.IEId = Q931ie_CAUSE;
+ cause.Size = sizeof(Q931ie_Cause);
+ cause.CodStand = Q931_CODING_ITU; /* ITU */
+ cause.Location = 1; /* private network */
+ cause.Recom = 1; /* */
+ *cause.Diag = '\0';
+
+ if(ftdmchan) {
+ switch(ftdmchan->state) {
+ case FTDM_CHANNEL_STATE_UP:
+ state.CallState = Q931_U10; /* Active */
+ break;
+ case FTDM_CHANNEL_STATE_RING:
+ state.CallState = Q931_U6; /* Call present */
+ break;
+ case FTDM_CHANNEL_STATE_DIALING:
+ state.CallState = Q931_U1; /* Call initiated */
+ break;
+ case FTDM_CHANNEL_STATE_DIALTONE:
+ state.CallState = Q931_U25; /* Overlap receiving */
+ break;
+
+ /* TODO: map missing states */
+
+ default:
+ state.CallState = Q931_U0;
+ }
+
+ cause.Value = 30; /* response to STATUS ENQUIRY */
+ } else {
+ cause.Value = 98; /* */
+ }
+
+ gen->CallState = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &state);
+ gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+ }
+ break;
+
+ default:
+ ftdm_log(FTDM_LOG_CRIT, "Received unhandled message %d (%#x)\n", (int)gen->MesType, (int)gen->MesType);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Handler for Q921 read event
+ * \param pvt Span were message is coming from
+ * \param ind Q921 indication
+ * \param tei Terminal Endpoint Identifier
+ * \param msg Message string
+ * \param mlen Message string length
+ * \return 0 on success, 1 on failure
+ */
+static int ftdm_isdn_921_23(void *pvt, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *msg, L2INT mlen)
+{
+ int ret, offset = (ind == Q921_DL_DATA) ? 4 : 3;
+ char bb[4096] = "";
+
+ switch(ind) {
+ case Q921_DL_DATA:
+ case Q921_DL_UNIT_DATA:
+ print_hex_bytes(msg + offset, mlen - offset, bb, sizeof(bb));
+#ifdef HAVE_LIBPCAP
+ /*Q931ToPcap*/
+ if(do_q931ToPcap==1){
+ ftdm_span_t *span = (ftdm_span_t *) pvt;
+ if(writeQ931PacketToPcap(msg + offset, mlen - offset, span->span_id, 1) != FTDM_SUCCESS){
+ ftdm_log(FTDM_LOG_WARNING, "Couldn't write Q931 buffer to pcap file!\n");
+ }
+ }
+ /*Q931ToPcap done*/
+#endif
+ ftdm_log(FTDM_LOG_DEBUG, "READ %d\n%s\n%s\n\n\n", (int)mlen - offset, LINE, bb);
+
+ default:
+ ret = Q931Rx23(pvt, ind, tei, msg, mlen);
+ if (ret != 0)
+ ftdm_log(FTDM_LOG_DEBUG, "931 parse error [%d] [%s]\n", ret, q931_error_to_name(ret));
+ break;
+ }
+
+ return ((ret >= 0) ? 1 : 0);
+}
+
+/**
+ * \brief Handler for Q921 write event
+ * \param pvt Span were message is coming from
+ * \param msg Message string
+ * \param mlen Message string length
+ * \return 0 on success, -1 on failure
+ */
+static int ftdm_isdn_921_21(void *pvt, L2UCHAR *msg, L2INT mlen)
+{
+ ftdm_span_t *span = (ftdm_span_t *) pvt;
+ ftdm_size_t len = (ftdm_size_t) mlen;
+ ftdm_isdn_data_t *isdn_data = span->signal_data;
+
+#ifdef IODEBUG
+ char bb[4096] = "";
+ print_hex_bytes(msg, len, bb, sizeof(bb));
+ print_bits(msg, (int)len, bb, sizeof(bb), FTDM_ENDIAN_LITTLE, 0);
+ ftdm_log(FTDM_LOG_DEBUG, "WRITE %d\n%s\n%s\n\n", (int)len, LINE, bb);
+
+#endif
+
+ assert(span != NULL);
+ return ftdm_channel_write(isdn_data->dchan, msg, len, &len) == FTDM_SUCCESS ? 0 : -1;
+}
+
+/**
+ * \brief Handler for channel state change
+ * \param ftdmchan Channel to handle
+ */
+static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
+{
+ Q931mes_Generic *gen = (Q931mes_Generic *) ftdmchan->caller_data.raw_data;
+ ftdm_isdn_data_t *isdn_data = ftdmchan->span->signal_data;
+ ftdm_sigmsg_t sig;
+ ftdm_status_t status;
+
+ ftdm_log(FTDM_LOG_DEBUG, "%d:%d STATE [%s]\n",
+ ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = ftdmchan->chan_id;
+ sig.span_id = ftdmchan->span_id;
+ sig.channel = ftdmchan;
+
+ switch (ftdmchan->state) {
+ case FTDM_CHANNEL_STATE_DOWN:
+ {
+ if (gen->CRV) {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ isdn_data->channels_local_crv[gen->CRV] = NULL;
+ } else {
+ isdn_data->channels_remote_crv[gen->CRV] = NULL;
+ }
+ Q931ReleaseCRV(&isdn_data->q931, gen->CRV);
+ }
+ ftdm_channel_done(ftdmchan);
+ }
+ break;
+ case FTDM_CHANNEL_STATE_PROGRESS:
+ {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ sig.event_id = FTDM_SIGEVENT_PROGRESS;
+ if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ } else {
+ gen->MesType = Q931mes_CALL_PROCEEDING;
+ gen->CRVFlag = 1; /* inbound */
+
+ if (FTDM_SPAN_IS_NT(ftdmchan->span)) {
+ Q931ie_ChanID ChanID;
+
+ /*
+ * Set new Channel ID
+ */
+ Q931InitIEChanID(&ChanID);
+ ChanID.IntType = FTDM_SPAN_IS_BRI(ftdmchan->span) ? 0 : 1; /* PRI = 1, BRI = 0 */
+ ChanID.PrefExcl = 1; /* always exclusive in NT-mode */
+
+ if(ChanID.IntType) {
+ ChanID.InfoChanSel = 1; /* None = 0, See Slot = 1, Any = 3 */
+ ChanID.ChanMapType = 3; /* B-Chan */
+ ChanID.ChanSlot = (unsigned char)ftdmchan->chan_id;
+ } else {
+ ChanID.InfoChanSel = (unsigned char)ftdmchan->chan_id & 0x03; /* None = 0, B1 = 1, B2 = 2, Any = 3 */
+ }
+ gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID);
+ }
+
+ Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_DIALTONE:
+ {
+ ftdm_isdn_bchan_data_t *data = (ftdm_isdn_bchan_data_t *)ftdmchan->mod_data;
+
+ if (data) {
+ data->digit_timeout = ftdm_time_now() + isdn_data->digit_timeout;
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_RING:
+ {
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ sig.event_id = FTDM_SIGEVENT_START;
+ if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_RESTART:
+ {
+ ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_UNSPECIFIED;
+ sig.event_id = FTDM_SIGEVENT_RESTART;
+ status = ftdm_span_send_signal(ftdmchan->span, &sig);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ }
+ break;
+ case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+ {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ sig.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
+ if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ } else {
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
+ if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ return;
+ }
+ }
+ gen->MesType = Q931mes_ALERTING;
+ gen->CRVFlag = 1; /* inbound call */
+ Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_UP:
+ {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ sig.event_id = FTDM_SIGEVENT_UP;
+ if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ } else {
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
+ if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ return;
+ }
+ }
+ gen->MesType = Q931mes_CONNECT;
+ gen->BearerCap = 0;
+ gen->CRVFlag = 1; /* inbound call */
+ Q931Rx43(&isdn_data->q931, (void *)gen, ftdmchan->caller_data.raw_data_len);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_DIALING:
+ if (!(isdn_data->opts & FTDM_ISDN_OPT_SUGGEST_CHANNEL)) {
+ Q931ie_BearerCap BearerCap;
+ Q931ie_ChanID ChanID;
+ Q931ie_CallingNum CallingNum;
+ Q931ie_CallingNum *ptrCallingNum;
+ Q931ie_CalledNum CalledNum;
+ Q931ie_CalledNum *ptrCalledNum;
+ Q931ie_Display Display, *ptrDisplay;
+ Q931ie_HLComp HLComp; /* High-Layer Compatibility IE */
+ Q931ie_ProgInd Progress; /* Progress Indicator IE */
+ int codec = 0;
+
+ /*
+ * get codec type
+ */
+ ftdm_channel_command(ftdmchan->span->channels[ftdmchan->chan_id], FTDM_COMMAND_GET_NATIVE_CODEC, &codec);
+
+ /*
+ * Q.931 Setup Message
+ */
+ Q931InitMesGeneric(gen);
+ gen->MesType = Q931mes_SETUP;
+ gen->CRVFlag = 0; /* outbound(?) */
+
+ /*
+ * Bearer Capability IE
+ */
+ Q931InitIEBearerCap(&BearerCap);
+ BearerCap.CodStand = Q931_CODING_ITU; /* ITU-T = 0, ISO/IEC = 1, National = 2, Network = 3 */
+ BearerCap.ITC = Q931_ITC_SPEECH; /* Speech */
+ BearerCap.TransMode = 0; /* Circuit = 0, Packet = 1 */
+ BearerCap.ITR = Q931_ITR_64K; /* 64k = 16, Packet mode = 0 */
+ BearerCap.Layer1Ident = 1;
+ BearerCap.UIL1Prot = (codec == FTDM_CODEC_ALAW) ? 3 : 2; /* U-law = 2, A-law = 3 */
+ gen->BearerCap = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &BearerCap);
+
+ /*
+ * ChannelID IE
+ */
+ Q931InitIEChanID(&ChanID);
+ ChanID.IntType = FTDM_SPAN_IS_BRI(ftdmchan->span) ? 0 : 1; /* PRI = 1, BRI = 0 */
+ ChanID.PrefExcl = FTDM_SPAN_IS_NT(ftdmchan->span) ? 1 : 0; /* Exclusive in NT-mode = 1, Preferred otherwise = 0 */
+ if(ChanID.IntType) {
+ ChanID.InfoChanSel = 1; /* None = 0, See Slot = 1, Any = 3 */
+ ChanID.ChanMapType = 3; /* B-Chan */
+ ChanID.ChanSlot = (unsigned char)ftdmchan->chan_id;
+ } else {
+ ChanID.InfoChanSel = (unsigned char)ftdmchan->chan_id & 0x03; /* None = 0, B1 = 1, B2 = 2, Any = 3 */
+ }
+ gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID);
+
+ /*
+ * Progress IE
+ */
+ Q931InitIEProgInd(&Progress);
+ Progress.CodStand = Q931_CODING_ITU; /* 0 = ITU */
+ Progress.Location = 0; /* 0 = User, 1 = Private Network */
+ Progress.ProgDesc = 3; /* 1 = Not end-to-end ISDN */
+ gen->ProgInd = Q931AppendIE((L3UCHAR *)gen, (L3UCHAR *)&Progress);
+
+ /*
+ * Display IE
+ */
+ if (!(isdn_data->opts & FTDM_ISDN_OPT_OMIT_DISPLAY_IE)) {
+ Q931InitIEDisplay(&Display);
+ Display.Size = Display.Size + (unsigned char)strlen(ftdmchan->caller_data.cid_name);
+ gen->Display = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &Display);
+ ptrDisplay = Q931GetIEPtr(gen->Display, gen->buf);
+ ftdm_copy_string((char *)ptrDisplay->Display, ftdmchan->caller_data.cid_name, strlen(ftdmchan->caller_data.cid_name)+1);
+ }
+
+ /*
+ * CallingNum IE
+ */
+ Q931InitIECallingNum(&CallingNum);
+ CallingNum.TypNum = ftdmchan->caller_data.ani.type;
+ CallingNum.NumPlanID = Q931_NUMPLAN_E164;
+ CallingNum.PresInd = Q931_PRES_ALLOWED;
+ CallingNum.ScreenInd = Q931_SCREEN_USER_NOT_SCREENED;
+ CallingNum.Size = CallingNum.Size + (unsigned char)strlen(ftdmchan->caller_data.cid_num.digits);
+ gen->CallingNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CallingNum);
+ ptrCallingNum = Q931GetIEPtr(gen->CallingNum, gen->buf);
+ ftdm_copy_string((char *)ptrCallingNum->Digit, ftdmchan->caller_data.cid_num.digits, strlen(ftdmchan->caller_data.cid_num.digits)+1);
+
+ /*
+ * CalledNum IE
+ */
+ Q931InitIECalledNum(&CalledNum);
+ CalledNum.TypNum = ftdmchan->caller_data.dnis.type;
+ CalledNum.NumPlanID = Q931_NUMPLAN_E164;
+ CalledNum.Size = CalledNum.Size + (unsigned char)strlen(ftdmchan->caller_data.dnis.digits);
+ gen->CalledNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CalledNum);
+ ptrCalledNum = Q931GetIEPtr(gen->CalledNum, gen->buf);
+ ftdm_copy_string((char *)ptrCalledNum->Digit, ftdmchan->caller_data.dnis.digits, strlen(ftdmchan->caller_data.dnis.digits)+1);
+
+ /*
+ * High-Layer Compatibility IE (Note: Required for AVM FritzBox)
+ */
+ Q931InitIEHLComp(&HLComp);
+ HLComp.CodStand = Q931_CODING_ITU; /* ITU */
+ HLComp.Interpret = 4; /* only possible value */
+ HLComp.PresMeth = 1; /* High-layer protocol profile */
+ HLComp.HLCharID = Q931_HLCHAR_TELEPHONY; /* Telephony = 1, Fax G2+3 = 4, Fax G4 = 65 (Class I)/ 68 (Class II or III) */ /* TODO: make accessible from user layer */
+ gen->HLComp = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &HLComp);
+
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+ isdn_data->channels_local_crv[gen->CRV] = ftdmchan;
+ }
+ break;
+ case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
+ {
+ /* reply RELEASE with RELEASE_COMPLETE message */
+ if(ftdmchan->last_state == FTDM_CHANNEL_STATE_HANGUP) {
+ gen->MesType = Q931mes_RELEASE_COMPLETE;
+
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+ }
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ }
+ break;
+ case FTDM_CHANNEL_STATE_HANGUP:
+ {
+ Q931ie_Cause cause;
+
+ ftdm_log(FTDM_LOG_DEBUG, "Hangup: Direction %s\n", ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) ? "Outbound" : "Inbound");
+
+ gen->CRVFlag = ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) ? 0 : 1;
+
+ cause.IEId = Q931ie_CAUSE;
+ cause.Size = sizeof(Q931ie_Cause);
+ cause.CodStand = Q931_CODING_ITU; /* ITU */
+ cause.Location = 1; /* private network */
+ cause.Recom = 1; /* */
+
+ /*
+ * BRI PTMP needs special handling here...
+ * TODO: cleanup / refine (see above)
+ */
+ if (ftdmchan->last_state == FTDM_CHANNEL_STATE_RING) {
+ /*
+ * inbound call [was: number unknown (= not found in routing state)]
+ * (in Q.931 spec terms: Reject request)
+ */
+ gen->MesType = Q931mes_RELEASE_COMPLETE;
+
+ //cause.Value = (unsigned char) FTDM_CAUSE_UNALLOCATED;
+ cause.Value = (unsigned char) ftdmchan->caller_data.hangup_cause;
+ *cause.Diag = '\0';
+ gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+
+ /* we're done, release channel */
+ //ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ }
+ else if (ftdmchan->last_state <= FTDM_CHANNEL_STATE_PROGRESS) {
+ /*
+ * just release all unanswered calls [was: inbound call, remote side hung up before we answered]
+ */
+ gen->MesType = Q931mes_RELEASE;
+
+ cause.Value = (unsigned char) ftdmchan->caller_data.hangup_cause;
+ *cause.Diag = '\0';
+ gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+ Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size);
+
+ /* this will be triggered by the RELEASE_COMPLETE reply */
+ /* ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE); */
+ }
+ else {
+ /*
+ * call connected, hangup
+ */
+ gen->MesType = Q931mes_DISCONNECT;
+
+ cause.Value = (unsigned char) ftdmchan->caller_data.hangup_cause;
+ *cause.Diag = '\0';
+ gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_TERMINATING:
+ {
+ ftdm_log(FTDM_LOG_DEBUG, "Terminating: Direction %s\n", ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) ? "Outbound" : "Inbound");
+
+ sig.event_id = FTDM_SIGEVENT_STOP;
+ status = ftdm_span_send_signal(ftdmchan->span, &sig);
+ gen->MesType = Q931mes_RELEASE;
+ gen->CRVFlag = ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) ? 0 : 1;
+ Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size);
+ }
+ default:
+ break;
+ }
+}
+
+/**
+ * \brief Checks current state on a span
+ * \param span Span to check status on
+ */
+static __inline__ void check_state(ftdm_span_t *span)
+{
+ if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
+ uint32_t j;
+ ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
+ for(j = 1; j <= span->chan_count; j++) {
+ if (ftdm_test_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE)) {
+ ftdm_mutex_lock(span->channels[j]->mutex);
+ ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
+ state_advance(span->channels[j]);
+ ftdm_channel_complete_state(span->channels[j]);
+ ftdm_mutex_unlock(span->channels[j]->mutex);
+ }
+ }
+ }
+}
+
+/**
+ * \brief Processes FreeTDM event on a span
+ * \param span Span to process event on
+ * \param event Event to process
+ * \return Success or failure
+ */
+static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *event)
+{
+ ftdm_log(FTDM_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n",
+ ftdm_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, ftdm_channel_state2str(event->channel->state));
+
+ switch(event->enum_id) {
+ case FTDM_OOB_ALARM_TRAP:
+ {
+ if (event->channel->state != FTDM_CHANNEL_STATE_DOWN) {
+ if (event->channel->type == FTDM_CHAN_TYPE_B) {
+ ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_RESTART);
+ }
+ }
+
+
+ ftdm_set_flag(event->channel, FTDM_CHANNEL_SUSPENDED);
+
+
+ ftdm_channel_get_alarms(event->channel);
+ ftdm_log(FTDM_LOG_WARNING, "channel %d:%d (%d:%d) has alarms! [%s]\n",
+ event->channel->span_id, event->channel->chan_id,
+ event->channel->physical_span_id, event->channel->physical_chan_id,
+ event->channel->last_error);
+ }
+ break;
+ case FTDM_OOB_ALARM_CLEAR:
+ {
+
+ ftdm_log(FTDM_LOG_WARNING, "channel %d:%d (%d:%d) alarms Cleared!\n", event->channel->span_id, event->channel->chan_id,
+ event->channel->physical_span_id, event->channel->physical_chan_id);
+
+ ftdm_clear_flag(event->channel, FTDM_CHANNEL_SUSPENDED);
+ ftdm_channel_get_alarms(event->channel);
+ }
+ break;
+ }
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Checks for events on a span
+ * \param span Span to check for events
+ */
+static __inline__ void check_events(ftdm_span_t *span)
+{
+ ftdm_status_t status;
+
+ status = ftdm_span_poll_event(span, 5);
+
+ switch(status) {
+ case FTDM_SUCCESS:
+ {
+ ftdm_event_t *event;
+ while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
+ if (event->enum_id == FTDM_OOB_NOOP) {
+ continue;
+ }
+ if (process_event(span, event) != FTDM_SUCCESS) {
+ break;
+ }
+ }
+ }
+ break;
+ case FTDM_FAIL:
+ {
+ ftdm_log(FTDM_LOG_DEBUG, "Event Failure! %d\n", ftdm_running());
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * \brief Retrieves tone generation output to be sent
+ * \param ts Teletone generator
+ * \param map Tone map
+ * \return -1 on error, 0 on success
+ */
+static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+ ftdm_buffer_t *dt_buffer = ts->user_data;
+ int wrote;
+
+ if (!dt_buffer) {
+ return -1;
+ }
+ wrote = teletone_mux_tones(ts, map);
+ ftdm_buffer_write(dt_buffer, ts->buffer, wrote * 2);
+ return 0;
+}
+
+/**
+ * \brief Main thread function for tone generation on a span
+ * \param me Current thread
+ * \param obj Span to generate tones on
+ */
+static void *ftdm_isdn_tones_run(ftdm_thread_t *me, void *obj)
+{
+ ftdm_span_t *span = (ftdm_span_t *) obj;
+ ftdm_isdn_data_t *isdn_data = span->signal_data;
+ ftdm_buffer_t *dt_buffer = NULL;
+ teletone_generation_session_t ts = {{{{0}}}};
+ unsigned char frame[1024];
+ uint32_t x;
+ int interval = 0;
+ int offset = 0;
+
+ ftdm_log(FTDM_LOG_DEBUG, "ISDN tones thread starting.\n");
+ ftdm_set_flag(isdn_data, FTDM_ISDN_TONES_RUNNING);
+
+ if (ftdm_buffer_create(&dt_buffer, 1024, 1024, 0) != FTDM_SUCCESS) {
+ snprintf(isdn_data->dchan->last_error, sizeof(isdn_data->dchan->last_error), "memory error!");
+ ftdm_log(FTDM_LOG_ERROR, "MEM ERROR\n");
+ goto done;
+ }
+ ftdm_buffer_set_loops(dt_buffer, -1);
+
+ /* get a tone generation friendly interval to avoid distortions */
+ for (x = 1; x <= span->chan_count; x++) {
+ if (span->channels[x]->type != FTDM_CHAN_TYPE_DQ921) {
+ ftdm_channel_command(span->channels[x], FTDM_COMMAND_GET_INTERVAL, &interval);
+ break;
+ }
+ }
+ if (!interval) {
+ interval = 20;
+ }
+ ftdm_log(FTDM_LOG_NOTICE, "Tone generating interval %d\n", interval);
+
+ /* init teletone */
+ teletone_init_session(&ts, 0, teletone_handler, dt_buffer);
+ ts.rate = 8000;
+ ts.duration = ts.rate;
+
+ /* main loop */
+ while(ftdm_running() && ftdm_test_flag(isdn_data, FTDM_ISDN_TONES_RUNNING) && !ftdm_test_flag(isdn_data, FTDM_ISDN_STOP)) {
+ ftdm_wait_flag_t flags;
+ ftdm_status_t status;
+ int last_chan_state = 0;
+ int gated = 0;
+ L2ULONG now = ftdm_time_now();
+
+ /*
+ * check b-channel states and generate & send tones if neccessary
+ */
+ for (x = 1; x <= span->chan_count; x++) {
+ ftdm_channel_t *ftdmchan = span->channels[x];
+ ftdm_size_t len = sizeof(frame), rlen;
+
+ if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
+ continue;
+ }
+
+ /*
+ * Generate tones based on current bchan state
+ * (Recycle buffer content if succeeding channels share the
+ * same state, this saves some cpu cycles)
+ */
+ switch (ftdmchan->state) {
+ case FTDM_CHANNEL_STATE_DIALTONE:
+ {
+ ftdm_isdn_bchan_data_t *data = (ftdm_isdn_bchan_data_t *)ftdmchan->mod_data;
+
+ /* check overlap dial timeout first before generating tone */
+ if (data && data->digit_timeout && data->digit_timeout <= now) {
+ if (strlen(ftdmchan->caller_data.dnis.digits) > 0) {
+ ftdm_log(FTDM_LOG_DEBUG, "Overlap dial timeout, advancing to RING state\n");
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
+ } else {
+ /* no digits received, hangup */
+ ftdm_log(FTDM_LOG_DEBUG, "Overlap dial timeout, no digits received, going to HANGUP state\n");
+ ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_RECOVERY_ON_TIMER_EXPIRE; /* TODO: probably wrong cause value */
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ data->digit_timeout = 0;
+ continue;
+ }
+
+ if (last_chan_state != ftdmchan->state) {
+ ftdm_buffer_zero(dt_buffer);
+ teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_DIAL]);
+ last_chan_state = ftdmchan->state;
+ }
+ }
+ break;
+
+ case FTDM_CHANNEL_STATE_RING:
+ {
+ if (last_chan_state != ftdmchan->state) {
+ ftdm_buffer_zero(dt_buffer);
+ teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_RING]);
+ last_chan_state = ftdmchan->state;
+ }
+ }
+ break;
+
+ default: /* Not in a tone generating state, go to next round */
+ continue;
+ }
+
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
+ if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ continue;
+ }
+ ftdm_log(FTDM_LOG_NOTICE, "Successfully opened channel %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id);
+ }
+
+ flags = FTDM_READ;
+
+ status = ftdm_channel_wait(ftdmchan, &flags, (gated) ? 0 : interval);
+ switch(status) {
+ case FTDM_FAIL:
+ continue;
+
+ case FTDM_TIMEOUT:
+ gated = 1;
+ continue;
+
+ default:
+ if (!(flags & FTDM_READ)) {
+ continue;
+ }
+ }
+ gated = 1;
+
+ status = ftdm_channel_read(ftdmchan, frame, &len);
+ if (status != FTDM_SUCCESS || len <= 0) {
+ continue;
+ }
+
+ if (ftdmchan->effective_codec != FTDM_CODEC_SLIN) {
+ len *= 2;
+ }
+
+ /* seek to current offset */
+ ftdm_buffer_seek(dt_buffer, offset);
+
+ rlen = ftdm_buffer_read_loop(dt_buffer, frame, len);
+
+ if (ftdmchan->effective_codec != FTDM_CODEC_SLIN) {
+ fio_codec_t codec_func = NULL;
+
+ if (ftdmchan->native_codec == FTDM_CODEC_ULAW) {
+ codec_func = fio_slin2ulaw;
+ } else if (ftdmchan->native_codec == FTDM_CODEC_ALAW) {
+ codec_func = fio_slin2alaw;
+ }
+
+ if (codec_func) {
+ status = codec_func(frame, sizeof(frame), &rlen);
+ } else {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "codec error!");
+ goto done;
+ }
+ }
+ ftdm_channel_write(ftdmchan, frame, sizeof(frame), &rlen);
+ }
+
+ /*
+ * sleep a bit if there was nothing to do
+ */
+ if (!gated) {
+ ftdm_sleep(interval);
+ }
+
+ offset += (ts.rate / (1000 / interval)) << 1;
+ if (offset >= ts.rate) {
+ offset = 0;
+ }
+ }
+
+done:
+ if (ts.buffer) {
+ teletone_destroy_session(&ts);
+ }
+
+ if (dt_buffer) {
+ ftdm_buffer_destroy(&dt_buffer);
+ }
+
+ ftdm_log(FTDM_LOG_DEBUG, "ISDN tone thread ended.\n");
+ ftdm_clear_flag(isdn_data, FTDM_ISDN_TONES_RUNNING);
+
+ return NULL;
+}
+
+/**
+ * \brief Main thread function for an ISDN span
+ * \param me Current thread
+ * \param obj Span to monitor
+ */
+static void *ftdm_isdn_run(ftdm_thread_t *me, void *obj)
+{
+ ftdm_span_t *span = (ftdm_span_t *) obj;
+ ftdm_isdn_data_t *isdn_data = span->signal_data;
+ unsigned char frame[1024];
+ ftdm_size_t len = sizeof(frame);
+ int errs = 0;
+
+#ifdef WIN32
+ timeBeginPeriod(1);
+#endif
+
+ ftdm_log(FTDM_LOG_DEBUG, "ISDN thread starting.\n");
+ ftdm_set_flag(isdn_data, FTDM_ISDN_RUNNING);
+
+ Q921Start(&isdn_data->q921);
+
+ while(ftdm_running() && ftdm_test_flag(isdn_data, FTDM_ISDN_RUNNING) && !ftdm_test_flag(isdn_data, FTDM_ISDN_STOP)) {
+ ftdm_wait_flag_t flags = FTDM_READ;
+ ftdm_status_t status = ftdm_channel_wait(isdn_data->dchan, &flags, 100);
+
+ Q921TimerTick(&isdn_data->q921);
+ Q931TimerTick(&isdn_data->q931);
+ check_state(span);
+ check_events(span);
+
+ /*
+ *
+ */
+ switch(status) {
+ case FTDM_FAIL:
+ {
+ ftdm_log(FTDM_LOG_ERROR, "D-Chan Read Error!\n");
+ snprintf(span->last_error, sizeof(span->last_error), "D-Chan Read Error!");
+ if (++errs == 10) {
+ isdn_data->dchan->state = FTDM_CHANNEL_STATE_UP;
+ goto done;
+ }
+ }
+ break;
+ case FTDM_TIMEOUT:
+ {
+ errs = 0;
+ }
+ break;
+ default:
+ {
+ errs = 0;
+ if (flags & FTDM_READ) {
+
+ if (ftdm_test_flag(isdn_data->dchan, FTDM_CHANNEL_SUSPENDED)) {
+ ftdm_clear_flag_all(span, FTDM_CHANNEL_SUSPENDED);
+ }
+ len = sizeof(frame);
+ if (ftdm_channel_read(isdn_data->dchan, frame, &len) == FTDM_SUCCESS) {
+#ifdef IODEBUG
+ char bb[4096] = "";
+ print_hex_bytes(frame, len, bb, sizeof(bb));
+
+ print_bits(frame, (int)len, bb, sizeof(bb), FTDM_ENDIAN_LITTLE, 0);
+ ftdm_log(FTDM_LOG_DEBUG, "READ %d\n%s\n%s\n\n", (int)len, LINE, bb);
+#endif
+
+ Q921QueueHDLCFrame(&isdn_data->q921, frame, (int)len);
+ Q921Rx12(&isdn_data->q921);
+ }
+ } else {
+ ftdm_log(FTDM_LOG_DEBUG, "No Read FLAG!\n");
+ }
+ }
+ break;
+ }
+ }
+
+ done:
+ ftdm_channel_close(&isdn_data->dchans[0]);
+ ftdm_channel_close(&isdn_data->dchans[1]);
+ ftdm_clear_flag(isdn_data, FTDM_ISDN_RUNNING);
+
+#ifdef WIN32
+ timeEndPeriod(1);
+#endif
+
+ ftdm_log(FTDM_LOG_DEBUG, "ISDN thread ended.\n");
+ return NULL;
+}
+
+/**
+ * \brief FreeTDM ISDN signaling module initialisation
+ * \return Success
+ */
+static FIO_SIG_LOAD_FUNCTION(ftdm_isdn_init)
+{
+ Q931Initialize();
+
+ Q921SetGetTimeCB(ftdm_time_now);
+ Q931SetGetTimeCB(ftdm_time_now);
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Receives a Q931 indication message
+ * \param pvt Span were message is coming from
+ * \param ind Q931 indication
+ * \param tei Terminal Endpoint Identifier
+ * \param msg Message string
+ * \param mlen Message string length
+ * \return 0 on success
+ */
+static int q931_rx_32(void *pvt, Q921DLMsg_t ind, L3UCHAR tei, L3UCHAR *msg, L3INT mlen)
+{
+ int offset = 4;
+ char bb[4096] = "";
+
+ switch(ind) {
+ case Q921_DL_UNIT_DATA:
+ offset = 3;
+
+ case Q921_DL_DATA:
+ print_hex_bytes(msg + offset, mlen - offset, bb, sizeof(bb));
+#ifdef HAVE_LIBPCAP
+ /*Q931ToPcap*/
+ if(do_q931ToPcap==1){
+ ftdm_span_t *span = (ftdm_span_t *) pvt;
+ if(writeQ931PacketToPcap(msg + offset, mlen - offset, span->span_id, 0) != FTDM_SUCCESS){
+ ftdm_log(FTDM_LOG_WARNING, "Couldn't write Q931 buffer to pcap file!\n");
+ }
+ }
+ /*Q931ToPcap done*/
+#endif
+ ftdm_log(FTDM_LOG_DEBUG, "WRITE %d\n%s\n%s\n\n", (int)mlen - offset, LINE, bb);
+ break;
+
+ default:
+ break;
+ }
+
+ return Q921Rx32(pvt, ind, tei, msg, mlen);
+}
+
+/**
+ * \brief Logs Q921 message
+ * \param pvt Span were message is coming from
+ * \param level Q921 log level
+ * \param msg Message string
+ * \param size Message string length
+ * \return 0
+ */
+static int ftdm_isdn_q921_log(void *pvt, Q921LogLevel_t level, char *msg, L2INT size)
+{
+ ftdm_span_t *span = (ftdm_span_t *) pvt;
+
+ ftdm_log("Span", "Q.921", span->span_id, (int)level, "%s", msg);
+ return 0;
+}
+
+/**
+ * \brief Logs Q931 message
+ * \param pvt Span were message is coming from
+ * \param level Q931 log level
+ * \param msg Message string
+ * \param size Message string length
+ * \return 0
+ */
+static L3INT ftdm_isdn_q931_log(void *pvt, Q931LogLevel_t level, char *msg, L3INT size)
+{
+ ftdm_span_t *span = (ftdm_span_t *) pvt;
+
+ ftdm_log("Span", "Q.931", span->span_id, (int)level, "%s", msg);
+ return 0;
+}
+/**
+ * \brief ISDN state map
+ */
+static ftdm_state_map_t isdn_state_map = {
+ {
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_ANY_STATE},
+ {FTDM_CHANNEL_STATE_RESTART, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_RESTART, FTDM_END},
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+ {FTDM_CHANNEL_STATE_DIALING, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_DIALING, FTDM_END},
+ {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_UP, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
+ },
+
+ /****************************************/
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_ANY_STATE},
+ {FTDM_CHANNEL_STATE_RESTART, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_RESTART, FTDM_END},
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+ {FTDM_CHANNEL_STATE_DIALTONE, FTDM_CHANNEL_STATE_RING, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_DIALTONE, FTDM_END},
+ {FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_RING, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA,
+ FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_UP, FTDM_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_UP, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+ },
+
+
+ }
+};
+
+/**
+ * \brief Stops an ISDN span
+ * \param span Span to halt
+ * \return Success
+ *
+ * Sets a stop flag and waits for the threads to end
+ */
+static ftdm_status_t ftdm_isdn_stop(ftdm_span_t *span)
+{
+ ftdm_isdn_data_t *isdn_data = span->signal_data;
+
+ if (!ftdm_test_flag(isdn_data, FTDM_ISDN_RUNNING)) {
+ return FTDM_FAIL;
+ }
+
+ ftdm_set_flag(isdn_data, FTDM_ISDN_STOP);
+
+ while(ftdm_test_flag(isdn_data, FTDM_ISDN_RUNNING)) {
+ ftdm_sleep(100);
+ }
+
+ while(ftdm_test_flag(isdn_data, FTDM_ISDN_TONES_RUNNING)) {
+ ftdm_sleep(100);
+ }
+
+ return FTDM_SUCCESS;
+
+}
+
+/**
+ * \brief Starts an ISDN span
+ * \param span Span to halt
+ * \return Success or failure
+ *
+ * Launches a thread to monitor the span and a thread to generate tones on the span
+ */
+static ftdm_status_t ftdm_isdn_start(ftdm_span_t *span)
+{
+ ftdm_status_t ret;
+ ftdm_isdn_data_t *isdn_data = span->signal_data;
+
+ if (ftdm_test_flag(isdn_data, FTDM_ISDN_RUNNING)) {
+ return FTDM_FAIL;
+ }
+
+ ftdm_clear_flag(isdn_data, FTDM_ISDN_STOP);
+ ret = ftdm_thread_create_detached(ftdm_isdn_run, span);
+
+ if (ret != FTDM_SUCCESS) {
+ return ret;
+ }
+
+ if (FTDM_SPAN_IS_NT(span) && !(isdn_data->opts & FTDM_ISDN_OPT_DISABLE_TONES)) {
+ ret = ftdm_thread_create_detached(ftdm_isdn_tones_run, span);
+ }
+ return ret;
+}
+
+/**
+ * \brief Parses an option string to flags
+ * \param in String to parse for configuration options
+ * \return Flags
+ */
+static uint32_t parse_opts(const char *in)
+{
+ uint32_t flags = 0;
+
+ if (!in) {
+ return 0;
+ }
+
+ if (strstr(in, "suggest_channel")) {
+ flags |= FTDM_ISDN_OPT_SUGGEST_CHANNEL;
+ }
+
+ if (strstr(in, "omit_display")) {
+ flags |= FTDM_ISDN_OPT_OMIT_DISPLAY_IE;
+ }
+
+ if (strstr(in, "disable_tones")) {
+ flags |= FTDM_ISDN_OPT_DISABLE_TONES;
+ }
+
+ return flags;
+}
+
+/**
+ * \brief Initialises an ISDN span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static FIO_SIG_CONFIGURE_FUNCTION(ftdm_isdn_configure_span)
+{
+ uint32_t i, x = 0;
+ ftdm_channel_t *dchans[2] = {0};
+ ftdm_isdn_data_t *isdn_data;
+ const char *tonemap = "us";
+ char *var, *val;
+ Q931Dialect_t dialect = Q931_Dialect_National;
+ int32_t digit_timeout = 0;
+ int q921loglevel = -1;
+ int q931loglevel = -1;
+#ifdef HAVE_LIBPCAP
+ int q931topcap = -1; /*Q931ToPcap*/
+ int openPcap = 0; /*Flag: open Pcap file please*/
+#endif
+
+ if (span->signal_type) {
+#ifdef HAVE_LIBPCAP
+ /*Q931ToPcap: Get the content of the q931topcap and pcapfilename args given by mod_freetdm */
+ while((var = va_arg(ap, char *))) {
+ if (!strcasecmp(var, "q931topcap")) {
+ q931topcap = va_arg(ap, int);
+ if(q931topcap==1) {
+ /*PCAP on*/;
+ openPcap=1;
+ } else if (q931topcap==0) {
+ /*PCAP off*/
+ if (closePcapFile() != FTDM_SUCCESS) return FTDM_FAIL;
+ do_q931ToPcap=0;
+ return FTDM_SUCCESS;
+ }
+ }
+ if (!strcasecmp(var, "pcapfilename")) {
+ /*Put filename into global var*/
+ pcapfn = va_arg(ap, char*);
+ }
+ }
+ /*We know now, that user wants to enable Q931ToPcap and what file name he wants, so open it please*/
+ if(openPcap==1){
+ if(openPcapFile() != FTDM_SUCCESS) return FTDM_FAIL;
+ do_q931ToPcap=1;
+ return FTDM_SUCCESS;
+ }
+ /*Q931ToPcap done*/
+#endif
+ snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling [%d].", span->signal_type);
+ return FTDM_FAIL;
+ }
+
+ if (span->trunk_type >= FTDM_TRUNK_NONE) {
+ ftdm_log(FTDM_LOG_WARNING, "Invalid trunk type '%s' defaulting to T1.\n", ftdm_trunk_type2str(span->trunk_type));
+ span->trunk_type = FTDM_TRUNK_T1;
+ }
+
+ for(i = 1; i <= span->chan_count; i++) {
+ if (span->channels[i]->type == FTDM_CHAN_TYPE_DQ921) {
+ if (x > 1) {
+ snprintf(span->last_error, sizeof(span->last_error), "Span has more than 2 D-Channels!");
+ return FTDM_FAIL;
+ } else {
+ if (ftdm_channel_open(span->span_id, i, &dchans[x]) == FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_DEBUG, "opening d-channel #%d %d:%d\n", x, dchans[x]->span_id, dchans[x]->chan_id);
+ dchans[x]->state = FTDM_CHANNEL_STATE_UP;
+ x++;
+ }
+ }
+ }
+ }
+
+ if (!x) {
+ snprintf(span->last_error, sizeof(span->last_error), "Span has no D-Channels!");
+ return FTDM_FAIL;
+ }
+
+ isdn_data = ftdm_malloc(sizeof(*isdn_data));
+ assert(isdn_data != NULL);
+ memset(isdn_data, 0, sizeof(*isdn_data));
+
+ isdn_data->mode = Q931_TE;
+ dialect = Q931_Dialect_National;
+
+ while((var = va_arg(ap, char *))) {
+ if (!strcasecmp(var, "mode")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ isdn_data->mode = strcasecmp(val, "net") ? Q931_TE : Q931_NT;
+ } else if (!strcasecmp(var, "dialect")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ dialect = q931_str2Q931Dialect_type(val);
+ if (dialect == Q931_Dialect_Count) {
+ return FTDM_FAIL;
+ }
+ } else if (!strcasecmp(var, "opts")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ isdn_data->opts = parse_opts(val);
+ } else if (!strcasecmp(var, "tonemap")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ tonemap = (const char *)val;
+ } else if (!strcasecmp(var, "digit_timeout")) {
+ int *optp;
+ if (!(optp = va_arg(ap, int *))) {
+ break;
+ }
+ digit_timeout = *optp;
+ } else if (!strcasecmp(var, "q921loglevel")) {
+ q921loglevel = va_arg(ap, int);
+ if (q921loglevel < Q921_LOG_NONE) {
+ q921loglevel = Q921_LOG_NONE;
+ } else if (q921loglevel > Q921_LOG_DEBUG) {
+ q921loglevel = Q921_LOG_DEBUG;
+ }
+ } else if (!strcasecmp(var, "q931loglevel")) {
+ q931loglevel = va_arg(ap, int);
+ if (q931loglevel < Q931_LOG_NONE) {
+ q931loglevel = Q931_LOG_NONE;
+ } else if (q931loglevel > Q931_LOG_DEBUG) {
+ q931loglevel = Q931_LOG_DEBUG;
+ }
+ } else {
+ snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+ return FTDM_FAIL;
+ }
+ }
+
+
+ if (!digit_timeout) {
+ digit_timeout = DEFAULT_DIGIT_TIMEOUT;
+ }
+ else if (digit_timeout < 3000 || digit_timeout > 30000) {
+ ftdm_log(FTDM_LOG_WARNING, "Digit timeout %d ms outside of range (3000 - 30000 ms), using default (10000 ms)\n", digit_timeout);
+ digit_timeout = DEFAULT_DIGIT_TIMEOUT;
+ }
+
+ /* allocate per b-chan data */
+ if (isdn_data->mode == Q931_NT) {
+ ftdm_isdn_bchan_data_t *data;
+
+ data = ftdm_malloc((span->chan_count - 1) * sizeof(ftdm_isdn_bchan_data_t));
+ if (!data) {
+ return FTDM_FAIL;
+ }
+
+ for (i = 1; i <= span->chan_count; i++, data++) {
+ if (span->channels[i]->type == FTDM_CHAN_TYPE_B) {
+ span->channels[i]->mod_data = data;
+ memset(data, 0, sizeof(ftdm_isdn_bchan_data_t));
+ }
+ }
+ }
+
+ span->start = ftdm_isdn_start;
+ span->stop = ftdm_isdn_stop;
+ span->signal_cb = sig_cb;
+ isdn_data->dchans[0] = dchans[0];
+ isdn_data->dchans[1] = dchans[1];
+ isdn_data->dchan = isdn_data->dchans[0];
+ isdn_data->digit_timeout = digit_timeout;
+
+ Q921_InitTrunk(&isdn_data->q921,
+ 0,
+ 0,
+ isdn_data->mode,
+ span->trunk_type == FTDM_TRUNK_BRI_PTMP ? Q921_PTMP : Q921_PTP,
+ 0,
+ ftdm_isdn_921_21,
+ (Q921Tx23CB_t)ftdm_isdn_921_23,
+ span,
+ &isdn_data->q931);
+
+ Q921SetLogCB(&isdn_data->q921, &ftdm_isdn_q921_log, isdn_data);
+ Q921SetLogLevel(&isdn_data->q921, (Q921LogLevel_t)q921loglevel);
+
+ Q931Api_InitTrunk(&isdn_data->q931,
+ dialect,
+ isdn_data->mode,
+ span->trunk_type,
+ ftdm_isdn_931_34,
+ (Q931Tx32CB_t)q931_rx_32,
+ ftdm_isdn_931_err,
+ &isdn_data->q921,
+ span);
+
+ Q931SetLogCB(&isdn_data->q931, &ftdm_isdn_q931_log, isdn_data);
+ Q931SetLogLevel(&isdn_data->q931, (Q931LogLevel_t)q931loglevel);
+
+ isdn_data->q931.autoRestartAck = 1;
+ isdn_data->q931.autoConnectAck = 0;
+ isdn_data->q931.autoServiceAck = 1;
+ span->signal_data = isdn_data;
+ span->signal_type = FTDM_SIGTYPE_ISDN;
+ span->outgoing_call = isdn_outgoing_call;
+
+ if ((isdn_data->opts & FTDM_ISDN_OPT_SUGGEST_CHANNEL)) {
+ span->channel_request = isdn_channel_request;
+ span->suggest_chan_id = 1;
+ }
+ span->state_map = &isdn_state_map;
+
+ ftdm_span_load_tones(span, tonemap);
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief FreeTDM ISDN signaling module definition
+ */
+EX_DECLARE_DATA ftdm_module_t ftdm_module = {
+ "isdn",
+ NULL,
+ close_pcap,
+ ftdm_isdn_init,
+ ftdm_isdn_configure_span,
+ NULL
+};
+
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ozmod_isdn.2005.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ozmod_isdn.2005.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ozmod_isdn.2005.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,316 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ftmod_isdn"
+ ProjectGUID="{729344A5-D5E9-434D-8EE8-AF8C6C795D15}"
+ RootNamespace="ftmod_isdn"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\isdn\5ESSmes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\5ESSStateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\5ESSStateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\DMSmes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\DMSStateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\DMSStateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\EuroISDNStateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\EuroISDNStateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\mfifo.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\nationalmes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\nationalStateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\nationalStateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="ftmod_isdn.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q921.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931api.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931ie.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931mes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931StateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931StateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q932mes.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\isdn\include\5ESS.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\DMS.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\mfifo.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\national.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q921.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q921priv.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q931.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q931ie.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q932.h"
+ >
+ </File>
+ <File
+ RelativePath="ftdm_isdn.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1364 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#include "freetdm.h"
+#include "ftmod_libpri.h"
+
+/**
+ * \brief Unloads libpri IO module
+ * \return Success
+ */
+static FIO_IO_UNLOAD_FUNCTION(ftdm_libpri_unload)
+{
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Starts a libpri channel (outgoing call)
+ * \param ftdmchan Channel to initiate call on
+ * \return Success or failure
+ */
+static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(isdn_outgoing_call)
+{
+ ftdm_status_t status = FTDM_SUCCESS;
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
+ return status;
+}
+
+/**
+ * \brief Requests an libpri channel on a span (outgoing call)
+ * \param span Span where to get a channel (unused)
+ * \param chan_id Specific channel to get (0 for any) (unused)
+ * \param direction Call direction (unused)
+ * \param caller_data Caller information (unused)
+ * \param ftdmchan Channel to initialise (unused)
+ * \return Failure
+ */
+static FIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request)
+{
+ return FTDM_FAIL;
+}
+
+#ifdef WIN32
+/**
+ * \brief Logs a libpri error
+ * \param s Error string
+ */
+static void s_pri_error(char *s)
+#else
+/**
+ * \brief Logs a libpri error
+ * \param pri libpri structure (unused)
+ * \param s Error string
+ */
+static void s_pri_error(struct pri *pri, char *s)
+#endif
+{
+ ftdm_log(FTDM_LOG_ERROR, "%s", s);
+}
+
+#ifdef WIN32
+/**
+ * \brief Logs a libpri message
+ * \param s Message string
+ */
+static void s_pri_message(char *s)
+#else
+/**
+ * \brief Logs a libpri message
+ * \param pri libpri structure (unused)
+ * \param s Message string
+ */
+static void s_pri_message(struct pri *pri, char *s)
+#endif
+{
+ ftdm_log(FTDM_LOG_DEBUG, "%s", s);
+}
+
+/**
+ * \brief Parses an option string to flags
+ * \param in String to parse for configuration options
+ * \return Flags
+ */
+static uint32_t parse_opts(const char *in)
+{
+ uint32_t flags = 0;
+
+ if (!in) {
+ return 0;
+ }
+
+ if (strstr(in, "suggest_channel")) {
+ flags |= FTMOD_LIBPRI_OPT_SUGGEST_CHANNEL;
+ }
+
+ if (strstr(in, "omit_display")) {
+ flags |= FTMOD_LIBPRI_OPT_OMIT_DISPLAY_IE;
+ }
+
+ if (strstr(in, "omit_redirecting_number")) {
+ flags |= FTMOD_LIBPRI_OPT_OMIT_REDIRECTING_NUMBER_IE;
+ }
+
+ return flags;
+}
+
+/**
+ * \brief Parses a debug string to flags
+ * \param in Debug string to parse for
+ * \return Flags
+ */
+static int parse_debug(const char *in)
+{
+ int flags = 0;
+
+ if (!in) {
+ return 0;
+ }
+
+ if (strstr(in, "q921_raw")) {
+ flags |= PRI_DEBUG_Q921_RAW;
+ }
+
+ if (strstr(in, "q921_dump")) {
+ flags |= PRI_DEBUG_Q921_DUMP;
+ }
+
+ if (strstr(in, "q921_state")) {
+ flags |= PRI_DEBUG_Q921_STATE;
+ }
+
+ if (strstr(in, "config")) {
+ flags |= PRI_DEBUG_CONFIG;
+ }
+
+ if (strstr(in, "q931_dump")) {
+ flags |= PRI_DEBUG_Q931_DUMP;
+ }
+
+ if (strstr(in, "q931_state")) {
+ flags |= PRI_DEBUG_Q931_STATE;
+ }
+
+ if (strstr(in, "q931_anomaly")) {
+ flags |= PRI_DEBUG_Q931_ANOMALY;
+ }
+
+ if (strstr(in, "apdu")) {
+ flags |= PRI_DEBUG_APDU;
+ }
+
+ if (strstr(in, "aoc")) {
+ flags |= PRI_DEBUG_AOC;
+ }
+
+ if (strstr(in, "all")) {
+ flags |= PRI_DEBUG_ALL;
+ }
+
+ if (strstr(in, "none")) {
+ flags = 0;
+ }
+
+ return flags;
+}
+
+static ftdm_io_interface_t ftdm_libpri_interface;
+
+static ftdm_status_t ftdm_libpri_start(ftdm_span_t *span);
+
+/**
+ * \brief API function to kill or debug a libpri span
+ * \param stream API stream handler
+ * \param data String containing argurments
+ * \return Flags
+ */
+static FIO_API_FUNCTION(ftdm_libpri_api)
+{
+ char *mycmd = NULL, *argv[10] = { 0 };
+ int argc = 0;
+
+ if (data) {
+ mycmd = ftdm_strdup(data);
+ argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+ }
+
+ if (argc == 2) {
+ if (!strcasecmp(argv[0], "kill")) {
+ int span_id = atoi(argv[1]);
+ ftdm_span_t *span = NULL;
+
+ if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) {
+ ftdm_libpri_data_t *isdn_data = span->signal_data;
+
+ if (span->start != ftdm_libpri_start) {
+ stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
+ goto done;
+ }
+
+ ftdm_clear_flag((&isdn_data->spri), LPWRAP_PRI_READY);
+ stream->write_function(stream, "%s: +OK killed.\n", __FILE__);
+ goto done;
+ } else {
+ stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
+ goto done;
+ }
+ }
+ }
+
+ if (argc > 2) {
+ if (!strcasecmp(argv[0], "debug")) {
+ ftdm_span_t *span = NULL;
+
+ if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS) {
+ ftdm_libpri_data_t *isdn_data = span->signal_data;
+ if (span->start != ftdm_libpri_start) {
+ stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
+ goto done;
+ }
+
+ pri_set_debug(isdn_data->spri.pri, parse_debug(argv[2]));
+ stream->write_function(stream, "%s: +OK debug set.\n", __FILE__);
+ goto done;
+ } else {
+ stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
+ goto done;
+ }
+ }
+
+ }
+
+ stream->write_function(stream, "%s: -ERR invalid command.\n", __FILE__);
+
+ done:
+
+ ftdm_safe_free(mycmd);
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Loads libpri IO module
+ * \param fio FreeTDM IO interface
+ * \return Success
+ */
+static FIO_IO_LOAD_FUNCTION(ftdm_libpri_io_init)
+{
+ assert(fio != NULL);
+ memset(&ftdm_libpri_interface, 0, sizeof(ftdm_libpri_interface));
+
+ ftdm_libpri_interface.name = "libpri";
+ ftdm_libpri_interface.api = ftdm_libpri_api;
+
+ *fio = &ftdm_libpri_interface;
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Loads libpri signaling module
+ * \param fio FreeTDM IO interface
+ * \return Success
+ */
+static FIO_SIG_LOAD_FUNCTION(ftdm_libpri_init)
+{
+ pri_set_error(s_pri_error);
+ pri_set_message(s_pri_message);
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief libpri state map
+ */
+static ftdm_state_map_t isdn_state_map = {
+ {
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_ANY_STATE},
+ {FTDM_CHANNEL_STATE_RESTART, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_RESTART, FTDM_END},
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+ {FTDM_CHANNEL_STATE_DIALING, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_DIALING, FTDM_END},
+ {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_UP, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
+ },
+
+ /****************************************/
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_ANY_STATE},
+ {FTDM_CHANNEL_STATE_RESTART, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_RESTART, FTDM_END},
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+ {FTDM_CHANNEL_STATE_DIALTONE, FTDM_CHANNEL_STATE_RING, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_DIALTONE, FTDM_END},
+ {FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_RING, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA,
+ FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_UP, FTDM_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_UP, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+ },
+
+
+ }
+};
+
+/**
+ * \brief Handler for channel state change
+ * \param ftdmchan Channel to handle
+ */
+static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
+{
+ //Q931mes_Generic *gen = (Q931mes_Generic *) ftdmchan->caller_data.raw_data;
+ ftdm_libpri_data_t *isdn_data = ftdmchan->span->signal_data;
+ ftdm_status_t status;
+ ftdm_sigmsg_t sig;
+ q931_call *call = (q931_call *) ftdmchan->call_data;
+
+
+ ftdm_log(FTDM_LOG_DEBUG, "%d:%d STATE [%s]\n",
+ ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
+
+
+#if 0
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) && !call) {
+ ftdm_log(FTDM_LOG_WARNING, "NO CALL!!!!\n");
+ }
+#endif
+
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = ftdmchan->chan_id;
+ sig.span_id = ftdmchan->span_id;
+ sig.channel = ftdmchan;
+
+
+ switch (ftdmchan->state) {
+ case FTDM_CHANNEL_STATE_DOWN:
+ {
+ ftdmchan->call_data = NULL;
+ ftdm_channel_done(ftdmchan);
+ }
+ break;
+ case FTDM_CHANNEL_STATE_PROGRESS:
+ {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ sig.event_id = FTDM_SIGEVENT_PROGRESS;
+ if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ } else if (call) {
+ pri_progress(isdn_data->spri.pri, call, ftdmchan->chan_id, 1);
+ } else {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+ {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ sig.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
+ if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ } else if (call) {
+ pri_proceeding(isdn_data->spri.pri, call, ftdmchan->chan_id, 1);
+ } else {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_RING:
+ {
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ if (call) {
+ pri_acknowledge(isdn_data->spri.pri, call, ftdmchan->chan_id, 0);
+ sig.event_id = FTDM_SIGEVENT_START;
+ if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ } else {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+ }
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_RESTART:
+ {
+ ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_UNSPECIFIED;
+ sig.event_id = FTDM_SIGEVENT_RESTART;
+ status = ftdm_span_send_signal(ftdmchan->span, &sig);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ }
+ break;
+ case FTDM_CHANNEL_STATE_UP:
+ {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ sig.event_id = FTDM_SIGEVENT_UP;
+ if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ } else if (call) {
+ pri_answer(isdn_data->spri.pri, call, 0, 1);
+ } else {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_DIALING:
+ if (isdn_data) {
+ struct pri_sr *sr;
+ int dp;
+
+ if (!(call = pri_new_call(isdn_data->spri.pri))) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+ return;
+ }
+
+
+ dp = ftdmchan->caller_data.dnis.type;
+ switch(dp) {
+ case FTDM_TON_NATIONAL:
+ dp = PRI_NATIONAL_ISDN;
+ break;
+ case FTDM_TON_INTERNATIONAL:
+ dp = PRI_INTERNATIONAL_ISDN;
+ break;
+ case FTDM_TON_SUBSCRIBER_NUMBER:
+ dp = PRI_LOCAL_ISDN;
+ break;
+ default:
+ dp = isdn_data->dp;
+ }
+
+ ftdmchan->call_data = call;
+ sr = pri_sr_new();
+ assert(sr);
+ pri_sr_set_channel(sr, ftdmchan->chan_id, 0, 0);
+ pri_sr_set_bearer(sr, 0, isdn_data->l1);
+ pri_sr_set_called(sr, ftdmchan->caller_data.dnis.digits, dp, 1);
+ pri_sr_set_caller(sr, ftdmchan->caller_data.cid_num.digits, (isdn_data->opts & FTMOD_LIBPRI_OPT_OMIT_DISPLAY_IE ? NULL : ftdmchan->caller_data.cid_name),
+ dp, (ftdmchan->caller_data.pres != 1 ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_PROHIB_USER_NUMBER_NOT_SCREENED));
+
+ if (!(isdn_data->opts & FTMOD_LIBPRI_OPT_OMIT_REDIRECTING_NUMBER_IE)) {
+ pri_sr_set_redirecting(sr, ftdmchan->caller_data.cid_num.digits, dp, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, PRI_REDIR_UNCONDITIONAL);
+ }
+
+ if (pri_setup(isdn_data->spri.pri, call, sr)) {
+ ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER;
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+
+ pri_sr_free(sr);
+ }
+
+ break;
+ case FTDM_CHANNEL_STATE_HANGUP:
+ {
+ if (call) {
+ pri_hangup(isdn_data->spri.pri, call, ftdmchan->caller_data.hangup_cause);
+ pri_destroycall(isdn_data->spri.pri, call);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ } else {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
+ break;
+ case FTDM_CHANNEL_STATE_TERMINATING:
+ {
+ sig.event_id = FTDM_SIGEVENT_STOP;
+ status = ftdm_span_send_signal(ftdmchan->span, &sig);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+
+ }
+ default:
+ break;
+ }
+
+
+
+ return;
+}
+
+/**
+ * \brief Checks current state on a span
+ * \param span Span to check status on
+ */
+static __inline__ void check_state(ftdm_span_t *span)
+{
+ if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
+ uint32_t j;
+ ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
+ for(j = 1; j <= span->chan_count; j++) {
+ if (ftdm_test_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE)) {
+ ftdm_mutex_lock(span->channels[j]->mutex);
+ ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
+ state_advance(span->channels[j]);
+ ftdm_channel_complete_state(span->channels[j]);
+ ftdm_mutex_unlock(span->channels[j]->mutex);
+ }
+ }
+ }
+}
+
+/**
+ * \brief Handler for libpri information event (incoming call?)
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_info(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+
+ ftdm_log(FTDM_LOG_DEBUG, "number is: %s\n", pevent->ring.callednum);
+ if (strlen(pevent->ring.callednum) > 3) {
+ ftdm_log(FTDM_LOG_DEBUG, "final number is: %s\n", pevent->ring.callednum);
+ pri_answer(spri->pri, pevent->ring.call, 0, 1);
+ }
+ return 0;
+}
+
+/**
+ * \brief Handler for libpri hangup event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_hangup(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+ ftdm_span_t *span = spri->private_info;
+ ftdm_channel_t *ftdmchan = NULL;
+ q931_call *call = NULL;
+ ftdmchan = span->channels[pevent->hangup.channel];
+
+ if (ftdmchan) {
+ call = (q931_call *) ftdmchan->call_data;
+ ftdm_log(FTDM_LOG_DEBUG, "-- Hangup on channel %d:%d\n", spri->span->span_id, pevent->hangup.channel);
+ ftdmchan->caller_data.hangup_cause = pevent->hangup.cause;
+ pri_release(spri->pri, call, 0);
+ pri_destroycall(spri->pri, call);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+ } else {
+ ftdm_log(FTDM_LOG_DEBUG, "-- Hangup on channel %d:%d %s but it's not in use?\n", spri->span->span_id,
+ pevent->hangup.channel, ftdmchan->chan_id);
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Handler for libpri answer event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_answer(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+ ftdm_span_t *span = spri->private_info;
+ ftdm_channel_t *ftdmchan = NULL;
+
+ ftdmchan = span->channels[pevent->answer.channel];
+
+ if (ftdmchan) {
+ ftdm_log(FTDM_LOG_DEBUG, "-- Answer on channel %d:%d\n", spri->span->span_id, pevent->answer.channel);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
+ } else {
+ ftdm_log(FTDM_LOG_DEBUG, "-- Answer on channel %d:%d %s but it's not in use?\n", spri->span->span_id, pevent->answer.channel, ftdmchan->chan_id);
+
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Handler for libpri proceed event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_proceed(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+ ftdm_span_t *span = spri->private_info;
+ ftdm_channel_t *ftdmchan = NULL;
+
+ ftdmchan = span->channels[pevent->proceeding.channel];
+
+ if (ftdmchan) {
+ ftdm_log(FTDM_LOG_DEBUG, "-- Proceeding on channel %d:%d\n", spri->span->span_id, pevent->proceeding.channel);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+ } else {
+ ftdm_log(FTDM_LOG_DEBUG, "-- Proceeding on channel %d:%d %s but it's not in use?\n", spri->span->span_id,
+ pevent->proceeding.channel, ftdmchan->chan_id);
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Handler for libpri ringing event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_ringing(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+ ftdm_span_t *span = spri->private_info;
+ ftdm_channel_t *ftdmchan = NULL;
+
+ ftdmchan = span->channels[pevent->ringing.channel];
+
+ if (ftdmchan) {
+ ftdm_log(FTDM_LOG_DEBUG, "-- Ringing on channel %d:%d\n", spri->span->span_id, pevent->ringing.channel);
+ /* we may get on_ringing even when we're already in FTDM_CHANNEL_STATE_PROGRESS_MEDIA */
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
+ /* dont try to move to STATE_PROGRESS to avoid annoying veto warning */
+ return 0;
+ }
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+ } else {
+ ftdm_log(FTDM_LOG_DEBUG, "-- Ringing on channel %d:%d %s but it's not in use?\n", spri->span->span_id,
+ pevent->ringing.channel, ftdmchan->chan_id);
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Handler for libpri ring event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0 on success
+ */
+static int on_ring(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+ ftdm_span_t *span = spri->private_info;
+ ftdm_channel_t *ftdmchan = NULL;
+ int ret = 0;
+
+ //switch_mutex_lock(globals.channel_mutex);
+
+ ftdmchan = span->channels[pevent->ring.channel];
+ if (!ftdmchan || ftdmchan->state != FTDM_CHANNEL_STATE_DOWN || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
+ ftdm_log(FTDM_LOG_WARNING, "--Duplicate Ring on channel %d:%d (ignored)\n", spri->span->span_id, pevent->ring.channel);
+ ret = 0;
+ goto done;
+ }
+
+ if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_WARNING, "--Failure opening channel %d:%d (ignored)\n", spri->span->span_id, pevent->ring.channel);
+ ret = 0;
+ goto done;
+ }
+
+
+ ftdm_log(FTDM_LOG_NOTICE, "-- Ring on channel %d:%d (from %s to %s)\n", spri->span->span_id, pevent->ring.channel,
+ pevent->ring.callingnum, pevent->ring.callednum);
+
+ memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data));
+
+ ftdm_set_string(ftdmchan->caller_data.cid_num.digits, (char *)pevent->ring.callingnum);
+ if (!ftdm_strlen_zero((char *)pevent->ring.callingname)) {
+ ftdm_set_string(ftdmchan->caller_data.cid_name, (char *)pevent->ring.callingname);
+ } else {
+ ftdm_set_string(ftdmchan->caller_data.cid_name, (char *)pevent->ring.callingnum);
+ }
+ ftdm_set_string(ftdmchan->caller_data.ani.digits, (char *)pevent->ring.callingani);
+ ftdm_set_string(ftdmchan->caller_data.dnis.digits, (char *)pevent->ring.callednum);
+
+ if (pevent->ring.ani2 >= 0) {
+ snprintf(ftdmchan->caller_data.aniII, 5, "%.2d", pevent->ring.ani2);
+ }
+
+ // scary to trust this pointer, you'd think they would give you a copy of the call data so you own it......
+ ftdmchan->call_data = pevent->ring.call;
+
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
+
+ done:
+ //switch_mutex_unlock(globals.channel_mutex);
+
+ return ret;
+}
+
+/**
+ * \brief Processes freetdm event
+ * \param span Span on which the event was fired
+ * \param event Event to be treated
+ * \return Success or failure
+ */
+static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *event)
+{
+ ftdm_log(FTDM_LOG_DEBUG, "EVENT [%s][%d][%d:%d] STATE [%s]\n",
+ ftdm_oob_event2str(event->enum_id), event->enum_id, event->channel->span_id, event->channel->chan_id, ftdm_channel_state2str(event->channel->state));
+
+ switch(event->enum_id) {
+ case FTDM_OOB_ALARM_TRAP:
+ {
+ if (event->channel->state != FTDM_CHANNEL_STATE_DOWN) {
+ if (event->channel->type == FTDM_CHAN_TYPE_B) {
+ ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_RESTART);
+ }
+ }
+
+
+ ftdm_set_flag(event->channel, FTDM_CHANNEL_SUSPENDED);
+
+
+ ftdm_channel_get_alarms(event->channel);
+ ftdm_log(FTDM_LOG_WARNING, "channel %d:%d (%d:%d) has alarms! [%s]\n",
+ event->channel->span_id, event->channel->chan_id,
+ event->channel->physical_span_id, event->channel->physical_chan_id,
+ event->channel->last_error);
+ }
+ break;
+ case FTDM_OOB_ALARM_CLEAR:
+ {
+
+ ftdm_log(FTDM_LOG_WARNING, "channel %d:%d (%d:%d) alarms Cleared!\n", event->channel->span_id, event->channel->chan_id,
+ event->channel->physical_span_id, event->channel->physical_chan_id);
+
+ ftdm_clear_flag(event->channel, FTDM_CHANNEL_SUSPENDED);
+ ftdm_channel_get_alarms(event->channel);
+ }
+ break;
+ }
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Checks for events on a span
+ * \param span Span to check for events
+ */
+static __inline__ void check_events(ftdm_span_t *span)
+{
+ ftdm_status_t status;
+
+ status = ftdm_span_poll_event(span, 5);
+
+ switch(status) {
+ case FTDM_SUCCESS:
+ {
+ ftdm_event_t *event;
+ while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
+ if (event->enum_id == FTDM_OOB_NOOP) {
+ continue;
+ }
+ if (process_event(span, event) != FTDM_SUCCESS) {
+ break;
+ }
+ }
+ }
+ break;
+ case FTDM_FAIL:
+ {
+ ftdm_log(FTDM_LOG_DEBUG, "Event Failure! %d\n", ftdm_running());
+ ftdm_sleep(2000);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * \brief Checks flags on a pri span
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \return 0 on success, -1 on error
+ */
+static int check_flags(lpwrap_pri_t *spri)
+{
+ ftdm_span_t *span = spri->private_info;
+
+ if (!ftdm_running() || ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
+ return -1;
+ }
+
+ check_state(span);
+ check_events(span);
+
+
+ return 0;
+}
+
+/**
+ * \brief Handler for libpri restart event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_restart(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+ ftdm_span_t *span = spri->private_info;
+ ftdm_channel_t *ftdmchan;
+
+ ftdm_log(FTDM_LOG_NOTICE, "-- Restarting %d:%d\n", spri->span->span_id, pevent->restart.channel);
+
+ ftdmchan = span->channels[pevent->restart.channel];
+
+ if (!ftdmchan) {
+ return 0;
+ }
+
+ if (pevent->restart.channel < 1) {
+ ftdm_set_state_all(ftdmchan->span, FTDM_CHANNEL_STATE_RESTART);
+ } else {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Handler for libpri dchan up event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_dchan_up(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+
+ if (!ftdm_test_flag(spri, LPWRAP_PRI_READY)) {
+ ftdm_log(FTDM_LOG_INFO, "Span %d D-Chan UP!\n", spri->span->span_id);
+ ftdm_set_flag(spri, LPWRAP_PRI_READY);
+ ftdm_set_state_all(spri->span, FTDM_CHANNEL_STATE_RESTART);
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Handler for libpri dchan down event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_dchan_down(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+
+ if (ftdm_test_flag(spri, LPWRAP_PRI_READY)) {
+ ftdm_log(FTDM_LOG_INFO, "Span %d D-Chan DOWN!\n", spri->span->span_id);
+ ftdm_clear_flag(spri, LPWRAP_PRI_READY);
+ ftdm_set_state_all(spri->span, FTDM_CHANNEL_STATE_RESTART);
+
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Handler for any libpri event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_anything(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+
+ ftdm_log(FTDM_LOG_DEBUG, "Caught Event span %d %u (%s)\n", spri->span->span_id, event_type, lpwrap_pri_event_str(event_type));
+ return 0;
+}
+
+/**
+ * \brief Handler for libpri io fail event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_io_fail(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+
+ ftdm_log(FTDM_LOG_DEBUG, "Caught Event span %d %u (%s)\n", spri->span->span_id, event_type, lpwrap_pri_event_str(event_type));
+ return 0;
+}
+
+/**
+ * \brief Main thread function for libpri span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *ftdm_libpri_run(ftdm_thread_t *me, void *obj)
+{
+ ftdm_span_t *span = (ftdm_span_t *) obj;
+ ftdm_libpri_data_t *isdn_data = span->signal_data;
+ int i, x = 0;
+ int down = 0;
+ int got_d = 0;
+
+ ftdm_set_flag(span, FTDM_SPAN_IN_THREAD);
+
+ while(ftdm_running() && !ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
+ if (!got_d) {
+ for(i = 1; i <= span->chan_count; i++) {
+ if (span->channels[i]->type == FTDM_CHAN_TYPE_DQ921) {
+ if (ftdm_channel_open(span->span_id, i, &isdn_data->dchan) == FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_DEBUG, "opening d-channel #%d %d:%d\n", x, isdn_data->dchan->span_id, isdn_data->dchan->chan_id);
+ isdn_data->dchan->state = FTDM_CHANNEL_STATE_UP;
+ got_d = 1;
+ x++;
+ break;
+ }
+ }
+ }
+ }
+
+
+ if (lpwrap_init_pri(&isdn_data->spri,
+ span, // span
+ isdn_data->dchan, // dchan
+ isdn_data->pswitch,
+ isdn_data->node,
+ isdn_data->debug) < 0) {
+ snprintf(span->last_error, sizeof(span->last_error), "PRI init FAIL!");
+ } else {
+
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_ANY, on_anything);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RING, on_ring);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RINGING, on_ringing);
+ //LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_SETUP_ACK, on_proceed);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_PROCEEDING, on_proceed);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_ANSWER, on_answer);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_DCHAN_UP, on_dchan_up);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_DCHAN_DOWN, on_dchan_down);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_HANGUP_REQ, on_hangup);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_HANGUP, on_hangup);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_INFO_RECEIVED, on_info);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RESTART, on_restart);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_IO_FAIL, on_io_fail);
+
+ if (down) {
+ ftdm_log(FTDM_LOG_INFO, "PRI back up on span %d\n", isdn_data->spri.span->span_id);
+ ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
+ down = 0;
+ }
+
+ isdn_data->spri.on_loop = check_flags;
+ isdn_data->spri.private_info = span;
+ lpwrap_run_pri(&isdn_data->spri);
+
+ }
+
+ if (!ftdm_running() || ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
+ break;
+ }
+
+ ftdm_log(FTDM_LOG_CRIT, "PRI down on span %d\n", isdn_data->spri.span->span_id);
+
+ if (!down) {
+ ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
+ check_state(span);
+ }
+
+ check_state(span);
+ check_events(span);
+
+ down++;
+ ftdm_sleep(5000);
+ }
+
+ ftdm_log(FTDM_LOG_DEBUG, "PRI thread ended on span %d\n", isdn_data->spri.span->span_id);
+
+ ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
+ ftdm_clear_flag(isdn_data, FTMOD_LIBPRI_RUNNING);
+
+ return NULL;
+}
+
+/**
+ * \brief Stops a libpri span
+ * \param span Span to halt
+ * \return Success
+ *
+ * Sets a stop flag and waits for the thread to end
+ */
+static ftdm_status_t ftdm_libpri_stop(ftdm_span_t *span)
+{
+ ftdm_libpri_data_t *isdn_data = span->signal_data;
+
+ if (!ftdm_test_flag(isdn_data, FTMOD_LIBPRI_RUNNING)) {
+ return FTDM_FAIL;
+ }
+
+ ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
+ check_state(span);
+ ftdm_set_flag(span, FTDM_SPAN_STOP_THREAD);
+ while(ftdm_test_flag(span, FTDM_SPAN_IN_THREAD)) {
+ ftdm_sleep(100);
+ }
+ check_state(span);
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Starts a libpri span
+ * \param span Span to halt
+ * \return Success or failure
+ *
+ * Launches a thread to monitor the span
+ */
+static ftdm_status_t ftdm_libpri_start(ftdm_span_t *span)
+{
+ ftdm_status_t ret;
+ ftdm_libpri_data_t *isdn_data = span->signal_data;
+
+ if (ftdm_test_flag(isdn_data, FTMOD_LIBPRI_RUNNING)) {
+ return FTDM_FAIL;
+ }
+
+ ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD);
+ ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
+
+ ftdm_set_flag(isdn_data, FTMOD_LIBPRI_RUNNING);
+ ret = ftdm_thread_create_detached(ftdm_libpri_run, span);
+
+ if (ret != FTDM_SUCCESS) {
+ return ret;
+ }
+
+ return ret;
+}
+
+/**
+ * \brief Converts a node string to node value
+ * \param node Node string to convert
+ * \return -1 on failure, node value on success
+ */
+static int str2node(char *node)
+{
+ if (!strcasecmp(node, "cpe") || !strcasecmp(node, "user"))
+ return PRI_CPE;
+ if (!strcasecmp(node, "network") || !strcasecmp(node, "net"))
+ return PRI_NETWORK;
+ return -1;
+}
+
+/**
+ * \brief Converts a switch string to switch value
+ * \param swtype Swtype string to convert
+ * \return Switch value
+ */
+static int str2switch(char *swtype)
+{
+ if (!strcasecmp(swtype, "ni1"))
+ return PRI_SWITCH_NI1;
+ if (!strcasecmp(swtype, "ni2"))
+ return PRI_SWITCH_NI2;
+ if (!strcasecmp(swtype, "dms100"))
+ return PRI_SWITCH_DMS100;
+ if (!strcasecmp(swtype, "lucent5e") || !strcasecmp(swtype, "5ess"))
+ return PRI_SWITCH_LUCENT5E;
+ if (!strcasecmp(swtype, "att4ess") || !strcasecmp(swtype, "4ess"))
+ return PRI_SWITCH_ATT4ESS;
+ if (!strcasecmp(swtype, "euroisdn"))
+ return PRI_SWITCH_EUROISDN_E1;
+ if (!strcasecmp(swtype, "gr303eoc"))
+ return PRI_SWITCH_GR303_EOC;
+ if (!strcasecmp(swtype, "gr303tmc"))
+ return PRI_SWITCH_GR303_TMC;
+ return PRI_SWITCH_DMS100;
+}
+
+/**
+ * \brief Converts a L1 string to L1 value
+ * \param l1 L1 string to convert
+ * \return L1 value
+ */
+static int str2l1(char *l1)
+{
+ if (!strcasecmp(l1, "alaw"))
+ return PRI_LAYER_1_ALAW;
+
+ return PRI_LAYER_1_ULAW;
+}
+
+/**
+ * \brief Converts a DP string to DP value
+ * \param dp DP string to convert
+ * \return DP value
+ */
+static int str2dp(char *dp)
+{
+ if (!strcasecmp(dp, "international"))
+ return PRI_INTERNATIONAL_ISDN;
+ if (!strcasecmp(dp, "national"))
+ return PRI_NATIONAL_ISDN;
+ if (!strcasecmp(dp, "local"))
+ return PRI_LOCAL_ISDN;
+ if (!strcasecmp(dp, "private"))
+ return PRI_PRIVATE;
+ if (!strcasecmp(dp, "unknown"))
+ return PRI_UNKNOWN;
+
+ return PRI_UNKNOWN;
+}
+
+/**
+ * \brief Initialises a libpri span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static FIO_SIG_CONFIGURE_FUNCTION(ftdm_libpri_configure_span)
+{
+ uint32_t i, x = 0;
+ //ftdm_channel_t *dchans[2] = {0};
+ ftdm_libpri_data_t *isdn_data;
+ char *var, *val;
+ char *debug = NULL;
+
+ if (span->trunk_type >= FTDM_TRUNK_NONE) {
+ ftdm_log(FTDM_LOG_WARNING, "Invalid trunk type '%s' defaulting to T1.\n", ftdm_trunk_type2str(span->trunk_type));
+ span->trunk_type = FTDM_TRUNK_T1;
+ }
+
+ for(i = 1; i <= span->chan_count; i++) {
+ if (span->channels[i]->type == FTDM_CHAN_TYPE_DQ921) {
+ if (x > 1) {
+ snprintf(span->last_error, sizeof(span->last_error), "Span has more than 2 D-Channels!");
+ return FTDM_FAIL;
+ } else {
+#if 0
+ if (ftdm_channel_open(span->span_id, i, &dchans[x]) == FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_DEBUG, "opening d-channel #%d %d:%d\n", x, dchans[x]->span_id, dchans[x]->chan_id);
+ dchans[x]->state = FTDM_CHANNEL_STATE_UP;
+ x++;
+ }
+#endif
+ }
+ }
+ }
+
+#if 0
+ if (!x) {
+ snprintf(span->last_error, sizeof(span->last_error), "Span has no D-Channels!");
+ return FTDM_FAIL;
+ }
+#endif
+
+ isdn_data = ftdm_malloc(sizeof(*isdn_data));
+ assert(isdn_data != NULL);
+ memset(isdn_data, 0, sizeof(*isdn_data));
+
+ if (span->trunk_type == FTDM_TRUNK_E1) {
+ ftdm_log(FTDM_LOG_NOTICE, "Setting default Layer 1 to ALAW since this is an E1 trunk\n");
+ isdn_data->l1 = PRI_LAYER_1_ALAW;
+ } else if (span->trunk_type == FTDM_TRUNK_T1) {
+ ftdm_log(FTDM_LOG_NOTICE, "Setting default Layer 1 to ULAW since this is a T1 trunk\n");
+ isdn_data->l1 = PRI_LAYER_1_ULAW;
+ }
+
+ while((var = va_arg(ap, char *))) {
+ if (!strcasecmp(var, "node")) {
+ int node;
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ node = str2node(val);
+ if (-1 == node) {
+ ftdm_log(FTDM_LOG_ERROR, "Unknown node type %s, defaulting to CPE mode\n", val);
+ node = PRI_CPE;
+ }
+ isdn_data->node = node;
+ } else if (!strcasecmp(var, "switch")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ isdn_data->pswitch = str2switch(val);
+ } else if (!strcasecmp(var, "opts")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ isdn_data->opts = parse_opts(val);
+ } else if (!strcasecmp(var, "dp")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ isdn_data->dp = str2dp(val);
+ } else if (!strcasecmp(var, "l1")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ isdn_data->l1 = str2l1(val);
+ } else if (!strcasecmp(var, "debug")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ debug = val;
+ } else {
+ snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+ return FTDM_FAIL;
+ }
+ }
+
+ span->start = ftdm_libpri_start;
+ span->stop = ftdm_libpri_stop;
+ span->signal_cb = sig_cb;
+ //isdn_data->dchans[0] = dchans[0];
+ //isdn_data->dchans[1] = dchans[1];
+ //isdn_data->dchan = isdn_data->dchans[0];
+
+ isdn_data->debug = parse_debug(debug);
+
+
+ span->signal_data = isdn_data;
+ span->signal_type = FTDM_SIGTYPE_ISDN;
+ span->outgoing_call = isdn_outgoing_call;
+
+ if ((isdn_data->opts & FTMOD_LIBPRI_OPT_SUGGEST_CHANNEL)) {
+ span->channel_request = isdn_channel_request;
+ span->suggest_chan_id = 1;
+ }
+
+ span->state_map = &isdn_state_map;
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief FreeTDM libpri signaling and IO module definition
+ */
+ftdm_module_t ftdm_module = {
+ "libpri",
+ ftdm_libpri_io_init,
+ ftdm_libpri_unload,
+ ftdm_libpri_init,
+ ftdm_libpri_configure_span,
+ NULL
+};
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2009, Anthony Minessale II
+ * 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.
+ */
+
+
+#ifndef FTMOD_LIBPRI_H
+#define FTMOD_LIBPRI_H
+#include "freetdm.h"
+#include "lpwrap_pri.h"
+
+typedef enum {
+ FTMOD_LIBPRI_OPT_NONE = 0,
+ FTMOD_LIBPRI_OPT_SUGGEST_CHANNEL = (1 << 0),
+ FTMOD_LIBPRI_OPT_OMIT_DISPLAY_IE = (1 << 1),
+ FTMOD_LIBPRI_OPT_OMIT_REDIRECTING_NUMBER_IE = (1 << 2),
+
+ FTMOD_LIBPRI_OPT_MAX = (1 << 3)
+} ftdm_isdn_opts_t;
+
+typedef enum {
+ FTMOD_LIBPRI_RUNNING = (1 << 0)
+} ftdm_isdn_flag_t;
+
+
+struct ftdm_libpri_data {
+ ftdm_channel_t *dchan;
+ ftdm_channel_t *dchans[2];
+ struct ftdm_sigmsg sigmsg;
+ uint32_t flags;
+ int32_t mode;
+ ftdm_isdn_opts_t opts;
+
+ int node;
+ int pswitch;
+ char *dialplan;
+ unsigned int l1;
+ unsigned int dp;
+
+ int debug;
+
+ lpwrap_pri_t spri;
+};
+
+typedef struct ftdm_libpri_data ftdm_libpri_data_t;
+
+
+/* b-channel private data */
+struct ftdm_isdn_bchan_data
+{
+ int32_t digit_timeout;
+};
+
+typedef struct ftdm_isdn_bchan_data ftdm_isdn_bchan_data_t;
+
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2009, Anthony Minessale II
+ * 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.
+ */
+
+//#define IODEBUG
+
+#include "freetdm.h"
+#include "lpwrap_pri.h"
+#ifndef HAVE_GETTIMEOFDAY
+
+#ifdef WIN32
+#include <mmsystem.h>
+
+static __inline int gettimeofday(struct timeval *tp, void *nothing)
+{
+#ifdef WITHOUT_MM_LIB
+ SYSTEMTIME st;
+ time_t tt;
+ struct tm tmtm;
+ /* mktime converts local to UTC */
+ GetLocalTime (&st);
+ tmtm.tm_sec = st.wSecond;
+ tmtm.tm_min = st.wMinute;
+ tmtm.tm_hour = st.wHour;
+ tmtm.tm_mday = st.wDay;
+ tmtm.tm_mon = st.wMonth - 1;
+ tmtm.tm_year = st.wYear - 1900; tmtm.tm_isdst = -1;
+ tt = mktime (&tmtm);
+ tp->tv_sec = tt;
+ tp->tv_usec = st.wMilliseconds * 1000;
+#else
+ /**
+ ** The earlier time calculations using GetLocalTime
+ ** had a time resolution of 10ms.The timeGetTime, part
+ ** of multimedia apis offer a better time resolution
+ ** of 1ms.Need to link against winmm.lib for this
+ **/
+ unsigned long Ticks = 0;
+ unsigned long Sec =0;
+ unsigned long Usec = 0;
+ Ticks = timeGetTime();
+
+ Sec = Ticks/1000;
+ Usec = (Ticks - (Sec*1000))*1000;
+ tp->tv_sec = Sec;
+ tp->tv_usec = Usec;
+#endif /* WITHOUT_MM_LIB */
+ (void)nothing;
+ return 0;
+}
+#endif /* WIN32 */
+#endif /* HAVE_GETTIMEOFDAY */
+
+static struct lpwrap_pri_event_list LPWRAP_PRI_EVENT_LIST[] = {
+ {0, LPWRAP_PRI_EVENT_ANY, "ANY"},
+ {1, LPWRAP_PRI_EVENT_DCHAN_UP, "DCHAN_UP"},
+ {2, LPWRAP_PRI_EVENT_DCHAN_DOWN, "DCHAN_DOWN"},
+ {3, LPWRAP_PRI_EVENT_RESTART, "RESTART"},
+ {4, LPWRAP_PRI_EVENT_CONFIG_ERR, "CONFIG_ERR"},
+ {5, LPWRAP_PRI_EVENT_RING, "RING"},
+ {6, LPWRAP_PRI_EVENT_HANGUP, "HANGUP"},
+ {7, LPWRAP_PRI_EVENT_RINGING, "RINGING"},
+ {8, LPWRAP_PRI_EVENT_ANSWER, "ANSWER"},
+ {9, LPWRAP_PRI_EVENT_HANGUP_ACK, "HANGUP_ACK"},
+ {10, LPWRAP_PRI_EVENT_RESTART_ACK, "RESTART_ACK"},
+ {11, LPWRAP_PRI_EVENT_FACNAME, "FACNAME"},
+ {12, LPWRAP_PRI_EVENT_INFO_RECEIVED, "INFO_RECEIVED"},
+ {13, LPWRAP_PRI_EVENT_PROCEEDING, "PROCEEDING"},
+ {14, LPWRAP_PRI_EVENT_SETUP_ACK, "SETUP_ACK"},
+ {15, LPWRAP_PRI_EVENT_HANGUP_REQ, "HANGUP_REQ"},
+ {16, LPWRAP_PRI_EVENT_NOTIFY, "NOTIFY"},
+ {17, LPWRAP_PRI_EVENT_PROGRESS, "PROGRESS"},
+ {18, LPWRAP_PRI_EVENT_KEYPAD_DIGIT, "KEYPAD_DIGIT"},
+ {19, LPWRAP_PRI_EVENT_IO_FAIL, "IO_FAIL"},
+};
+
+#define LINE "--------------------------------------------------------------------------------"
+
+const char *lpwrap_pri_event_str(lpwrap_pri_event_t event_id)
+{
+ return LPWRAP_PRI_EVENT_LIST[event_id].name;
+}
+
+static int __pri_lpwrap_read(struct pri *pri, void *buf, int buflen)
+{
+ struct lpwrap_pri *spri = (struct lpwrap_pri *) pri_get_userdata(pri);
+ ftdm_size_t len = buflen;
+ int res;
+ ftdm_status_t zst;
+
+ if ((zst = ftdm_channel_read(spri->dchan, buf, &len)) != FTDM_SUCCESS) {
+ if (zst == FTDM_FAIL) {
+ ftdm_log(FTDM_LOG_CRIT, "span %d D-READ FAIL! [%s]\n", spri->span->span_id, spri->dchan->last_error);
+ spri->errs++;
+ } else {
+ ftdm_log(FTDM_LOG_CRIT, "span %d D-READ TIMEOUT\n", spri->span->span_id);
+ }
+
+ ftdm_clear_flag(spri, LPWRAP_PRI_READY);
+ return -1;
+ }
+ spri->errs = 0;
+ res = (int)len;
+ memset(&((unsigned char*)buf)[res],0,2);
+ res+=2;
+
+#ifdef IODEBUG
+ {
+ char bb[2048] = { 0 };
+
+ print_hex_bytes(buf, res - 2, bb, sizeof(bb));
+ ftdm_log(FTDM_LOG_DEBUG, "READ %d\n", res-2);
+ }
+#endif
+
+ return res;
+}
+
+static int __pri_lpwrap_write(struct pri *pri, void *buf, int buflen)
+{
+ struct lpwrap_pri *spri = (struct lpwrap_pri *) pri_get_userdata(pri);
+ ftdm_size_t len = buflen -2;
+
+ if (ftdm_channel_write(spri->dchan, buf, buflen, &len) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_CRIT, "span %d D-WRITE FAIL! [%s]\n", spri->span->span_id, spri->dchan->last_error);
+ ftdm_clear_flag(spri, LPWRAP_PRI_READY);
+ return -1;
+ }
+
+#ifdef IODEBUG
+ {
+ char bb[2048] = { 0 };
+
+ print_hex_bytes(buf, buflen - 2, bb, sizeof(bb));
+ ftdm_log(FTDM_LOG_DEBUG, "WRITE %d\n", (int)buflen-2);
+ }
+#endif
+
+ return (int) buflen;
+}
+
+int lpwrap_init_pri(struct lpwrap_pri *spri, ftdm_span_t *span, ftdm_channel_t *dchan, int swtype, int node, int debug)
+{
+ int ret = -1;
+
+ memset(spri, 0, sizeof(struct lpwrap_pri));
+
+ spri->dchan = dchan;
+ spri->span = span;
+
+ if ((spri->pri = pri_new_cb(spri->dchan->sockfd, node, swtype, __pri_lpwrap_read, __pri_lpwrap_write, spri))){
+ unsigned char buf[4] = { 0 };
+ size_t buflen = sizeof(buf), len = 0;
+ pri_set_debug(spri->pri, debug);
+ ret = 0;
+ ftdm_set_flag(spri, LPWRAP_PRI_READY);
+ ftdm_channel_write(spri->dchan, buf, buflen, &len);
+ } else {
+ fprintf(stderr, "Unable to create PRI\n");
+ }
+
+ return ret;
+}
+
+
+int lpwrap_one_loop(struct lpwrap_pri *spri)
+{
+ fd_set rfds, efds;
+ struct timeval now = {0,0}, *next;
+ pri_event *event;
+ event_handler handler;
+ int sel;
+
+ if (spri->on_loop) {
+ if ((sel = spri->on_loop(spri)) < 0) {
+ return sel;
+ }
+ }
+
+ if (spri->errs >= 2) {
+ spri->errs = 0;
+ return -1;
+ }
+
+ FD_ZERO(&rfds);
+ FD_ZERO(&efds);
+
+#ifdef _MSC_VER
+ //Windows macro for FD_SET includes a warning C4127: conditional expression is constant
+#pragma warning(push)
+#pragma warning(disable:4127)
+#endif
+
+ FD_SET(pri_fd(spri->pri), &rfds);
+ FD_SET(pri_fd(spri->pri), &efds);
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+ now.tv_sec = 0;
+ now.tv_usec = 100000;
+
+ sel = select(pri_fd(spri->pri) + 1, &rfds, NULL, &efds, &now);
+
+ event = NULL;
+
+ if (!sel) {
+ if ((next = pri_schedule_next(spri->pri))) {
+ gettimeofday(&now, NULL);
+ if (now.tv_sec >= next->tv_sec && (now.tv_usec >= next->tv_usec || next->tv_usec <= 100000)) {
+ //ftdm_log(FTDM_LOG_DEBUG, "Check event\n");
+ event = pri_schedule_run(spri->pri);
+ }
+ }
+ } else if (sel > 0) {
+ event = pri_check_event(spri->pri);
+ }
+
+ if (event) {
+ /* 0 is catchall event handler */
+ if ((handler = spri->eventmap[event->e] ? spri->eventmap[event->e] : spri->eventmap[0] ? spri->eventmap[0] : NULL)) {
+ handler(spri, event->e, event);
+ } else {
+ ftdm_log(FTDM_LOG_CRIT, "No event handler found for event %d.\n", event->e);
+ }
+ }
+
+
+ return sel;
+
+
+ if ((handler = spri->eventmap[LPWRAP_PRI_EVENT_IO_FAIL] ? spri->eventmap[LPWRAP_PRI_EVENT_IO_FAIL] : spri->eventmap[0] ? spri->eventmap[0] : NULL)) {
+ handler(spri, LPWRAP_PRI_EVENT_IO_FAIL, NULL);
+ }
+
+ return -1;
+}
+
+int lpwrap_run_pri(struct lpwrap_pri *spri)
+{
+ int ret = 0;
+
+ for (;;){
+ ret = lpwrap_one_loop(spri);
+
+ if (ret < 0) {
+
+#ifndef WIN32 //This needs to be adressed fror WIN32 still
+ if (errno == EINTR){
+ /* Igonore an interrupted system call */
+ continue;
+ }
+#endif
+ ftdm_log(FTDM_LOG_CRIT, "Error = %i [%s]\n", ret, strerror(errno));
+ break;
+ }
+ }
+
+ return ret;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2009, Anthony Minessale II
+ * 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.
+ */
+
+#ifndef _LPWRAP_PRI_H
+#define _LPWRAP_PRI_H
+#include <libpri.h>
+#include <freetdm.h>
+
+
+#define LPWRAP_MAX_CHAN_PER_SPAN 32
+
+typedef enum {
+ LPWRAP_PRI_EVENT_ANY = 0,
+ LPWRAP_PRI_EVENT_DCHAN_UP = PRI_EVENT_DCHAN_UP,
+ LPWRAP_PRI_EVENT_DCHAN_DOWN = PRI_EVENT_DCHAN_DOWN,
+ LPWRAP_PRI_EVENT_RESTART = PRI_EVENT_RESTART,
+ LPWRAP_PRI_EVENT_CONFIG_ERR = PRI_EVENT_CONFIG_ERR,
+ LPWRAP_PRI_EVENT_RING = PRI_EVENT_RING,
+ LPWRAP_PRI_EVENT_HANGUP = PRI_EVENT_HANGUP,
+ LPWRAP_PRI_EVENT_RINGING = PRI_EVENT_RINGING,
+ LPWRAP_PRI_EVENT_ANSWER = PRI_EVENT_ANSWER,
+ LPWRAP_PRI_EVENT_HANGUP_ACK = PRI_EVENT_HANGUP_ACK,
+ LPWRAP_PRI_EVENT_RESTART_ACK = PRI_EVENT_RESTART_ACK,
+ LPWRAP_PRI_EVENT_FACNAME = PRI_EVENT_FACNAME,
+ LPWRAP_PRI_EVENT_INFO_RECEIVED = PRI_EVENT_INFO_RECEIVED,
+ LPWRAP_PRI_EVENT_PROCEEDING = PRI_EVENT_PROCEEDING,
+ LPWRAP_PRI_EVENT_SETUP_ACK = PRI_EVENT_SETUP_ACK,
+ LPWRAP_PRI_EVENT_HANGUP_REQ = PRI_EVENT_HANGUP_REQ,
+ LPWRAP_PRI_EVENT_NOTIFY = PRI_EVENT_NOTIFY,
+ LPWRAP_PRI_EVENT_PROGRESS = PRI_EVENT_PROGRESS,
+ LPWRAP_PRI_EVENT_KEYPAD_DIGIT = PRI_EVENT_KEYPAD_DIGIT,
+ LPWRAP_PRI_EVENT_IO_FAIL = 19,
+
+ /* don't touch */
+ LPWRAP_PRI_EVENT_MAX
+} lpwrap_pri_event_t;
+
+typedef enum {
+ LPWRAP_PRI_NETWORK = PRI_NETWORK,
+ LPWRAP_PRI_CPE = PRI_CPE
+} lpwrap_pri_node_t;
+
+typedef enum {
+ LPWRAP_PRI_SWITCH_UNKNOWN = PRI_SWITCH_UNKNOWN,
+ LPWRAP_PRI_SWITCH_NI2 = PRI_SWITCH_NI2,
+ LPWRAP_PRI_SWITCH_DMS100 = PRI_SWITCH_DMS100,
+ LPWRAP_PRI_SWITCH_LUCENT5E = PRI_SWITCH_LUCENT5E,
+ LPWRAP_PRI_SWITCH_ATT4ESS = PRI_SWITCH_ATT4ESS,
+ LPWRAP_PRI_SWITCH_EUROISDN_E1 = PRI_SWITCH_EUROISDN_E1,
+ LPWRAP_PRI_SWITCH_EUROISDN_T1 = PRI_SWITCH_EUROISDN_T1,
+ LPWRAP_PRI_SWITCH_NI1 = PRI_SWITCH_NI1,
+ LPWRAP_PRI_SWITCH_GR303_EOC = PRI_SWITCH_GR303_EOC,
+ LPWRAP_PRI_SWITCH_GR303_TMC = PRI_SWITCH_GR303_TMC,
+ LPWRAP_PRI_SWITCH_QSIG = PRI_SWITCH_QSIG,
+
+ /* don't touch */
+ LPWRAP_PRI_SWITCH_MAX
+} lpwrap_pri_switch_t;
+
+typedef enum {
+ LPWRAP_PRI_READY = (1 << 0)
+} lpwrap_pri_flag_t;
+
+struct lpwrap_pri;
+typedef int (*event_handler)(struct lpwrap_pri *, lpwrap_pri_event_t, pri_event *);
+typedef int (*loop_handler)(struct lpwrap_pri *);
+
+struct lpwrap_pri {
+ struct pri *pri;
+ ftdm_span_t *span;
+ ftdm_channel_t *dchan;
+ unsigned int flags;
+ void *private_info;
+ event_handler eventmap[LPWRAP_PRI_EVENT_MAX];
+ loop_handler on_loop;
+ int errs;
+};
+
+typedef struct lpwrap_pri lpwrap_pri_t;
+
+struct lpwrap_pri_event_list {
+ int event_id;
+ int pri_event;
+ const char *name;
+};
+
+
+
+#define LPWRAP_MAP_PRI_EVENT(spri, event, func) spri.eventmap[event] = func;
+
+const char *lpwrap_pri_event_str(lpwrap_pri_event_t event_id);
+int lpwrap_one_loop(struct lpwrap_pri *spri);
+int lpwrap_init_pri(struct lpwrap_pri *spri, ftdm_span_t *span, ftdm_channel_t *dchan, int swtype, int node, int debug);
+int lpwrap_run_pri(struct lpwrap_pri *spri);
+
+#endif
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftdm_pika.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftdm_pika.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftdm_pika.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#ifndef FTDM_PIKA_H
+#define FTDM_PIKA_H
+#include "freetdm.h"
+#include "pikahmpapi.h"
+
+
+
+#define PIKA_STR2ENUM_P(_FUNC1, _FUNC2, _TYPE) _TYPE _FUNC1 (const char *name); const char * _FUNC2 (_TYPE type);
+#define PIKA_STR2ENUM(_FUNC1, _FUNC2, _TYPE, _STRINGS, _MAX) \
+ _TYPE _FUNC1 (const char *name) \
+ { \
+ int i; \
+ _TYPE t = _MAX ; \
+ \
+ for (i = 0; i < _MAX ; i++) { \
+ if (!strcasecmp(name, _STRINGS[i])) { \
+ t = (_TYPE) i; \
+ break; \
+ } \
+ } \
+ \
+ return t; \
+ } \
+ const char * _FUNC2 (_TYPE type) \
+ { \
+ if (type > _MAX) { \
+ type = _MAX; \
+ } \
+ return _STRINGS[(int)type]; \
+ }
+
+
+typedef enum {
+ PIKA_SPAN_FRAMING_T1_D4,
+ PIKA_SPAN_FRAMING_T1_ESF,
+ PIKA_SPAN_FRAMING_E1_BASIC,
+ PIKA_SPAN_FRAMING_E1_CRC4,
+ PIKA_SPAN_INVALID
+} PIKA_TSpanFraming;
+#define PIKA_SPAN_STRINGS "T1_D4", "T1_ESF", "E1_BASIC", "E1_CRC4"
+PIKA_STR2ENUM_P(pika_str2span, pika_span2str, PIKA_TSpanFraming)
+
+typedef enum {
+ PIKA_SPAN_ENCODING_T1_AMI_ZS_NONE,
+ PIKA_SPAN_ENCODING_T1_AMI_ZS_GTE,
+ PIKA_SPAN_ENCODING_T1_AMI_ZS_BELL,
+ PIKA_SPAN_ENCODING_T1_AMI_ZS_JAM8,
+ PIKA_SPAN_ENCODING_T1_B8ZS,
+ PIKA_SPAN_ENCODING_E1_AMI,
+ PIKA_SPAN_ENCODING_E1_HDB3,
+ PIKA_SPAN_ENCODING_INVALID
+} PIKA_TSpanEncoding;
+#define PIKA_SPAN_ENCODING_STRINGS "T1_AMI_ZS_NONE", "T1_AMI_ZS_GTE", "T1_AMI_ZS_BELL", "T1_AMI_ZS_JAM8", "T1_B8ZS", "E1_AMI", "E1_HDB3"
+PIKA_STR2ENUM_P(pika_str2span_encoding, pika_span_encoding2str, PIKA_TSpanEncoding)
+
+typedef enum {
+ PIKA_SPAN_LOOP_LENGTH_SHORT_HAUL,
+ PIKA_SPAN_LOOP_LENGTH_LONG_HAUL,
+ PIKA_SPAN_LOOP_INVALID
+} PIKA_TSpanLoopLength;
+#define PIKA_LL_STRINGS "SHORT_HAUL", "LONG_HAUL"
+PIKA_STR2ENUM_P(pika_str2loop_length, pika_loop_length2str, PIKA_TSpanLoopLength)
+
+typedef enum {
+ PIKA_SPAN_LBO_T1_LONG_0_DB,
+ PIKA_SPAN_LBO_T1_LONG_7_DB,
+ PIKA_SPAN_LBO_T1_LONG_15_DB,
+ PIKA_SPAN_LBO_T1_LONG_22_DB,
+ PIKA_SPAN_LBO_T1_SHORT_133_FT,
+ PIKA_SPAN_LBO_T1_SHORT_266_FT,
+ PIKA_SPAN_LBO_T1_SHORT_399_FT,
+ PIKA_SPAN_LBO_T1_SHORT_533_FT,
+ PIKA_SPAN_LBO_T1_SHORT_655_FT,
+ PIKA_SPAN_LBO_E1_WAVEFORM_120_OHM,
+ PIKA_SPAN_LBO_INVALID
+} PIKA_TSpanBuildOut;
+#define PIKA_LBO_STRINGS "T1_LONG_0_DB", "T1_LONG_7_DB", "T1_LONG_15_DB", "T1_LONG_22_DB", "T1_SHORT_133_FT", "T1_SHORT_266_FT", "T1_SHORT_399_FT", "T1_SHORT_533_FT", "T1_SHORT_655_FT", "E1_WAVEFORM_120_OHM"
+PIKA_STR2ENUM_P(pika_str2lbo, pika_lbo2str, PIKA_TSpanBuildOut)
+
+typedef enum {
+ PIKA_SPAN_COMPAND_MODE_MU_LAW = 1,
+ PIKA_SPAN_COMPAND_MODE_A_LAW,
+ PIKA_SPAN_COMPAND_MODE_INVALID
+} PIKA_TSpanCompandMode;
+#define PIKA_SPAN_COMPAND_MODE_STRINGS "MU_LAW", "A_LAW"
+PIKA_STR2ENUM_P(pika_str2compand_mode, pika_compand_mode2str, PIKA_TSpanCompandMode)
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="ftmod_pika"
+ ProjectGUID="{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}"
+ RootNamespace="ftmod_pika"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_PIKA_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="pikahmpapi.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="..\..\..\pika\aoh\lib"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_PIKA_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="pikahmpapi.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="..\..\..\pika\aoh\lib"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\ftmod_pika.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\ftdm_pika.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1469 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+
+#include "freetdm.h"
+#include "ftdm_pika.h"
+
+
+#define MAX_NUMBER_OF_TRUNKS 64
+#define PIKA_BLOCK_SIZE 160
+#define PIKA_BLOCK_LEN 20
+#define PIKA_NUM_BUFFERS 8
+#define TRY_OR_DIE(__code, __status, __label) if ((status = __code ) != __status) goto __label
+#define pk_atof(__a) (PK_FLOAT) atof(__a)
+
+PK_VOID PK_CALLBACK media_out_callback(PKH_TPikaEvent *event);
+
+FTDM_ENUM_NAMES(PIKA_SPAN_NAMES, PIKA_SPAN_STRINGS)
+PIKA_STR2ENUM(pika_str2span, pika_span2str, PIKA_TSpanFraming, PIKA_SPAN_NAMES, PIKA_SPAN_INVALID)
+
+FTDM_ENUM_NAMES(PIKA_SPAN_ENCODING_NAMES, PIKA_SPAN_ENCODING_STRINGS)
+PIKA_STR2ENUM(pika_str2span_encoding, pika_span_encoding2str, PIKA_TSpanEncoding, PIKA_SPAN_ENCODING_NAMES, PIKA_SPAN_ENCODING_INVALID)
+
+FTDM_ENUM_NAMES(PIKA_LL_NAMES, PIKA_LL_STRINGS)
+PIKA_STR2ENUM(pika_str2loop_length, pika_loop_length2str, PIKA_TSpanLoopLength, PIKA_LL_NAMES, PIKA_SPAN_LOOP_INVALID)
+
+FTDM_ENUM_NAMES(PIKA_LBO_NAMES, PIKA_LBO_STRINGS)
+PIKA_STR2ENUM(pika_str2lbo, pika_lbo2str, PIKA_TSpanBuildOut, PIKA_LBO_NAMES, PIKA_SPAN_LBO_INVALID)
+
+FTDM_ENUM_NAMES(PIKA_SPAN_COMPAND_MODE_NAMES, PIKA_SPAN_COMPAND_MODE_STRINGS)
+PIKA_STR2ENUM(pika_str2compand_mode, pika_compand_mode2str, PIKA_TSpanCompandMode, PIKA_SPAN_COMPAND_MODE_NAMES, PIKA_SPAN_COMPAND_MODE_INVALID)
+
+
+typedef enum {
+ PK_FLAG_READY = (1 << 0),
+ PK_FLAG_LOCKED = (1 << 1)
+} pk_flag_t;
+
+struct general_config {
+ uint32_t region;
+};
+typedef struct general_config general_config_t;
+
+struct pika_channel_profile {
+ char name[80];
+ PKH_TRecordConfig record_config;
+ PKH_TPlayConfig play_config;
+ int ec_enabled;
+ PKH_TECConfig ec_config;
+ PKH_TSpanConfig span_config;
+ general_config_t general_config;
+ int cust_span;
+};
+typedef struct pika_channel_profile pika_channel_profile_t;
+
+static struct {
+ PKH_TSystemDeviceList board_list;
+ TPikaHandle open_boards[MAX_NUMBER_OF_TRUNKS];
+ TPikaHandle system_handle;
+ PKH_TSystemConfig system_config;
+ PKH_TRecordConfig record_config;
+ PKH_TPlayConfig play_config;
+ PKH_TECConfig ec_config;
+ PKH_TSpanConfig t1_span_config;
+ PKH_TSpanConfig e1_span_config;
+ ftdm_hash_t *profile_hash;
+ general_config_t general_config;
+} globals;
+
+
+struct pika_span_data {
+ TPikaHandle event_queue;
+ PKH_TPikaEvent last_oob_event;
+ uint32_t boardno;
+ PKH_TSpanConfig span_config;
+ TPikaHandle handle;
+ uint32_t flags;
+};
+typedef struct pika_span_data pika_span_data_t;
+
+struct pika_chan_data {
+ TPikaHandle handle;
+ TPikaHandle media_in;
+ TPikaHandle media_out;
+ TPikaHandle media_in_queue;
+ TPikaHandle media_out_queue;
+ PKH_TPikaEvent last_media_event;
+ PKH_TPikaEvent last_oob_event;
+ PKH_TRecordConfig record_config;
+ PKH_TPlayConfig play_config;
+ int ec_enabled;
+ PKH_TECConfig ec_config;
+ PKH_THDLCConfig hdlc_config;
+ ftdm_buffer_t *digit_buffer;
+ ftdm_mutex_t *digit_mutex;
+ ftdm_size_t dtmf_len;
+ uint32_t flags;
+ uint32_t hdlc_bytes;
+};
+typedef struct pika_chan_data pika_chan_data_t;
+
+static const char *pika_board_type_string(PK_UINT type)
+{
+ if (type == PKH_BOARD_TYPE_DIGITAL_GATEWAY) {
+ return "digital_gateway";
+ }
+
+ if (type == PKH_BOARD_TYPE_ANALOG_GATEWAY) {
+ return "analog_gateway";
+ }
+
+ return "unknown";
+}
+
+/**
+ * \brief Process configuration variable for a pika profile
+ * \param category Pika profile name
+ * \param var Variable name
+ * \param val Variable value
+ * \param lineno Line number from configuration file (unused)
+ * \return Success
+ */
+static FIO_CONFIGURE_FUNCTION(pika_configure)
+{
+ pika_channel_profile_t *profile = NULL;
+ int ok = 1;
+
+ if (!(profile = (pika_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)category))) {
+ profile = ftdm_malloc(sizeof(*profile));
+ memset(profile, 0, sizeof(*profile));
+ ftdm_set_string(profile->name, category);
+ profile->ec_config = globals.ec_config;
+ profile->record_config = globals.record_config;
+ profile->play_config = globals.play_config;
+ hashtable_insert(globals.profile_hash, (void *)profile->name, profile, HASHTABLE_FLAG_NONE);
+ ftdm_log(FTDM_LOG_INFO, "creating profile [%s]\n", category);
+ }
+
+ if (!strcasecmp(var, "rx-gain")) {
+ profile->record_config.gain = pk_atof(val);
+ } else if (!strcasecmp(var, "rx-agc-enabled")) {
+ profile->record_config.AGC.enabled = ftdm_true(val);
+ } else if (!strcasecmp(var, "rx-agc-targetPower")) {
+ profile->record_config.AGC.targetPower = pk_atof(val);
+ } else if (!strcasecmp(var, "rx-agc-minGain")) {
+ profile->record_config.AGC.minGain = pk_atof(val);
+ } else if (!strcasecmp(var, "rx-agc-maxGain")) {
+ profile->record_config.AGC.maxGain = pk_atof(val);
+ } else if (!strcasecmp(var, "rx-agc-attackRate")) {
+ profile->record_config.AGC.attackRate = atoi(val);
+ } else if (!strcasecmp(var, "rx-agc-decayRate")) {
+ profile->record_config.AGC.decayRate = atoi(val);
+ } else if (!strcasecmp(var, "rx-agc-speechThreshold")) {
+ profile->record_config.AGC.speechThreshold = pk_atof(val);
+ } else if (!strcasecmp(var, "rx-vad-enabled")) {
+ profile->record_config.VAD.enabled = ftdm_true(val);
+ } else if (!strcasecmp(var, "rx-vad-activationThreshold")) {
+ profile->record_config.VAD.activationThreshold = pk_atof(val);
+ } else if (!strcasecmp(var, "rx-vad-activationDebounceTime")) {
+ profile->record_config.VAD.activationDebounceTime = atoi(val);
+ } else if (!strcasecmp(var, "rx-vad-deactivationThreshold")) {
+ profile->record_config.VAD.deactivationThreshold = pk_atof(val);
+ } else if (!strcasecmp(var, "rx-vad-deactivationDebounceTime")) {
+ profile->record_config.VAD.deactivationDebounceTime = atoi(val);
+ } else if (!strcasecmp(var, "rx-vad-preSpeechBufferSize")) {
+ profile->record_config.VAD.preSpeechBufferSize = atoi(val);
+ } else if (!strcasecmp(var, "tx-gain")) {
+ profile->play_config.gain = pk_atof(val);
+ } else if (!strcasecmp(var, "tx-agc-enabled")) {
+ profile->play_config.AGC.enabled = ftdm_true(val);
+ } else if (!strcasecmp(var, "tx-agc-targetPower")) {
+ profile->play_config.AGC.targetPower = pk_atof(val);
+ } else if (!strcasecmp(var, "tx-agc-minGain")) {
+ profile->play_config.AGC.minGain = pk_atof(val);
+ } else if (!strcasecmp(var, "tx-agc-maxGain")) {
+ profile->play_config.AGC.maxGain = pk_atof(val);
+ } else if (!strcasecmp(var, "tx-agc-attackRate")) {
+ profile->play_config.AGC.attackRate = atoi(val);
+ } else if (!strcasecmp(var, "tx-agc-decayRate")) {
+ profile->play_config.AGC.decayRate = atoi(val);
+ } else if (!strcasecmp(var, "tx-agc-speechThreshold")) {
+ profile->play_config.AGC.speechThreshold = pk_atof(val);
+ } else if (!strcasecmp(var, "ec-enabled")) {
+ profile->ec_enabled = ftdm_true(val);
+ } else if (!strcasecmp(var, "ec-doubleTalkerThreshold")) {
+ profile->ec_config.doubleTalkerThreshold = pk_atof(val);
+ } else if (!strcasecmp(var, "ec-speechPresentThreshold")) {
+ profile->ec_config.speechPresentThreshold = pk_atof(val);
+ } else if (!strcasecmp(var, "ec-echoSuppressionThreshold")) {
+ profile->ec_config.echoSuppressionThreshold = pk_atof(val);
+ } else if (!strcasecmp(var, "ec-echoSuppressionEnabled")) {
+ profile->ec_config.echoSuppressionEnabled = ftdm_true(val);
+ } else if (!strcasecmp(var, "ec-comfortNoiseEnabled")) {
+ profile->ec_config.comfortNoiseEnabled = ftdm_true(val);
+ } else if (!strcasecmp(var, "ec-adaptationModeEnabled")) {
+ profile->ec_config.adaptationModeEnabled = ftdm_true(val);
+ } else if (!strcasecmp(var, "framing")) {
+ profile->span_config.framing = pika_str2span(val);
+ profile->cust_span++;
+ } else if (!strcasecmp(var, "encoding")) {
+ profile->span_config.encoding = pika_str2span_encoding(val);
+ profile->cust_span++;
+ } else if (!strcasecmp(var, "loopLength")) {
+ profile->span_config.loopLength = pika_str2loop_length(val);
+ profile->cust_span++;
+ } else if (!strcasecmp(var, "buildOut")) {
+ profile->span_config.buildOut = pika_str2lbo(val);
+ profile->cust_span++;
+ } else if (!strcasecmp(var, "compandMode")) {
+ profile->span_config.compandMode = pika_str2compand_mode(val);
+ profile->cust_span++;
+ } else if (!strcasecmp(var, "region")) {
+ if (!strcasecmp(val, "eu")) {
+ profile->general_config.region = PKH_TRUNK_EU;
+ } else {
+ profile->general_config.region = PKH_TRUNK_NA;
+ }
+ } else {
+ ok = 0;
+ }
+
+ if (ok) {
+ ftdm_log(FTDM_LOG_INFO, "setting param [%s]=[%s] for profile [%s]\n", var, val, category);
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "unknown param [%s]\n", var);
+ }
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Pika event handler
+ * \param event Pika event
+ */
+PK_VOID PK_CALLBACK media_out_callback(PKH_TPikaEvent *event)
+{
+ PK_STATUS pk_status;
+ ftdm_channel_t *ftdmchan = event->userData;
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->mod_data;
+
+ //PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+ //PKH_EVENT_GetText(event->id, event_text, sizeof(event_text));
+ //ftdm_log(FTDM_LOG_DEBUG, "Event: %s\n", event_text);
+
+ switch (event->id) {
+ case PKH_EVENT_PLAY_IDLE:
+ {
+ while (ftdm_buffer_inuse(chan_data->digit_buffer)) {
+ char dtmf[128] = "";
+ ftdm_mutex_lock(chan_data->digit_mutex);
+ chan_data->dtmf_len = ftdm_buffer_read(chan_data->digit_buffer, dtmf, sizeof(dtmf));
+ pk_status = PKH_TG_PlayDTMF(chan_data->media_out, dtmf);
+ ftdm_mutex_unlock(chan_data->digit_mutex);
+ }
+ }
+ break;
+ case PKH_EVENT_TG_TONE_PLAYED:
+ {
+
+ if (!event->p1) {
+ ftdm_mutex_lock(chan_data->digit_mutex);
+ PKH_PLAY_Start(chan_data->media_out);
+ chan_data->dtmf_len = 0;
+ ftdm_mutex_unlock(chan_data->digit_mutex);
+ }
+
+
+ }
+ break;
+ default:
+ break;
+ }
+
+}
+
+/**
+ * \brief Initialises a range of pika channels
+ * \param span FreeTDM span
+ * \param boardno Pika board number
+ * \param spanno Pika span number
+ * \param start Initial pika channel number
+ * \param end Final pika channel number
+ * \param type FreeTDM channel type
+ * \param name FreeTDM span name
+ * \param number FreeTDM span number
+ * \param profile Pika channel profile
+ * \return number of spans configured
+ */
+static unsigned pika_open_range(ftdm_span_t *span, unsigned boardno, unsigned spanno, unsigned start, unsigned end,
+ ftdm_chan_type_t type, char *name, char *number, pika_channel_profile_t *profile)
+{
+ unsigned configured = 0, x;
+ PK_STATUS status;
+ PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
+ pika_span_data_t *span_data;
+
+ if (boardno >= globals.board_list.numberOfBoards) {
+ ftdm_log(FTDM_LOG_ERROR, "Board %u is not present!\n", boardno);
+ return 0;
+ }
+
+ if (!globals.open_boards[boardno]) {
+ status = PKH_BOARD_Open(globals.board_list.board[boardno].id,
+ NULL,
+ &globals.open_boards[boardno]);
+ if(status != PK_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error: PKH_BOARD_Open %d failed(%s)!\n", boardno,
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+ return 0;
+ }
+
+ ftdm_log(FTDM_LOG_DEBUG, "Open board %u\n", boardno);
+
+ //PKH_BOARD_SetDebugTrace(globals.open_boards[boardno], 1, 0);
+
+ }
+
+ if (span->mod_data) {
+ span_data = span->mod_data;
+ } else {
+ span_data = ftdm_malloc(sizeof(*span_data));
+ assert(span_data != NULL);
+ memset(span_data, 0, sizeof(*span_data));
+ span_data->boardno = boardno;
+
+ status = PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &span_data->event_queue);
+
+ if (status != PK_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error: PKH_QUEUE_Create failed(%s)!\n",
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+ ftdm_safe_free(span_data);
+ return 0;
+ }
+
+ //PKH_QUEUE_Attach(span_data->event_queue, globals.open_boards[boardno], NULL);
+
+ span->mod_data = span_data;
+ }
+
+ if (type == FTDM_CHAN_TYPE_FXS || type == FTDM_CHAN_TYPE_FXO) {
+ start--;
+ end--;
+ }
+
+ for(x = start; x < end; x++) {
+ ftdm_channel_t *chan;
+ pika_chan_data_t *chan_data = NULL;
+
+ chan_data = ftdm_malloc(sizeof *chan_data);
+ assert(chan_data);
+ memset(chan_data, 0, sizeof(*chan_data));
+ ftdm_span_add_channel(span, 0, type, &chan);
+ chan->mod_data = chan_data;
+
+ if ((type == FTDM_CHAN_TYPE_B || type == FTDM_CHAN_TYPE_DQ921) && !span_data->handle) {
+ PKH_TBoardConfig boardConfig;
+
+ TRY_OR_DIE(PKH_BOARD_GetConfig(globals.open_boards[boardno], &boardConfig), PK_SUCCESS, error);
+ if ((profile && profile->general_config.region == PKH_TRUNK_EU) || ftdm_test_flag(span_data, PK_FLAG_LOCKED)) {
+ if (span->trunk_type == FTDM_TRUNK_T1) {
+ ftdm_log(FTDM_LOG_WARNING, "Changing trunk type to E1 based on previous config.\n");
+ }
+ span->trunk_type = FTDM_TRUNK_E1;
+ }
+
+ if (span->trunk_type == FTDM_TRUNK_T1) {
+ if (ftdm_test_flag(span_data, PK_FLAG_LOCKED)) {
+ ftdm_log(FTDM_LOG_WARNING, "Already locked into E1 mode!\n");
+ }
+ } else if (span->trunk_type == FTDM_TRUNK_E1) {
+ boardConfig.specific.DigitalGateway.interfaceType = PKH_BOARD_INTERFACE_TYPE_E1;
+ if ((status = PKH_BOARD_SetConfig(globals.open_boards[boardno], &boardConfig)) != PK_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error: [%s]\n",
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+ }
+ ftdm_set_flag(span_data, PK_FLAG_LOCKED);
+ }
+
+ TRY_OR_DIE(PKH_SPAN_Open(globals.open_boards[boardno], spanno, NULL, &span_data->handle), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_SPAN_GetConfig(span_data->handle, &span_data->span_config), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, span_data->handle, (PK_VOID*) span), PK_SUCCESS, error);
+ }
+
+ if (type == FTDM_CHAN_TYPE_FXO) {
+ PKH_TTrunkConfig trunkConfig;
+
+ TRY_OR_DIE(PKH_TRUNK_Open(globals.open_boards[boardno], x, &chan_data->handle), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_TRUNK_Seize(chan_data->handle), PK_SUCCESS, error);
+
+ if (profile && profile->general_config.region == PKH_TRUNK_EU) {
+ TRY_OR_DIE(PKH_TRUNK_GetConfig(chan_data->handle, &trunkConfig), PK_SUCCESS, error);
+ trunkConfig.internationalControl = PKH_PHONE_INTERNATIONAL_CONTROL_EU;
+ trunkConfig.audioFormat = PKH_AUDIO_ALAW;
+ trunkConfig.compandMode = PKH_PHONE_AUDIO_ALAW;
+ chan->native_codec = chan->effective_codec = FTDM_CODEC_ALAW;
+ TRY_OR_DIE(PKH_TRUNK_SetConfig(chan_data->handle, &trunkConfig), PK_SUCCESS, error);
+ } else {
+ chan->native_codec = chan->effective_codec = FTDM_CODEC_ULAW;
+ }
+
+
+ TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_TRUNK_GetMediaStreams(chan_data->handle, &chan_data->media_in, &chan_data->media_out), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->media_in, (PK_VOID*) chan), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_CALLBACK, &chan_data->media_out_queue), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_SetEventHandler(chan_data->media_out_queue, media_out_callback), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_out_queue, chan_data->media_out, (PK_VOID*) chan), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_TRUNK_Start(chan_data->handle), PK_SUCCESS, error);
+ } else if (type == FTDM_CHAN_TYPE_FXS) {
+ PKH_TPhoneConfig phoneConfig;
+
+ if (profile && profile->general_config.region == PKH_TRUNK_EU) {
+ TRY_OR_DIE(PKH_PHONE_GetConfig(chan_data->handle, &phoneConfig), PK_SUCCESS, error);
+ phoneConfig.internationalControl = PKH_PHONE_INTERNATIONAL_CONTROL_EU;
+ phoneConfig.compandMode = PKH_PHONE_AUDIO_ALAW;
+ chan->native_codec = chan->effective_codec = FTDM_CODEC_ALAW;
+ TRY_OR_DIE(PKH_PHONE_SetConfig(chan_data->handle, &phoneConfig), PK_SUCCESS, error);
+ } else {
+ chan->native_codec = chan->effective_codec = FTDM_CODEC_ULAW;
+ }
+
+ TRY_OR_DIE(PKH_PHONE_Open(globals.open_boards[boardno], x, &chan_data->handle), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_PHONE_Seize(chan_data->handle), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_PHONE_GetMediaStreams(chan_data->handle, &chan_data->media_in, &chan_data->media_out), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->media_in, (PK_VOID*) chan), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_CALLBACK, &chan_data->media_out_queue), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_SetEventHandler(chan_data->media_out_queue, media_out_callback), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_out_queue, chan_data->media_out, (PK_VOID*) chan), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_PHONE_Start(chan_data->handle), PK_SUCCESS, error);
+ } else if (type == FTDM_CHAN_TYPE_B) {
+ TRY_OR_DIE(PKH_SPAN_SeizeChannel(span_data->handle, x), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_SPAN_GetMediaStreams(span_data->handle, x, &chan_data->media_in, &chan_data->media_out), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->media_in, (PK_VOID*) chan), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_CALLBACK, &chan_data->media_out_queue), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_SetEventHandler(chan_data->media_out_queue, media_out_callback), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_out_queue, chan_data->media_out, (PK_VOID*) chan), PK_SUCCESS, error);
+ } else if (type == FTDM_CHAN_TYPE_DQ921) {
+ TRY_OR_DIE(PKH_SPAN_HDLC_Open(span_data->handle, PKH_SPAN_HDLC_MODE_NORMAL, &chan_data->handle), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_SPAN_HDLC_GetConfig(chan_data->handle, &chan_data->hdlc_config), PK_SUCCESS, error);
+ chan_data->hdlc_config.channelId = x;
+ TRY_OR_DIE(PKH_SPAN_HDLC_SetConfig(chan_data->handle, &chan_data->hdlc_config), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
+
+ if (profile) {
+ if (profile->cust_span) {
+ span_data->span_config.framing = profile->span_config.framing;
+ span_data->span_config.encoding = profile->span_config.encoding;
+ span_data->span_config.loopLength = profile->span_config.loopLength;
+ span_data->span_config.buildOut = profile->span_config.buildOut;
+ span_data->span_config.compandMode = profile->span_config.compandMode;
+ } else {
+ if (profile->general_config.region == PKH_TRUNK_EU) {
+ span_data->span_config = globals.e1_span_config;
+ } else {
+ span_data->span_config = globals.t1_span_config;
+ }
+ }
+ } else {
+ if (span->trunk_type == FTDM_TRUNK_E1) {
+ span_data->span_config = globals.e1_span_config;
+ } else {
+ span_data->span_config = globals.t1_span_config;
+ }
+ }
+
+ PKH_SPAN_SetConfig(span_data->handle, &span_data->span_config);
+ TRY_OR_DIE(PKH_SPAN_Start(span_data->handle), PK_SUCCESS, error);
+ }
+
+ goto ok;
+
+ error:
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text));
+ ftdm_log(FTDM_LOG_ERROR, "failure configuring device b%ds%dc%d [%s]\n", boardno, spanno, x, error_text);
+ continue;
+ ok:
+ ftdm_set_flag(chan_data, PK_FLAG_READY);
+ status = PKH_RECORD_GetConfig(chan_data->media_in, &chan_data->record_config);
+ chan_data->record_config.encoding = PKH_RECORD_ENCODING_MU_LAW;
+ chan_data->record_config.samplingRate = PKH_RECORD_SAMPLING_RATE_8KHZ;
+ chan_data->record_config.bufferSize = PIKA_BLOCK_SIZE;
+ chan_data->record_config.numberOfBuffers = PIKA_NUM_BUFFERS;
+ chan_data->record_config.VAD.enabled = PK_FALSE;
+ //chan_data->record_config.speechSegmentEventsEnabled = PK_FALSE;
+ //chan_data->record_config.gain = rxgain;
+
+ status = PKH_PLAY_GetConfig(chan_data->media_out, &chan_data->play_config);
+ chan_data->play_config.encoding = PKH_RECORD_ENCODING_MU_LAW;
+ chan_data->play_config.samplingRate = PKH_RECORD_SAMPLING_RATE_8KHZ;
+ chan_data->play_config.AGC.enabled = PK_FALSE;
+ ftdm_log(FTDM_LOG_INFO, "configuring device b%ds%dc%d as FreeTDM device %d:%d\n", boardno, spanno, x, chan->span_id, chan->chan_id);
+
+ if (profile) {
+ ftdm_log(FTDM_LOG_INFO, "applying config profile %s to device %d:%d\n", profile->name, chan->span_id, chan->chan_id);
+ chan_data->record_config.gain = profile->record_config.gain;
+ chan_data->record_config.AGC = profile->record_config.AGC;
+ chan_data->record_config.VAD = profile->record_config.VAD;
+ chan_data->play_config.gain = profile->play_config.gain;
+ chan_data->play_config.AGC = profile->play_config.AGC;
+ chan_data->ec_enabled = profile->ec_enabled;
+ chan_data->ec_config = profile->ec_config;
+ }
+
+ if (type == FTDM_CHAN_TYPE_B) {
+ if (span_data->span_config.compandMode == PKH_SPAN_COMPAND_MODE_A_LAW) {
+ chan->native_codec = chan->effective_codec = FTDM_CODEC_ALAW;
+ } else {
+ chan->native_codec = chan->effective_codec = FTDM_CODEC_ULAW;
+ }
+ }
+
+ status = PKH_RECORD_SetConfig(chan_data->media_in, &chan_data->record_config);
+ status = PKH_PLAY_SetConfig(chan_data->media_out, &chan_data->play_config);
+
+ chan->physical_span_id = spanno;
+ chan->physical_chan_id = x;
+
+ chan->rate = 8000;
+ chan->packet_len = (uint32_t)chan_data->record_config.bufferSize;
+ chan->effective_interval = chan->native_interval = chan->packet_len / 8;
+
+ PKH_RECORD_Start(chan_data->media_in);
+ PKH_PLAY_Start(chan_data->media_out);
+ if (chan_data->ec_enabled) {
+ PKH_EC_SetConfig(chan_data->media_in, &chan_data->ec_config);
+ PKH_EC_Start(chan_data->media_in, chan_data->media_in, chan_data->media_out);
+ }
+
+ if (!ftdm_strlen_zero(name)) {
+ ftdm_copy_string(chan->chan_name, name, sizeof(chan->chan_name));
+ }
+
+ if (!ftdm_strlen_zero(number)) {
+ ftdm_copy_string(chan->chan_number, number, sizeof(chan->chan_number));
+ }
+
+ ftdm_channel_set_feature(chan, FTDM_CHANNEL_FEATURE_DTMF_GENERATE);
+ ftdm_buffer_create(&chan_data->digit_buffer, 128, 128, 0);
+ ftdm_mutex_create(&chan_data->digit_mutex);
+
+ configured++;
+ }
+
+
+ return configured;
+}
+
+/**
+ * \brief Initialises an freetdm pika span from a configuration string
+ * \param span FreeTDM span
+ * \param str Configuration string
+ * \param type FreeTDM span type
+ * \param name FreeTDM span name
+ * \param number FreeTDM span number
+ * \return Success or failure
+ */
+static FIO_CONFIGURE_SPAN_FUNCTION(pika_configure_span)
+{
+ int items, i;
+ char *mydata, *item_list[10];
+ char *bd, *sp, *ch = NULL, *mx;
+ int boardno;
+ int channo;
+ int spanno;
+ int top = 0;
+ unsigned configured = 0;
+ char *profile_name = NULL;
+ pika_channel_profile_t *profile = NULL;
+
+ assert(str != NULL);
+
+ mydata = ftdm_strdup(str);
+ assert(mydata != NULL);
+
+ if ((profile_name = strchr(mydata, '@'))) {
+ *profile_name++ = '\0';
+ if (!ftdm_strlen_zero(profile_name)) {
+ profile = (pika_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)profile_name);
+ }
+ }
+
+ items = ftdm_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
+
+ for(i = 0; i < items; i++) {
+ bd = item_list[i];
+ if ((sp = strchr(bd, ':'))) {
+ *sp++ = '\0';
+ if ((ch = strchr(sp, ':'))) {
+ *ch++ = '\0';
+ }
+ }
+
+ if (!(bd && sp && ch)) {
+ ftdm_log(FTDM_LOG_ERROR, "Invalid input\n");
+ continue;
+ }
+
+ boardno = atoi(bd);
+ channo = atoi(ch);
+ spanno = atoi(sp);
+
+
+ if (boardno < 0) {
+ ftdm_log(FTDM_LOG_ERROR, "Invalid board number %d\n", boardno);
+ continue;
+ }
+
+ if (channo < 0) {
+ ftdm_log(FTDM_LOG_ERROR, "Invalid channel number %d\n", channo);
+ continue;
+ }
+
+ if (spanno < 0) {
+ ftdm_log(FTDM_LOG_ERROR, "Invalid span number %d\n", channo);
+ continue;
+ }
+
+ if ((mx = strchr(ch, '-'))) {
+ mx++;
+ top = atoi(mx) + 1;
+ } else {
+ top = channo + 1;
+ }
+
+
+ if (top < 0) {
+ ftdm_log(FTDM_LOG_ERROR, "Invalid range number %d\n", top);
+ continue;
+ }
+
+ configured += pika_open_range(span, boardno, spanno, channo, top, type, name, number, profile);
+
+ }
+
+ ftdm_safe_free(mydata);
+
+ return configured;
+}
+
+/**
+ * \brief Opens Pika channel
+ * \param ftdmchan Channel to open
+ * \return Success or failure
+ */
+static FIO_OPEN_FUNCTION(pika_open)
+{
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->mod_data;
+
+ if (!chan_data && !ftdm_test_flag(chan_data, PK_FLAG_READY)) {
+ return FTDM_FAIL;
+ }
+
+ if (chan_data->media_in_queue) {
+ PKH_QUEUE_Flush(chan_data->media_in_queue);
+ }
+
+ if (ftdmchan->type == FTDM_CHAN_TYPE_FXS || ftdmchan->type == FTDM_CHAN_TYPE_FXO || ftdmchan->type == FTDM_CHAN_TYPE_B) {
+ PKH_PLAY_Start(chan_data->media_out);
+ }
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Closes Pika channel
+ * \param ftdmchan Channel to close
+ * \return Success
+ */
+static FIO_CLOSE_FUNCTION(pika_close)
+{
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Waits for an event on a Pika channel
+ * \param ftdmchan Channel to open
+ * \param flags Type of event to wait for
+ * \param to Time to wait (in ms)
+ * \return Success, failure or timeout
+ */
+static FIO_WAIT_FUNCTION(pika_wait)
+{
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->mod_data;
+ PK_STATUS status;
+ ftdm_wait_flag_t myflags = *flags;
+ PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+
+ *flags = FTDM_NO_FLAGS;
+
+ if (myflags & FTDM_READ) {
+ if (chan_data->hdlc_bytes) {
+ *flags |= FTDM_READ;
+ return FTDM_SUCCESS;
+ }
+ status = PKH_QUEUE_WaitOnEvent(chan_data->media_in_queue, to, &chan_data->last_media_event);
+
+ if (status == PK_SUCCESS) {
+ if (chan_data->last_media_event.id == PKH_EVENT_QUEUE_TIMEOUT || chan_data->last_media_event.id == PKH_EVENT_RECORD_BUFFER_OVERFLOW) {
+ return FTDM_TIMEOUT;
+ }
+
+ *flags |= FTDM_READ;
+ return FTDM_SUCCESS;
+ }
+
+ PKH_EVENT_GetText(chan_data->last_media_event.id, event_text, sizeof(event_text));
+ ftdm_log(FTDM_LOG_DEBUG, "Event: %s\n", event_text);
+ }
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Reads data from a Pika channel
+ * \param ftdmchan Channel to read from
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success or failure
+ */
+static FIO_READ_FUNCTION(pika_read)
+{
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->mod_data;
+ PK_STATUS status;
+ PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+ uint32_t len;
+
+ if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
+ if ((status = PKH_SPAN_HDLC_GetMessage(chan_data->handle, data, *datalen)) == PK_SUCCESS) {
+ *datalen = chan_data->hdlc_bytes;
+ chan_data->hdlc_bytes = 0;
+ return FTDM_SUCCESS;
+ }
+ return FTDM_FAIL;
+ }
+
+ if (!(len = chan_data->last_media_event.p0)) {
+ len = ftdmchan->packet_len;
+ }
+
+ if (len < *datalen) {
+ *datalen = len;
+ }
+
+ if ((status = PKH_RECORD_GetData(chan_data->media_in, data, *datalen)) == PK_SUCCESS) {
+ return FTDM_SUCCESS;
+ }
+
+
+ PKH_ERROR_GetText(status, event_text, sizeof(event_text));
+ ftdm_log(FTDM_LOG_DEBUG, "ERR: %s\n", event_text);
+ return FTDM_FAIL;
+}
+
+/**
+ * \brief Writes data to a Pika channel
+ * \param ftdmchan Channel to write to
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success or failure
+ */
+static FIO_WRITE_FUNCTION(pika_write)
+{
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->mod_data;
+ PK_STATUS status;
+
+ if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
+ if ((status = PKH_SPAN_HDLC_SendMessage(chan_data->handle, data, *datalen)) == PK_SUCCESS) {
+ return FTDM_SUCCESS;
+ }
+ return FTDM_FAIL;
+ }
+
+ if (PKH_PLAY_AddData(chan_data->media_out, 0, data, *datalen) == PK_SUCCESS) {
+ return FTDM_SUCCESS;
+ }
+
+ return FTDM_FAIL;
+}
+
+/**
+ * \brief Executes an FreeTDM command on a Pika channel
+ * \param ftdmchan Channel to execute command on
+ * \param command FreeTDM command to execute
+ * \param obj Object (unused)
+ * \return Success or failure
+ */
+static FIO_COMMAND_FUNCTION(pika_command)
+{
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->mod_data;
+ //pika_span_data_t *span_data = (pika_span_data_t *) ftdmchan->span->mod_data;
+ PK_STATUS pk_status;
+ ftdm_status_t status = FTDM_SUCCESS;
+
+ switch(command) {
+ case FTDM_COMMAND_OFFHOOK:
+ {
+ if ((pk_status = PKH_TRUNK_SetHookSwitch(chan_data->handle, PKH_TRUNK_OFFHOOK)) != PK_SUCCESS) {
+ PKH_ERROR_GetText(pk_status, ftdmchan->last_error, sizeof(ftdmchan->last_error));
+ GOTO_STATUS(done, FTDM_FAIL);
+ } else {
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
+ }
+ }
+ break;
+ case FTDM_COMMAND_ONHOOK:
+ {
+ if ((pk_status = PKH_TRUNK_SetHookSwitch(chan_data->handle, PKH_TRUNK_ONHOOK)) != PK_SUCCESS) {
+ PKH_ERROR_GetText(pk_status, ftdmchan->last_error, sizeof(ftdmchan->last_error));
+ GOTO_STATUS(done, FTDM_FAIL);
+ } else {
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
+ }
+ }
+ break;
+ case FTDM_COMMAND_GENERATE_RING_ON:
+ {
+ if ((pk_status = PKH_PHONE_RingStart(chan_data->handle, 0, 0)) != PK_SUCCESS) {
+ PKH_ERROR_GetText(pk_status, ftdmchan->last_error, sizeof(ftdmchan->last_error));
+ GOTO_STATUS(done, FTDM_FAIL);
+ } else {
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
+ }
+ }
+ break;
+ case FTDM_COMMAND_GENERATE_RING_OFF:
+ {
+ if ((pk_status = PKH_PHONE_RingStop(chan_data->handle)) != PK_SUCCESS) {
+ PKH_ERROR_GetText(pk_status, ftdmchan->last_error, sizeof(ftdmchan->last_error));
+ GOTO_STATUS(done, FTDM_FAIL);
+ } else {
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
+ }
+ }
+ break;
+ case FTDM_COMMAND_GET_INTERVAL:
+ {
+
+ FTDM_COMMAND_OBJ_INT = ftdmchan->native_interval;
+
+ }
+ break;
+ case FTDM_COMMAND_SET_INTERVAL:
+ {
+ int interval = FTDM_COMMAND_OBJ_INT;
+ int len = interval * 8;
+ chan_data->record_config.bufferSize = len;
+ chan_data->record_config.numberOfBuffers = (PK_UINT)chan_data->record_config.bufferSize;
+ ftdmchan->packet_len = (uint32_t)chan_data->record_config.bufferSize;
+ ftdmchan->effective_interval = ftdmchan->native_interval = ftdmchan->packet_len / 8;
+ PKH_RECORD_SetConfig(chan_data->media_in, &chan_data->record_config);
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ break;
+ case FTDM_COMMAND_GET_DTMF_ON_PERIOD:
+ {
+
+ FTDM_COMMAND_OBJ_INT = ftdmchan->dtmf_on;
+ GOTO_STATUS(done, FTDM_SUCCESS);
+
+ }
+ break;
+ case FTDM_COMMAND_GET_DTMF_OFF_PERIOD:
+ {
+ FTDM_COMMAND_OBJ_INT = ftdmchan->dtmf_on;
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ break;
+ case FTDM_COMMAND_SET_DTMF_ON_PERIOD:
+ {
+ int val = FTDM_COMMAND_OBJ_INT;
+ if (val > 10 && val < 1000) {
+ ftdmchan->dtmf_on = val;
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ } else {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid value %d range 10-1000", val);
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ }
+ break;
+ case FTDM_COMMAND_SET_DTMF_OFF_PERIOD:
+ {
+ int val = FTDM_COMMAND_OBJ_INT;
+ if (val > 10 && val < 1000) {
+ ftdmchan->dtmf_off = val;
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ } else {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid value %d range 10-1000", val);
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ }
+ break;
+ case FTDM_COMMAND_SEND_DTMF:
+ {
+ char *digits = FTDM_COMMAND_OBJ_CHAR_P;
+ ftdm_log(FTDM_LOG_DEBUG, "Adding DTMF SEQ [%s]\n", digits);
+ ftdm_mutex_lock(chan_data->digit_mutex);
+ ftdm_buffer_write(chan_data->digit_buffer, digits, strlen(digits));
+ ftdm_mutex_unlock(chan_data->digit_mutex);
+ pk_status = PKH_PLAY_Stop(chan_data->media_out);
+
+ if (pk_status != PK_SUCCESS) {
+ PKH_ERROR_GetText(pk_status, ftdmchan->last_error, sizeof(ftdmchan->last_error));
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ break;
+ default:
+ break;
+ };
+
+ done:
+ return status;
+}
+
+/**
+ * \brief Checks for events on a Pika span
+ * \param span Span to check for events
+ * \param ms Time to wait for event
+ * \return Success if event is waiting or failure if not
+ */
+static FIO_SPAN_POLL_EVENT_FUNCTION(pika_poll_event)
+{
+ pika_span_data_t *span_data = (pika_span_data_t *) span->mod_data;
+ PK_STATUS status;
+ PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+
+ status = PKH_QUEUE_WaitOnEvent(span_data->event_queue, ms, &span_data->last_oob_event);
+
+ if (status == PK_SUCCESS) {
+ ftdm_channel_t *ftdmchan = NULL;
+ uint32_t *data = (uint32_t *) span_data->last_oob_event.userData;
+ ftdm_data_type_t data_type = FTDM_TYPE_NONE;
+
+ if (span_data->last_oob_event.id == PKH_EVENT_QUEUE_TIMEOUT) {
+ return FTDM_TIMEOUT;
+ }
+
+ if (data) {
+ data_type = *data;
+ }
+
+ if (data_type == FTDM_TYPE_CHANNEL) {
+ ftdmchan = span_data->last_oob_event.userData;
+ } else if (data_type == FTDM_TYPE_SPAN) {
+ ftdm_time_t last_event_time = ftdm_current_time_in_ms();
+ uint32_t event_id = 0;
+
+ switch (span_data->last_oob_event.id) {
+ case PKH_EVENT_SPAN_ALARM_T1_RED:
+ case PKH_EVENT_SPAN_ALARM_T1_YELLOW:
+ case PKH_EVENT_SPAN_ALARM_T1_AIS:
+ case PKH_EVENT_SPAN_ALARM_E1_RED:
+ case PKH_EVENT_SPAN_ALARM_E1_RAI:
+ case PKH_EVENT_SPAN_ALARM_E1_AIS:
+ case PKH_EVENT_SPAN_ALARM_E1_RMAI:
+ case PKH_EVENT_SPAN_ALARM_E1_TS16AIS:
+ case PKH_EVENT_SPAN_ALARM_E1_TS16LOS:
+ case PKH_EVENT_SPAN_OUT_OF_SYNC:
+ case PKH_EVENT_SPAN_FRAMING_ERROR:
+ case PKH_EVENT_SPAN_LOSS_OF_SIGNAL:
+ case PKH_EVENT_SPAN_OUT_OF_CRC_MF_SYNC:
+ case PKH_EVENT_SPAN_OUT_OF_CAS_MF_SYNC:
+ event_id = FTDM_OOB_ALARM_TRAP;
+ break;
+ case PKH_EVENT_SPAN_ALARM_T1_RED_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_T1_YELLOW_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_T1_AIS_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_E1_RED_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_E1_RAI_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_E1_AIS_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_E1_RMAI_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_E1_TS16AIS_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_E1_TS16LOS_CLEAR:
+ case PKH_EVENT_SPAN_IN_SYNC:
+ case PKH_EVENT_SPAN_LOSS_OF_SIGNAL_CLEAR:
+ case PKH_EVENT_SPAN_IN_CRC_MF_SYNC:
+ case PKH_EVENT_SPAN_IN_CAS_MF_SYNC:
+ event_id = FTDM_OOB_ALARM_CLEAR;
+ break;
+ case PKH_EVENT_SPAN_MESSAGE:
+ case PKH_EVENT_SPAN_ABCD_SIGNAL_CHANGE:
+ break;
+ }
+
+ if (event_id) {
+ uint32_t x = 0;
+ ftdm_channel_t *ftdmchan;
+ pika_chan_data_t *chan_data;
+ for(x = 1; x <= span->chan_count; x++) {
+ ftdmchan = span->channels[x];
+ assert(ftdmchan != NULL);
+ chan_data = (pika_chan_data_t *) ftdmchan->mod_data;
+ assert(chan_data != NULL);
+
+
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_EVENT);
+ ftdmchan->last_event_time = last_event_time;
+ chan_data->last_oob_event = span_data->last_oob_event;
+ }
+
+ }
+
+ }
+
+ PKH_EVENT_GetText(span_data->last_oob_event.id, event_text, sizeof(event_text));
+ //ftdm_log(FTDM_LOG_DEBUG, "Event: %s\n", event_text);
+
+ if (ftdmchan) {
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->mod_data;
+
+ assert(chan_data != NULL);
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_EVENT);
+ ftdmchan->last_event_time = ftdm_current_time_in_ms();
+ chan_data->last_oob_event = span_data->last_oob_event;
+ }
+
+ return FTDM_SUCCESS;
+ }
+
+ return FTDM_FAIL;
+}
+
+/**
+ * \brief Retrieves an event from a Pika span
+ * \param span Span to retrieve event from
+ * \param event FreeTDM event to return
+ * \return Success or failure
+ */
+static FIO_SPAN_NEXT_EVENT_FUNCTION(pika_next_event)
+{
+ uint32_t i, event_id = 0;
+
+ for(i = 1; i <= span->chan_count; i++) {
+ if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) span->channels[i]->mod_data;
+ PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+
+ ftdm_clear_flag(span->channels[i], FTDM_CHANNEL_EVENT);
+
+ PKH_EVENT_GetText(chan_data->last_oob_event.id, event_text, sizeof(event_text));
+
+ switch(chan_data->last_oob_event.id) {
+ case PKH_EVENT_HDLC_MESSAGE:
+ chan_data->hdlc_bytes = chan_data->last_oob_event.p2;
+ continue;
+ case PKH_EVENT_TRUNK_HOOKFLASH:
+ event_id = FTDM_OOB_FLASH;
+ break;
+ case PKH_EVENT_TRUNK_RING_OFF:
+ event_id = FTDM_OOB_RING_STOP;
+ break;
+ case PKH_EVENT_TRUNK_RING_ON:
+ event_id = FTDM_OOB_RING_START;
+ break;
+
+ case PKH_EVENT_PHONE_OFFHOOK:
+ ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
+ event_id = FTDM_OOB_OFFHOOK;
+ break;
+
+ case PKH_EVENT_TRUNK_BELOW_THRESHOLD:
+ case PKH_EVENT_TRUNK_ABOVE_THRESHOLD:
+ case PKH_EVENT_PHONE_ONHOOK:
+ ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
+ event_id = FTDM_OOB_ONHOOK;
+ break;
+
+
+
+ case PKH_EVENT_SPAN_ALARM_T1_RED:
+ ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_RED);
+ snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "RED ALARM");
+ event_id = FTDM_OOB_ALARM_TRAP;
+ break;
+ case PKH_EVENT_SPAN_ALARM_T1_YELLOW:
+ ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_YELLOW);
+ snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "YELLOW ALARM");
+ event_id = FTDM_OOB_ALARM_TRAP;
+ break;
+ case PKH_EVENT_SPAN_ALARM_T1_AIS:
+ ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_AIS);
+ snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "AIS ALARM");
+ event_id = FTDM_OOB_ALARM_TRAP;
+ break;
+ case PKH_EVENT_SPAN_ALARM_E1_RED:
+ ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_RED);
+ snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "RED ALARM");
+ event_id = FTDM_OOB_ALARM_TRAP;
+ break;
+ case PKH_EVENT_SPAN_ALARM_E1_RAI:
+ ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_RAI);
+ snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "RAI ALARM");
+ event_id = FTDM_OOB_ALARM_TRAP;
+ break;
+ case PKH_EVENT_SPAN_ALARM_E1_AIS:
+ ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_AIS);
+ snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "AIS ALARM");
+ event_id = FTDM_OOB_ALARM_TRAP;
+ break;
+ case PKH_EVENT_SPAN_ALARM_E1_RMAI:
+ case PKH_EVENT_SPAN_ALARM_E1_TS16AIS:
+ case PKH_EVENT_SPAN_ALARM_E1_TS16LOS:
+ case PKH_EVENT_SPAN_OUT_OF_SYNC:
+ case PKH_EVENT_SPAN_FRAMING_ERROR:
+ case PKH_EVENT_SPAN_LOSS_OF_SIGNAL:
+ case PKH_EVENT_SPAN_OUT_OF_CRC_MF_SYNC:
+ case PKH_EVENT_SPAN_OUT_OF_CAS_MF_SYNC:
+ ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_GENERAL);
+ snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "GENERAL ALARM");
+ event_id = FTDM_OOB_ALARM_TRAP;
+ break;
+ case PKH_EVENT_SPAN_ALARM_T1_RED_CLEAR:
+ ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_RED);
+ case PKH_EVENT_SPAN_ALARM_T1_YELLOW_CLEAR:
+ ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_YELLOW);
+ case PKH_EVENT_SPAN_ALARM_T1_AIS_CLEAR:
+ ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_AIS);
+ case PKH_EVENT_SPAN_ALARM_E1_RED_CLEAR:
+ ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_RED);
+ case PKH_EVENT_SPAN_ALARM_E1_RAI_CLEAR:
+ ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_RAI);
+ case PKH_EVENT_SPAN_ALARM_E1_AIS_CLEAR:
+ ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_AIS);
+ case PKH_EVENT_SPAN_ALARM_E1_RMAI_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_E1_TS16AIS_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_E1_TS16LOS_CLEAR:
+ case PKH_EVENT_SPAN_IN_SYNC:
+ case PKH_EVENT_SPAN_LOSS_OF_SIGNAL_CLEAR:
+ case PKH_EVENT_SPAN_IN_CRC_MF_SYNC:
+ case PKH_EVENT_SPAN_IN_CAS_MF_SYNC:
+ ftdm_clear_alarm_flag(span->channels[i], FTDM_ALARM_GENERAL);
+ event_id = FTDM_OOB_ALARM_CLEAR;
+ break;
+ case PKH_EVENT_SPAN_MESSAGE:
+ case PKH_EVENT_SPAN_ABCD_SIGNAL_CHANGE:
+ break;
+
+
+
+
+ case PKH_EVENT_TRUNK_ONHOOK:
+ case PKH_EVENT_TRUNK_OFFHOOK:
+ case PKH_EVENT_TRUNK_DIALED :
+ case PKH_EVENT_TRUNK_REVERSAL:
+ case PKH_EVENT_TRUNK_LCSO:
+ case PKH_EVENT_TRUNK_DROPOUT:
+ case PKH_EVENT_TRUNK_LOF:
+ case PKH_EVENT_TRUNK_RX_OVERLOAD:
+ default:
+ ftdm_log(FTDM_LOG_DEBUG, "Unhandled event %d on channel %d [%s]\n", chan_data->last_oob_event.id, i, event_text);
+ event_id = FTDM_OOB_INVALID;
+ break;
+ }
+
+ span->channels[i]->last_event_time = 0;
+ span->event_header.e_type = FTDM_EVENT_OOB;
+ span->event_header.enum_id = event_id;
+ span->event_header.channel = span->channels[i];
+ *event = &span->event_header;
+ return FTDM_SUCCESS;
+ }
+ }
+
+ return FTDM_FAIL;
+}
+
+/**
+ * \brief Destroys a Pika Span
+ * \param span Span to destroy
+ * \return Success
+ */
+static FIO_SPAN_DESTROY_FUNCTION(pika_span_destroy)
+{
+ pika_span_data_t *span_data = (pika_span_data_t *) span->mod_data;
+
+ if (span_data) {
+ PKH_QUEUE_Destroy(span_data->event_queue);
+ ftdm_safe_free(span_data);
+ }
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Destroys a Pika Channel
+ * \param ftdmchan Channel to destroy
+ * \return Success or failure
+ */
+static FIO_CHANNEL_DESTROY_FUNCTION(pika_channel_destroy)
+{
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->mod_data;
+ pika_span_data_t *span_data = (pika_span_data_t *) ftdmchan->span->mod_data;
+
+ if (!chan_data) {
+ return FTDM_FAIL;
+ }
+
+ if (!ftdm_test_flag(chan_data, PK_FLAG_READY)) {
+ goto end;
+ }
+
+ PKH_RECORD_Stop(chan_data->media_in);
+ PKH_PLAY_Stop(chan_data->media_out);
+ PKH_QUEUE_Destroy(chan_data->media_in_queue);
+ PKH_QUEUE_Destroy(chan_data->media_out_queue);
+
+ switch(ftdmchan->type) {
+ case FTDM_CHAN_TYPE_FXS:
+ PKH_QUEUE_Detach(span_data->event_queue, chan_data->handle);
+ PKH_PHONE_Close(chan_data->handle);
+ break;
+ case FTDM_CHAN_TYPE_FXO:
+ PKH_QUEUE_Detach(span_data->event_queue, chan_data->handle);
+ PKH_TRUNK_Close(chan_data->handle);
+ break;
+ case FTDM_CHAN_TYPE_DQ921:
+ PKH_SPAN_Stop(span_data->handle);
+ break;
+ default:
+ break;
+ }
+
+
+ ftdm_mutex_destroy(&chan_data->digit_mutex);
+ ftdm_buffer_destroy(&chan_data->digit_buffer);
+
+ end:
+ ftdm_safe_free(chan_data);
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Gets alarms from a Pika Channel (does nothing)
+ * \param ftdmchan Channel to get alarms from
+ * \return Failure
+ */
+static FIO_GET_ALARMS_FUNCTION(pika_get_alarms)
+{
+ return FTDM_FAIL;
+}
+
+static ftdm_io_interface_t pika_interface;
+
+/**
+ * \brief Loads Pika IO module
+ * \param fio FreeTDM IO interface
+ * \return Success or failure
+ */
+static FIO_IO_LOAD_FUNCTION(pika_init)
+{
+
+ PK_STATUS status;
+ PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
+ uint32_t i;
+ int ok = 0;
+ PKH_TLogMasks m;
+ TPikaHandle tmpHandle;
+
+ assert(fio != NULL);
+ memset(&pika_interface, 0, sizeof(pika_interface));
+ memset(&globals, 0, sizeof(globals));
+ globals.general_config.region = PKH_TRUNK_NA;
+
+ globals.profile_hash = create_hashtable(16, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+
+ // Open the system object, to enumerate boards configured for this system
+ if ((status = PKH_SYSTEM_Open(&globals.system_handle)) != PK_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error: PKH_SYSTEM_Open failed(%s)!\n",
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+ return FTDM_FAIL;
+ }
+
+ // Retrieves a list of all boards in this system, existing,
+ // or listed in pika.cfg
+ if ((status = PKH_SYSTEM_Detect(globals.system_handle, &globals.board_list)) != PK_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error: PKH_SYSTEM_Detect failed(%s)!\n",
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+ return FTDM_FAIL;
+ }
+
+ PKH_SYSTEM_GetConfig(globals.system_handle, &globals.system_config);
+ globals.system_config.maxAudioProcessBlockSize = PIKA_BLOCK_LEN;
+ globals.system_config.playBufferSize = PIKA_BLOCK_SIZE;
+ globals.system_config.recordBufferSize = PIKA_BLOCK_SIZE;
+ globals.system_config.recordNumberOfBuffers = PIKA_NUM_BUFFERS;
+ PKH_SYSTEM_SetConfig(globals.system_handle, &globals.system_config);
+
+ status = PKH_MEDIA_STREAM_Create(&tmpHandle);
+ status = PKH_RECORD_GetConfig(tmpHandle, &globals.record_config);
+ status = PKH_PLAY_GetConfig(tmpHandle, &globals.play_config);
+ status = PKH_EC_GetConfig(tmpHandle, &globals.ec_config);
+ status = PKH_MEDIA_STREAM_Destroy(tmpHandle);
+
+
+
+ ftdm_log(FTDM_LOG_DEBUG, "Found %u board%s\n", globals.board_list.numberOfBoards, globals.board_list.numberOfBoards == 1 ? "" : "s");
+ for(i = 0; i < globals.board_list.numberOfBoards; ++i) {
+ ftdm_log(FTDM_LOG_INFO, "Found PIKA board type:[%s] id:[%u] serno:[%u]\n",
+ pika_board_type_string(globals.board_list.board[i].type), globals.board_list.board[i].id, (uint32_t)
+ globals.board_list.board[i].serialNumber);
+
+ if (globals.board_list.board[i].type == PKH_BOARD_TYPE_DIGITAL_GATEWAY) {
+ TPikaHandle board_handle, span_handle;
+ PKH_TBoardConfig boardConfig;
+ PKH_BOARD_GetConfig(board_handle, &boardConfig);
+ PKH_BOARD_Open(globals.board_list.board[i].id, NULL, &board_handle);
+ PKH_SPAN_Open(board_handle, 0, NULL, &span_handle);
+ PKH_SPAN_GetConfig(span_handle, &globals.t1_span_config);
+ PKH_SPAN_Close(span_handle);
+ boardConfig.specific.DigitalGateway.interfaceType = PKH_BOARD_INTERFACE_TYPE_E1;
+ PKH_BOARD_SetConfig(board_handle, &boardConfig);
+ PKH_SPAN_Open(board_handle, 0, NULL, &span_handle);
+ PKH_SPAN_GetConfig(span_handle, &globals.e1_span_config);
+ PKH_SPAN_Close(span_handle);
+ boardConfig.specific.DigitalGateway.interfaceType = PKH_BOARD_INTERFACE_TYPE_T1;
+ PKH_BOARD_SetConfig(board_handle, &boardConfig);
+ PKH_BOARD_Close(board_handle);
+ }
+ ok++;
+
+ }
+
+ if (!ok) {
+ return FTDM_FAIL;
+ }
+
+ pika_interface.name = "pika";
+ pika_interface.configure = pika_configure;
+ pika_interface.configure_span = pika_configure_span;
+ pika_interface.open = pika_open;
+ pika_interface.close = pika_close;
+ pika_interface.wait = pika_wait;
+ pika_interface.read = pika_read;
+ pika_interface.write = pika_write;
+ pika_interface.command = pika_command;
+ pika_interface.poll_event = pika_poll_event;
+ pika_interface.next_event = pika_next_event;
+ pika_interface.channel_destroy = pika_channel_destroy;
+ pika_interface.span_destroy = pika_span_destroy;
+ pika_interface.get_alarms = pika_get_alarms;
+ *fio = &pika_interface;
+
+
+ ftdm_log(FTDM_LOG_INFO, "Dumping Default configs:\n");
+ ftdm_log(FTDM_LOG_INFO, "rx-gain => %0.2f\n", (float)globals.record_config.gain);
+ ftdm_log(FTDM_LOG_INFO, "rx-agc-enabled => %s\n", globals.record_config.AGC.enabled ? "true" : "false");
+ ftdm_log(FTDM_LOG_INFO, "rx-agc-targetPower => %0.2f\n", (float)globals.record_config.AGC.targetPower);
+ ftdm_log(FTDM_LOG_INFO, "rx-agc-minGain => %0.2f\n", (float)globals.record_config.AGC.minGain);
+ ftdm_log(FTDM_LOG_INFO, "rx-agc-maxGain => %0.2f\n", (float)globals.record_config.AGC.maxGain);
+ ftdm_log(FTDM_LOG_INFO, "rx-agc-attackRate => %d\n", (int)globals.record_config.AGC.attackRate);
+ ftdm_log(FTDM_LOG_INFO, "rx-agc-decayRate => %d\n", (int)globals.record_config.AGC.decayRate);
+ ftdm_log(FTDM_LOG_INFO, "rx-agc-speechThreshold => %0.2f\n", (float)globals.record_config.AGC.speechThreshold);
+ ftdm_log(FTDM_LOG_INFO, "rx-vad-enabled => %s\n", globals.record_config.VAD.enabled ? "true" : "false");
+ ftdm_log(FTDM_LOG_INFO, "rx-vad-activationThreshold => %0.2f\n", (float)globals.record_config.VAD.activationThreshold);
+ ftdm_log(FTDM_LOG_INFO, "rx-vad-activationDebounceTime => %d\n", (int)globals.record_config.VAD.activationDebounceTime);
+ ftdm_log(FTDM_LOG_INFO, "rx-vad-deactivationThreshold => %0.2f\n", (float)globals.record_config.VAD.deactivationThreshold);
+ ftdm_log(FTDM_LOG_INFO, "rx-vad-deactivationDebounceTime => %d\n", (int)globals.record_config.VAD.deactivationDebounceTime);
+ ftdm_log(FTDM_LOG_INFO, "rx-vad-preSpeechBufferSize => %d\n", (int)globals.record_config.VAD.preSpeechBufferSize);
+ ftdm_log(FTDM_LOG_INFO, "tx-gain => %0.2f\n", (float)globals.play_config.gain);
+ ftdm_log(FTDM_LOG_INFO, "tx-agc-enabled => %s\n", globals.play_config.AGC.enabled ? "true" : "false");
+ ftdm_log(FTDM_LOG_INFO, "tx-agc-targetPower => %0.2f\n", (float)globals.play_config.AGC.targetPower);
+ ftdm_log(FTDM_LOG_INFO, "tx-agc-minGain => %0.2f\n", (float)globals.play_config.AGC.minGain);
+ ftdm_log(FTDM_LOG_INFO, "tx-agc-maxGain => %0.2f\n", (float)globals.play_config.AGC.maxGain);
+ ftdm_log(FTDM_LOG_INFO, "tx-agc-attackRate => %d\n", (int)globals.play_config.AGC.attackRate);
+ ftdm_log(FTDM_LOG_INFO, "tx-agc-decayRate => %d\n", (int)globals.play_config.AGC.decayRate);
+ ftdm_log(FTDM_LOG_INFO, "tx-agc-speechThreshold => %0.2f\n", (float)globals.play_config.AGC.speechThreshold);
+ ftdm_log(FTDM_LOG_INFO, "ec-doubleTalkerThreshold => %0.2f\n", (float)globals.ec_config.doubleTalkerThreshold);
+ ftdm_log(FTDM_LOG_INFO, "ec-speechPresentThreshold => %0.2f\n", (float)globals.ec_config.speechPresentThreshold);
+ ftdm_log(FTDM_LOG_INFO, "ec-echoSuppressionThreshold => %0.2f\n", (float)globals.ec_config.echoSuppressionThreshold);
+ ftdm_log(FTDM_LOG_INFO, "ec-echoSuppressionEnabled => %s\n", globals.ec_config.echoSuppressionEnabled ? "true" : "false");
+ ftdm_log(FTDM_LOG_INFO, "ec-comfortNoiseEnabled => %s\n", globals.ec_config.comfortNoiseEnabled ? "true" : "false");
+ ftdm_log(FTDM_LOG_INFO, "ec-adaptationModeEnabled => %s\n", globals.ec_config.adaptationModeEnabled ? "true" : "false");
+
+
+
+ memset(&m, 0, sizeof(m));
+ //m.apiMask = 0xffffffff;
+ //PKH_LOG_SetMasks(&m);
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Unloads Pika IO module
+ * \return Success
+ */
+static FIO_IO_UNLOAD_FUNCTION(pika_destroy)
+{
+ uint32_t x;
+ PK_STATUS status;
+ PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
+
+ for (x = 0; x < MAX_NUMBER_OF_TRUNKS; x++) {
+ if (globals.open_boards[x]) {
+ ftdm_log(FTDM_LOG_INFO, "Closing board %u\n", x);
+ PKH_BOARD_Close(globals.open_boards[x]);
+ }
+ }
+
+ // The system can now be closed.
+ if ((status = PKH_SYSTEM_Close(globals.system_handle)) != PK_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error: PKH_SYSTEM_Close failed(%s)!\n",
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+ } else {
+ ftdm_log(FTDM_LOG_INFO, "Closing system handle\n");
+ }
+
+ hashtable_destroy(globals.profile_hash);
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Pika IO module definition
+ */
+EX_DECLARE_DATA ftdm_module_t ftdm_module = {
+ "pika",
+ pika_init,
+ pika_destroy,
+};
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ozmod_pika.2005.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ozmod_pika.2005.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ozmod_pika.2005.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ftmod_pika"
+ ProjectGUID="{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}"
+ RootNamespace="ftmod_pika"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_PIKA_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="pikahmpapi.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="..\..\..\pika\aoh\lib"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_PIKA_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="pikahmpapi.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="..\..\..\pika\aoh\lib"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\ftmod_pika.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\ftdm_pika.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1363 @@
+/*
+ * Copyright (c) 2009, Moises Silva <moy@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.
+ */
+
+#include <stdio.h>
+#include <openr2.h>
+#include "freetdm.h"
+
+/* debug thread count for r2 legs */
+static ftdm_mutex_t* g_thread_count_mutex;
+static int32_t g_thread_count = 0;
+
+/* when the users kills a span we clear this flag to kill the signaling thread */
+/* FIXME: what about the calls that are already up-and-running? */
+typedef enum {
+ FTDM_R2_RUNNING = (1 << 0),
+} ftdm_r2_flag_t;
+
+/* private call information stored in ftdmchan->call_data void* ptr */
+#define R2CALL(ftdmchan) ((ftdm_r2_call_t*)((ftdmchan)->call_data))
+typedef struct ftdm_r2_call_t {
+ openr2_chan_t *r2chan;
+ int accepted:1;
+ int answer_pending:1;
+ int state_ack_pending:1;
+ int disconnect_rcvd:1;
+ int ftdm_started:1;
+ ftdm_channel_state_t chanstate;
+ ftdm_size_t dnis_index;
+ ftdm_size_t ani_index;
+ char name[10];
+} ftdm_r2_call_t;
+
+/* this is just used as place holder in the stack when configuring the span to avoid using bunch of locals */
+typedef struct ft_r2_conf_s {
+ /* openr2 types */
+ openr2_variant_t variant;
+ openr2_calling_party_category_t category;
+ openr2_log_level_t loglevel;
+
+ /* strings */
+ char *logdir;
+ char *advanced_protocol_file;
+
+ /* ints */
+ int32_t max_ani;
+ int32_t max_dnis;
+ int32_t mfback_timeout;
+ int32_t metering_pulse_timeout;
+
+ /* booleans */
+ int immediate_accept;
+ int skip_category;
+ int get_ani_first;
+ int call_files;
+ int double_answer;
+ int charge_calls;
+ int forced_release;
+ int allow_collect_calls;
+} ft_r2_conf_t;
+
+/* r2 configuration stored in span->signal_data */
+typedef struct ftdm_r2_data_s {
+ /* span flags */
+ ftdm_r2_flag_t flags;
+ /* openr2 handle for the R2 variant context */
+ openr2_context_t *r2context;
+ /* category to use when making calls */
+ openr2_calling_party_category_t category;
+ /* whether to use OR2_CALL_WITH_CHARGE or OR2_CALL_NO_CHARGE when accepting a call */
+ int charge_calls:1;
+ /* allow or reject collect calls */
+ int allow_collect_calls:1;
+ /* whether to use forced release when hanging up */
+ int forced_release:1;
+ /* whether accept the call when offered, or wait until the user decides to accept */
+ int accept_on_offer:1;
+} ftdm_r2_data_t;
+
+/* one element per span will be stored in g_mod_data_hash global var to keep track of them
+ and destroy them on module unload */
+typedef struct ftdm_r2_span_pvt_s {
+ openr2_context_t *r2context; /* r2 context allocated for this span */
+ ftdm_hash_t *r2calls; /* hash table of allocated call data per channel for this span */
+} ftdm_r2_span_pvt_t;
+
+/* span monitor thread */
+static void *ftdm_r2_run(ftdm_thread_t *me, void *obj);
+
+/* channel monitor thread */
+static void *ftdm_r2_channel_run(ftdm_thread_t *me, void *obj);
+
+/* hash of all the private span allocations
+ we need to keep track of them to destroy them when unloading the module
+ since freetdm does not notify signaling modules when destroying a span
+ span -> ftdm_r2_mod_allocs_t */
+static ftdm_hash_t *g_mod_data_hash;
+
+/* IO interface for the command API */
+static ftdm_io_interface_t g_ftdm_r2_interface;
+
+static void ft_r2_clean_call(ftdm_r2_call_t *call)
+{
+ openr2_chan_t *r2chan = call->r2chan;
+ memset(call, 0, sizeof(*call));
+ call->r2chan = r2chan;
+}
+
+static void ft_r2_accept_call(ftdm_channel_t *ftdmchan)
+{
+ openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan;
+ // FIXME: not always accept as no charge, let the user decide that
+ // also we should check the return code from openr2_chan_accept_call and handle error condition
+ // hanging up the call with protocol error as the reason, this openr2 API will fail only when there something
+ // wrong at the I/O layer or the library itself
+ openr2_chan_accept_call(r2chan, OR2_CALL_NO_CHARGE);
+ R2CALL(ftdmchan)->accepted = 1;
+}
+
+static void ft_r2_answer_call(ftdm_channel_t *ftdmchan)
+{
+ openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan;
+ // FIXME
+ // 1. check openr2_chan_answer_call return code
+ // 2. The openr2_chan_answer_call_with_mode should be used depending on user settings
+ // openr2_chan_answer_call_with_mode(r2chan, OR2_ANSWER_SIMPLE);
+ openr2_chan_answer_call(r2chan);
+ R2CALL(ftdmchan)->answer_pending = 0;
+}
+
+static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
+{
+ ftdm_status_t status;
+ ftdm_mutex_lock(ftdmchan->mutex);
+
+ /* the channel may be down but the thread not quite done */
+ ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_INTHREAD, 200);
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
+ ftdm_log(FTDM_LOG_ERROR, "%d:%d Yay! R2 outgoing call in channel that is already in thread.\n",
+ ftdmchan->span_id, ftdmchan->chan_id);
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ return FTDM_FAIL;
+ }
+
+ ft_r2_clean_call(ftdmchan->call_data);
+ R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
+ ftdm_channel_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING, 0);
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
+ R2CALL(ftdmchan)->ftdm_started = 1;
+ ftdm_mutex_unlock(ftdmchan->mutex);
+
+ status = ftdm_thread_create_detached(ftdm_r2_channel_run, ftdmchan);
+ if (status == FTDM_FAIL) {
+ ftdm_log(FTDM_LOG_ERROR, "%d:%d Cannot handle request to start call in channel, failed to create thread!\n",
+ ftdmchan->span_id, ftdmchan->chan_id);
+ ftdm_channel_done(ftdmchan);
+ return FTDM_FAIL;
+ }
+
+ return FTDM_SUCCESS;
+}
+
+static ftdm_status_t ftdm_r2_start(ftdm_span_t *span)
+{
+ ftdm_r2_data_t *r2_data = span->signal_data;
+ ftdm_set_flag(r2_data, FTDM_R2_RUNNING);
+ return ftdm_thread_create_detached(ftdm_r2_run, span);
+}
+
+/* always called from the monitor thread */
+static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
+{
+ ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+ ftdm_status_t status;
+ ftdm_log(FTDM_LOG_NOTICE, "Received request to start call on chan %d\n", openr2_chan_get_number(r2chan));
+
+ ftdm_mutex_lock(ftdmchan->mutex);
+
+ if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) {
+ ftdm_log(FTDM_LOG_ERROR, "Cannot handle request to start call in channel %d, invalid state (%d)\n",
+ openr2_chan_get_number(r2chan), ftdmchan->state);
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ return;
+ }
+
+ /* the channel may be down but the thread not quite done */
+ ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_INTHREAD, 200);
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
+ ftdm_log(FTDM_LOG_ERROR, "Cannot handle request to start call in channel %d, already in thread!\n",
+ openr2_chan_get_number(r2chan));
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ return;
+ }
+ ft_r2_clean_call(ftdmchan->call_data);
+ R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
+ ftdm_channel_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT, 0);
+ ftdm_mutex_unlock(ftdmchan->mutex);
+
+ status = ftdm_thread_create_detached(ftdm_r2_channel_run, ftdmchan);
+ if (status == FTDM_FAIL) {
+ ftdm_log(FTDM_LOG_ERROR, "Cannot handle request to start call in channel %d, failed to create thread!\n",
+ openr2_chan_get_number(r2chan));
+ }
+}
+
+/* only called for incoming calls when the ANI, DNIS etc is complete and the user has to decide either to accept or reject the call */
+static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, openr2_calling_party_category_t category)
+{
+ ftdm_sigmsg_t sigev;
+ ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+
+ ftdm_log(FTDM_LOG_NOTICE, "Call offered on chan %d, ANI = %s, DNIS = %s, Category = %s\n", openr2_chan_get_number(r2chan),
+ ani, dnis, openr2_proto_get_category_string(category));
+
+ /* notify the user about the new call */
+ memset(&sigev, 0, sizeof(sigev));
+ sigev.chan_id = ftdmchan->chan_id;
+ sigev.span_id = ftdmchan->span_id;
+ sigev.channel = ftdmchan;
+ sigev.event_id = FTDM_SIGEVENT_START;
+
+ if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_NOTICE, "Failed to handle call offered on chan %d\n", openr2_chan_get_number(r2chan));
+ openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CANCEL);
+ return;
+ }
+ ftdm_channel_use(ftdmchan);
+ R2CALL(ftdmchan)->ftdm_started = 1;
+}
+
+static void ftdm_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
+{
+ ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+ ftdm_log(FTDM_LOG_NOTICE, "Call accepted on chan %d\n", openr2_chan_get_number(r2chan));
+ /* at this point the MF signaling has ended and there is no point on keep reading */
+ openr2_chan_disable_read(r2chan);
+ if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
+ R2CALL(ftdmchan)->state_ack_pending = 1;
+ if (R2CALL(ftdmchan)->answer_pending) {
+ ftdm_log(FTDM_LOG_DEBUG, "Answer was pending on chan %d, answering now.\n", openr2_chan_get_number(r2chan));
+ ft_r2_answer_call(ftdmchan);
+ return;
+ }
+ } else {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+ }
+}
+
+static void ftdm_r2_on_call_answered(openr2_chan_t *r2chan)
+{
+ ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+ ftdm_log(FTDM_LOG_NOTICE, "Call answered on chan %d\n", openr2_chan_get_number(r2chan));
+ /* notify the upper layer of progress in the outbound call */
+ if (OR2_DIR_FORWARD == openr2_chan_get_direction(r2chan)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
+ }
+}
+
+/* may be called in the signaling or media thread depending on whether the hangup is product of MF or CAS signaling */
+static void ftdm_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disconnect_cause_t cause)
+{
+ ftdm_sigmsg_t sigev;
+ ftdm_r2_data_t *r2data;
+ ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+ ftdm_log(FTDM_LOG_NOTICE, "Call disconnected on chan %d\n", openr2_chan_get_number(r2chan));
+
+ ftdm_log(FTDM_LOG_DEBUG, "Got openr2 disconnection, clearing call on channel %d\n", ftdmchan->physical_chan_id);
+
+ R2CALL(ftdmchan)->disconnect_rcvd = 1;
+
+ /* acknowledge the hangup, cause will be ignored. From here to -> HANGUP once the freetdm side hangs up as well */
+ openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
+
+ /* if the call has not been started yet we must go to HANGUP right here */
+ if (!R2CALL(ftdmchan)->ftdm_started) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ return;
+ }
+
+ /* FIXME: use the cause received from openr2 and map it to ftdm cause */
+ ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING;
+
+ /* notify the user of the call terminating */
+ memset(&sigev, 0, sizeof(sigev));
+ sigev.chan_id = ftdmchan->chan_id;
+ sigev.span_id = ftdmchan->span_id;
+ sigev.channel = ftdmchan;
+ sigev.event_id = FTDM_SIGEVENT_STOP;
+ r2data = ftdmchan->span->signal_data;
+
+ ftdm_span_send_signal(ftdmchan->span, &sigev);
+}
+
+static void ftdm_r2_on_call_end(openr2_chan_t *r2chan)
+{
+ ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+ ftdm_log(FTDM_LOG_NOTICE, "Call finished on chan %d\n", openr2_chan_get_number(r2chan));
+ /* this means the freetdm side disconnected the call, therefore we must move to DOWN here */
+ if (!R2CALL(ftdmchan)->disconnect_rcvd) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ return;
+ }
+}
+
+static void ftdm_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen)
+{
+ ftdm_log(FTDM_LOG_NOTICE, "Call read data on chan %d\n", openr2_chan_get_number(r2chan));
+}
+
+static void ftdm_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
+{
+ ftdm_log(FTDM_LOG_NOTICE, "Alarm on chan %d (%d)\n", openr2_chan_get_number(r2chan), alarm);
+}
+
+static void ftdm_r2_on_os_error(openr2_chan_t *r2chan, int errorcode)
+{
+ ftdm_log(FTDM_LOG_ERROR, "OS error on chan %d: %s\n", openr2_chan_get_number(r2chan), strerror(errorcode));
+}
+
+static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_error_t reason)
+{
+ ftdm_sigmsg_t sigev;
+ ftdm_r2_data_t *r2data;
+ ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+
+ ftdm_log(FTDM_LOG_ERROR, "Protocol error on chan %d\n", openr2_chan_get_number(r2chan));
+
+ R2CALL(ftdmchan)->disconnect_rcvd = 1;
+
+ if (!R2CALL(ftdmchan)->ftdm_started) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ return;
+ }
+
+ ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_PROTOCOL_ERROR;
+
+ /* notify the user of the call terminating */
+ memset(&sigev, 0, sizeof(sigev));
+ sigev.chan_id = ftdmchan->chan_id;
+ sigev.span_id = ftdmchan->span_id;
+ sigev.channel = ftdmchan;
+ sigev.event_id = FTDM_SIGEVENT_STOP;
+ r2data = ftdmchan->span->signal_data;
+
+ ftdm_span_send_signal(ftdmchan->span, &sigev);
+}
+
+static void ftdm_r2_on_line_blocked(openr2_chan_t *r2chan)
+{
+ ftdm_log(FTDM_LOG_NOTICE, "Far end blocked on chan %d\n", openr2_chan_get_number(r2chan));
+}
+
+static void ftdm_r2_on_line_idle(openr2_chan_t *r2chan)
+{
+ ftdm_log(FTDM_LOG_NOTICE, "Far end unblocked on chan %d\n", openr2_chan_get_number(r2chan));
+}
+
+static void ftdm_r2_write_log(openr2_log_level_t level, const char *message)
+{
+ switch (level) {
+ case OR2_LOG_NOTICE:
+ ftdm_log(FTDM_LOG_NOTICE, "%s", message);
+ break;
+ case OR2_LOG_WARNING:
+ ftdm_log(FTDM_LOG_WARNING, "%s", message);
+ break;
+ case OR2_LOG_ERROR:
+ ftdm_log(FTDM_LOG_ERROR, "%s", message);
+ break;
+ case OR2_LOG_STACK_TRACE:
+ case OR2_LOG_MF_TRACE:
+ case OR2_LOG_CAS_TRACE:
+ case OR2_LOG_DEBUG:
+ case OR2_LOG_EX_DEBUG:
+ ftdm_log(FTDM_LOG_DEBUG, "%s", message);
+ break;
+ default:
+ ftdm_log(FTDM_LOG_WARNING, "We should handle logging level %d here.\n", level);
+ ftdm_log(FTDM_LOG_DEBUG, "%s", message);
+ break;
+ }
+}
+
+static void ftdm_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap)
+{
+#define CONTEXT_TAG "Context -"
+ char logmsg[256];
+ char completemsg[sizeof(logmsg) + sizeof(CONTEXT_TAG) - 1];
+ vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
+ snprintf(completemsg, sizeof(completemsg), CONTEXT_TAG "%s", logmsg);
+ ftdm_r2_write_log(level, completemsg);
+#undef CONTEXT_TAG
+}
+
+static void ftdm_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap)
+{
+#define CHAN_TAG "Chan "
+ char logmsg[256];
+ char completemsg[sizeof(logmsg) + sizeof(CHAN_TAG) - 1];
+ vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
+ snprintf(completemsg, sizeof(completemsg), CHAN_TAG "%d: %s", openr2_chan_get_number(r2chan), logmsg);
+ ftdm_r2_write_log(level, completemsg);
+#undef CHAN_TAG
+}
+
+static int ftdm_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit)
+{
+ ftdm_sigmsg_t sigev;
+ ftdm_r2_data_t *r2data;
+ ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+ ftdm_size_t collected_len = R2CALL(ftdmchan)->dnis_index;
+
+ ftdm_log(FTDM_LOG_DEBUG, "DNIS digit %d received chan %d\n", digit, openr2_chan_get_number(r2chan));
+
+ /* save the digit we just received */
+ ftdmchan->caller_data.dnis.digits[collected_len] = digit;
+ collected_len++;
+ ftdmchan->caller_data.dnis.digits[collected_len] = '\0';
+ R2CALL(ftdmchan)->dnis_index = collected_len;
+
+ /* notify the user about the new digit and check if we should stop requesting more DNIS */
+ memset(&sigev, 0, sizeof(sigev));
+ sigev.chan_id = ftdmchan->chan_id;
+ sigev.span_id = ftdmchan->span_id;
+ sigev.channel = ftdmchan;
+ sigev.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT;
+ r2data = ftdmchan->span->signal_data;
+ if (ftdm_span_send_signal(ftdmchan->span, &sigev) == FTDM_BREAK) {
+ ftdm_log(FTDM_LOG_NOTICE, "Requested to stop getting DNIS. Current DNIS = %s on chan %d\n", ftdmchan->caller_data.dnis.digits, openr2_chan_get_number(r2chan));
+ return OR2_STOP_DNIS_REQUEST;
+ }
+
+ /* the only other reason to stop requesting DNIS is that there is no more room to save it */
+ if (collected_len == (sizeof(ftdmchan->caller_data.dnis.digits) - 1)) {
+ ftdm_log(FTDM_LOG_NOTICE, "No more room for DNIS. Current DNIS = %s on chan %d\n", ftdmchan->caller_data.dnis.digits, openr2_chan_get_number(r2chan));
+ return OR2_STOP_DNIS_REQUEST;
+ }
+
+ return OR2_CONTINUE_DNIS_REQUEST;
+}
+
+static void ftdm_r2_on_ani_digit_received(openr2_chan_t *r2chan, char digit)
+{
+ ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+ ftdm_size_t collected_len = R2CALL(ftdmchan)->ani_index;
+
+ /* check if we should drop ANI */
+ if (collected_len == (sizeof(ftdmchan->caller_data.ani.digits) - 1)) {
+ ftdm_log(FTDM_LOG_NOTICE, "No more room for ANI %c on chan %d, digit dropped.\n", digit, openr2_chan_get_number(r2chan));
+ return;
+ }
+ ftdm_log(FTDM_LOG_DEBUG, "ANI digit %c received chan %d\n", digit, openr2_chan_get_number(r2chan));
+
+ /* save the digit we just received */
+ ftdmchan->caller_data.ani.digits[collected_len++] = digit;
+ ftdmchan->caller_data.ani.digits[collected_len] = '\0';
+}
+
+static openr2_event_interface_t ftdm_r2_event_iface = {
+ .on_call_init = ftdm_r2_on_call_init,
+ .on_call_offered = ftdm_r2_on_call_offered,
+ .on_call_accepted = ftdm_r2_on_call_accepted,
+ .on_call_answered = ftdm_r2_on_call_answered,
+ .on_call_disconnect = ftdm_r2_on_call_disconnect,
+ .on_call_end = ftdm_r2_on_call_end,
+ .on_call_read = ftdm_r2_on_call_read,
+ .on_hardware_alarm = ftdm_r2_on_hardware_alarm,
+ .on_os_error = ftdm_r2_on_os_error,
+ .on_protocol_error = ftdm_r2_on_protocol_error,
+ .on_line_blocked = ftdm_r2_on_line_blocked,
+ .on_line_idle = ftdm_r2_on_line_idle,
+ /* cast seems to be needed to get rid of the annoying warning regarding format attribute */
+ .on_context_log = (openr2_handle_context_logging_func)ftdm_r2_on_context_log,
+ .on_dnis_digit_received = ftdm_r2_on_dnis_digit_received,
+ .on_ani_digit_received = ftdm_r2_on_ani_digit_received,
+ /* so far we do nothing with billing pulses */
+ .on_billing_pulse_received = NULL
+};
+
+static int ftdm_r2_io_set_cas(openr2_chan_t *r2chan, int cas)
+{
+ ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan);
+ ftdm_status_t status = ftdm_channel_command(ftdm_chan, FTDM_COMMAND_SET_CAS_BITS, &cas);
+ if (FTDM_FAIL == status) {
+ return -1;
+ }
+ return 0;
+}
+
+static int ftdm_r2_io_get_cas(openr2_chan_t *r2chan, int *cas)
+{
+ ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan);
+ ftdm_status_t status = ftdm_channel_command(ftdm_chan, FTDM_COMMAND_GET_CAS_BITS, cas);
+ if (FTDM_FAIL == status) {
+ return -1;
+ }
+ return 0;
+}
+
+static int ftdm_r2_io_flush_write_buffers(openr2_chan_t *r2chan)
+{
+ ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan);
+ ftdm_status_t status = ftdm_channel_command(ftdm_chan, FTDM_COMMAND_FLUSH_TX_BUFFERS, NULL);
+ if (FTDM_FAIL == status) {
+ return -1;
+ }
+ return 0;
+}
+
+static int ftdm_r2_io_write(openr2_chan_t *r2chan, const void *buf, int size)
+{
+ ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan);
+ ftdm_size_t outsize = size;
+ ftdm_status_t status = ftdm_channel_write(ftdm_chan, (void *)buf, size, &outsize);
+ if (FTDM_FAIL == status) {
+ return -1;
+ }
+ return outsize;
+}
+
+static int ftdm_r2_io_read(openr2_chan_t *r2chan, const void *buf, int size)
+{
+ ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan);
+ ftdm_size_t outsize = size;
+ ftdm_status_t status = ftdm_channel_read(ftdm_chan, (void *)buf, &outsize);
+ if (FTDM_FAIL == status) {
+ return -1;
+ }
+ return outsize;
+}
+
+static int ftdm_r2_io_wait(openr2_chan_t *r2chan, int *flags, int block)
+{
+ ftdm_status_t status;
+ ftdm_wait_flag_t ftdmflags = 0;
+
+ ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan);
+ int32_t timeout = block ? -1 : 0;
+
+ if (*flags & OR2_IO_READ) {
+ ftdmflags |= FTDM_READ;
+ }
+ if (*flags & OR2_IO_WRITE) {
+ ftdmflags |= FTDM_WRITE;
+ }
+ if (*flags & OR2_IO_OOB_EVENT) {
+ ftdmflags |= FTDM_EVENTS;
+ }
+
+ status = ftdm_channel_wait(ftdm_chan, &ftdmflags, timeout);
+
+ if (FTDM_SUCCESS != status) {
+ return -1;
+ }
+
+ *flags = 0;
+ if (ftdmflags & FTDM_READ) {
+ *flags |= OR2_IO_READ;
+ }
+ if (ftdmflags & FTDM_WRITE) {
+ *flags |= OR2_IO_WRITE;
+ }
+ if (ftdmflags & FTDM_EVENTS) {
+ *flags |= OR2_IO_OOB_EVENT;
+ }
+
+ return 0;
+}
+
+/* The following openr2 hooks never get called, read on for reasoning ... */
+/* since freetdm takes care of opening the file descriptor and using openr2_chan_new_from_fd, openr2 should never call this hook */
+static openr2_io_fd_t ftdm_r2_io_open(openr2_context_t *r2context, int channo)
+{
+ ftdm_log(FTDM_LOG_ERROR, "I should not be called (I/O open)!!\n");
+ return NULL;
+}
+
+/* since freetdm takes care of closing the file descriptor and uses openr2_chan_new_from_fd, openr2 should never call this hook */
+static int ftdm_r2_io_close(openr2_chan_t *r2chan)
+{
+ ftdm_log(FTDM_LOG_ERROR, "I should not be called (I/O close)!!\n");
+ return 0;
+}
+
+/* since freetdm takes care of opening the file descriptor and using openr2_chan_new_from_fd, openr2 should never call this hook */
+static int ftdm_r2_io_setup(openr2_chan_t *r2chan)
+{
+ ftdm_log(FTDM_LOG_ERROR, "I should not be called (I/O Setup)!!\n");
+ return 0;
+}
+
+/* since the signaling thread calls openr2_chan_process_cas_signaling directly, openr2 should never call this hook */
+static int ftdm_r2_io_get_oob_event(openr2_chan_t *r2chan, openr2_oob_event_t *event)
+{
+ *event = 0;
+ ftdm_log(FTDM_LOG_ERROR, "I should not be called (I/O get oob event)!!\n");
+ return 0;
+}
+
+static openr2_io_interface_t ftdm_r2_io_iface = {
+ .open = ftdm_r2_io_open, /* never called */
+ .close = ftdm_r2_io_close, /* never called */
+ .set_cas = ftdm_r2_io_set_cas,
+ .get_cas = ftdm_r2_io_get_cas,
+ .flush_write_buffers = ftdm_r2_io_flush_write_buffers,
+ .write = ftdm_r2_io_write,
+ .read = ftdm_r2_io_read,
+ .setup = ftdm_r2_io_setup, /* never called */
+ .wait = ftdm_r2_io_wait,
+ .get_oob_event = ftdm_r2_io_get_oob_event /* never called */
+};
+
+static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span)
+ //ftdm_status_t (ftdm_span_t *span, fio_signal_cb_t sig_cb, va_list ap)
+{
+ int i = 0;
+ int conf_failure = 0;
+ char *var = NULL;
+ char *val = NULL;
+ ftdm_r2_data_t *r2data = NULL;
+ ftdm_r2_span_pvt_t *spanpvt = NULL;
+ ftdm_r2_call_t *r2call = NULL;
+ openr2_chan_t *r2chan = NULL;
+
+ assert(sig_cb != NULL);
+
+ ft_r2_conf_t r2conf =
+ {
+ .variant = OR2_VAR_ITU,
+ .category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER,
+ .loglevel = OR2_LOG_ERROR | OR2_LOG_WARNING,
+ .max_ani = 10,
+ .max_dnis = 4,
+ .mfback_timeout = -1,
+ .metering_pulse_timeout = -1,
+ .allow_collect_calls = -1,
+ .immediate_accept = -1,
+ .skip_category = -1,
+ .forced_release = -1,
+ .charge_calls = -1,
+ .get_ani_first = -1,
+ .call_files = -1,
+ .logdir = NULL,
+ .advanced_protocol_file = NULL
+ };
+
+
+ if (span->signal_type) {
+ snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
+ return FTDM_FAIL;
+ }
+
+ while ((var = va_arg(ap, char *))) {
+ ftdm_log(FTDM_LOG_DEBUG, "Reading R2 parameter %s for span %d\n", var, span->span_id);
+ if (!strcasecmp(var, "variant")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ if (ftdm_strlen_zero_buf(val)) {
+ ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 variant parameter\n");
+ continue;
+ }
+ r2conf.variant = openr2_proto_get_variant(val);
+ if (r2conf.variant == OR2_VAR_UNKNOWN) {
+ ftdm_log(FTDM_LOG_ERROR, "Unknown R2 variant %s\n", val);
+ conf_failure = 1;
+ break;
+ }
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d for variant %s\n", span->span_id, val);
+ } else if (!strcasecmp(var, "category")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ if (ftdm_strlen_zero_buf(val)) {
+ ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 category parameter\n");
+ continue;
+ }
+ r2conf.category = openr2_proto_get_category(val);
+ if (r2conf.category == OR2_CALLING_PARTY_CATEGORY_UNKNOWN) {
+ ftdm_log(FTDM_LOG_ERROR, "Unknown R2 caller category %s\n", val);
+ conf_failure = 1;
+ break;
+ }
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with default category %s\n", span->span_id, val);
+ } else if (!strcasecmp(var, "logdir")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ if (ftdm_strlen_zero_buf(val)) {
+ ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 logdir parameter\n");
+ continue;
+ }
+ r2conf.logdir = val;
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with logdir %s\n", span->span_id, val);
+ } else if (!strcasecmp(var, "logging")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ if (ftdm_strlen_zero_buf(val)) {
+ ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 logging parameter\n");
+ continue;
+ }
+ openr2_log_level_t tmplevel;
+ char *clevel;
+ char *logval = ftdm_malloc(strlen(val)+1); /* alloca man page scared me, so better to use good ol' malloc */
+ if (!logval) {
+ ftdm_log(FTDM_LOG_WARNING, "Ignoring R2 logging parameter: '%s', failed to alloc memory\n", val);
+ continue;
+ }
+ strcpy(logval, val);
+ while (logval) {
+ clevel = strsep(&logval, ",");
+ if (-1 == (tmplevel = openr2_log_get_level(clevel))) {
+ ftdm_log(FTDM_LOG_WARNING, "Ignoring invalid R2 logging level: '%s'\n", clevel);
+ continue;
+ }
+ r2conf.loglevel |= tmplevel;
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with loglevel %s\n", span->span_id, clevel);
+ }
+ ftdm_safe_free(logval);
+ } else if (!strcasecmp(var, "advanced_protocol_file")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ if (ftdm_strlen_zero_buf(val)) {
+ ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 advanced_protocol_file parameter\n");
+ continue;
+ }
+ r2conf.advanced_protocol_file = val;
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with advanced protocol file %s\n", span->span_id, val);
+ } else if (!strcasecmp(var, "allow_collect_calls")) {
+ r2conf.allow_collect_calls = va_arg(ap, int);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with allow collect calls max ani = %d\n", span->span_id, r2conf.allow_collect_calls);
+ } else if (!strcasecmp(var, "double_answer")) {
+ r2conf.double_answer = va_arg(ap, int);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with double answer = %d\n", span->span_id, r2conf.double_answer);
+ } else if (!strcasecmp(var, "immediate_accept")) {
+ r2conf.immediate_accept = va_arg(ap, int);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with immediate accept = %d\n", span->span_id, r2conf.immediate_accept);
+ } else if (!strcasecmp(var, "skip_category")) {
+ r2conf.skip_category = va_arg(ap, int);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with skip category = %d\n", span->span_id, r2conf.skip_category);
+ } else if (!strcasecmp(var, "forced_release")) {
+ r2conf.forced_release = va_arg(ap, int);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with forced release = %d\n", span->span_id, r2conf.forced_release);
+ } else if (!strcasecmp(var, "charge_calls")) {
+ r2conf.charge_calls = va_arg(ap, int);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with charge calls = %d\n", span->span_id, r2conf.charge_calls);
+ } else if (!strcasecmp(var, "get_ani_first")) {
+ r2conf.get_ani_first = va_arg(ap, int);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with get ani first = %d\n", span->span_id, r2conf.get_ani_first);
+ } else if (!strcasecmp(var, "call_files")) {
+ r2conf.call_files = va_arg(ap, int);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with call files = %d\n", span->span_id, r2conf.call_files);
+ } else if (!strcasecmp(var, "mfback_timeout")) {
+ r2conf.mfback_timeout = va_arg(ap, int);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with MF backward timeout = %dms\n", span->span_id, r2conf.mfback_timeout);
+ } else if (!strcasecmp(var, "metering_pulse_timeout")) {
+ r2conf.metering_pulse_timeout = va_arg(ap, int);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with metering pulse timeout = %dms\n", span->span_id, r2conf.metering_pulse_timeout);
+ } else if (!strcasecmp(var, "max_ani")) {
+ r2conf.max_ani = va_arg(ap, int);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with max ani = %d\n", span->span_id, r2conf.max_ani);
+ } else if (!strcasecmp(var, "max_dnis")) {
+ r2conf.max_dnis = va_arg(ap, int);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with max dnis = %d\n", span->span_id, r2conf.max_dnis);
+ } else {
+ snprintf(span->last_error, sizeof(span->last_error), "Unknown R2 parameter [%s]", var);
+ return FTDM_FAIL;
+ }
+ }
+
+ if (conf_failure) {
+ snprintf(span->last_error, sizeof(span->last_error), "R2 configuration error");
+ return FTDM_FAIL;
+ }
+
+ r2data = ftdm_malloc(sizeof(*r2data));
+ if (!r2data) {
+ snprintf(span->last_error, sizeof(span->last_error), "Failed to allocate R2 data.");
+ return FTDM_FAIL;
+ }
+ memset(r2data, 0, sizeof(*r2data));
+
+ spanpvt = ftdm_malloc(sizeof(*spanpvt));
+ if (!spanpvt) {
+ snprintf(span->last_error, sizeof(span->last_error), "Failed to allocate private span data container.");
+ goto fail;
+ }
+ memset(spanpvt, 0, sizeof(*spanpvt));
+
+ r2data->r2context = openr2_context_new(r2conf.variant, &ftdm_r2_event_iface, r2conf.max_ani, r2conf.max_dnis);
+ if (!r2data->r2context) {
+ snprintf(span->last_error, sizeof(span->last_error), "Cannot create openr2 context for span.");
+ goto fail;
+ }
+ openr2_context_set_io_type(r2data->r2context, OR2_IO_CUSTOM, &ftdm_r2_io_iface);
+ openr2_context_set_log_level(r2data->r2context, r2conf.loglevel);
+ openr2_context_set_ani_first(r2data->r2context, r2conf.get_ani_first);
+ openr2_context_set_skip_category_request(r2data->r2context, r2conf.skip_category);
+ openr2_context_set_mf_back_timeout(r2data->r2context, r2conf.mfback_timeout);
+ openr2_context_set_metering_pulse_timeout(r2data->r2context, r2conf.metering_pulse_timeout);
+ openr2_context_set_double_answer(r2data->r2context, r2conf.double_answer);
+ openr2_context_set_immediate_accept(r2data->r2context, r2conf.immediate_accept);
+ if (r2conf.logdir) {
+ openr2_context_set_log_directory(r2data->r2context, r2conf.logdir);
+ }
+ if (r2conf.advanced_protocol_file) {
+ openr2_context_configure_from_advanced_file(r2data->r2context, r2conf.advanced_protocol_file);
+ }
+
+ spanpvt->r2calls = create_hashtable(FTDM_MAX_CHANNELS_SPAN, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+ if (!spanpvt->r2calls) {
+ snprintf(span->last_error, sizeof(span->last_error), "Cannot create channel calls hash for span.");
+ goto fail;
+ }
+
+ for (i = 1; (i <= span->chan_count) && (i <= FTDM_MAX_CHANNELS_SPAN); i++) {
+ r2chan = openr2_chan_new_from_fd(r2data->r2context, span->channels[i], span->channels[i]->physical_chan_id);
+ if (!r2chan) {
+ snprintf(span->last_error, sizeof(span->last_error), "Cannot create all openr2 channels for span.");
+ goto fail;
+ }
+ if (r2conf.call_files) {
+ openr2_chan_enable_call_files(r2chan);
+ openr2_chan_set_log_level(r2chan, r2conf.loglevel);
+ }
+
+ r2call = ftdm_malloc(sizeof(*r2call));
+ if (!r2call) {
+ snprintf(span->last_error, sizeof(span->last_error), "Cannot create all R2 call data structures for the span.");
+ ftdm_safe_free(r2chan);
+ goto fail;
+ }
+ memset(r2call, 0, sizeof(*r2call));
+ openr2_chan_set_logging_func(r2chan, ftdm_r2_on_chan_log);
+ openr2_chan_set_client_data(r2chan, span->channels[i]);
+ r2call->r2chan = r2chan;
+ span->channels[i]->call_data = r2call;
+ /* value and key are the same so just free one of them */
+ snprintf(r2call->name, sizeof(r2call->name), "chancall%d", i);
+ hashtable_insert(spanpvt->r2calls, (void *)r2call->name, r2call, HASHTABLE_FLAG_FREE_VALUE);
+
+ }
+ spanpvt->r2context = r2data->r2context;
+
+ /* just the value must be freed by the hash */
+ hashtable_insert(g_mod_data_hash, (void *)span->name, spanpvt, HASHTABLE_FLAG_FREE_VALUE);
+
+ span->start = ftdm_r2_start;
+ r2data->flags = 0;
+ span->signal_cb = sig_cb;
+ span->signal_type = FTDM_SIGTYPE_R2;
+ span->signal_data = r2data;
+ span->outgoing_call = r2_outgoing_call;
+
+ return FTDM_SUCCESS;
+
+fail:
+
+ if (r2data && r2data->r2context) {
+ openr2_context_delete(r2data->r2context);
+ }
+ if (spanpvt && spanpvt->r2calls) {
+ hashtable_destroy(spanpvt->r2calls);
+ }
+ ftdm_safe_free(r2data);
+ ftdm_safe_free(spanpvt);
+ return FTDM_FAIL;
+
+}
+
+static void *ftdm_r2_channel_run(ftdm_thread_t *me, void *obj)
+{
+ ftdm_channel_t *closed_chan;
+ uint32_t interval = 0;
+ ftdm_sigmsg_t sigev;
+ ftdm_channel_t *ftdmchan = (ftdm_channel_t *)obj;
+ openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan;
+
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_INTHREAD);
+
+ ftdm_mutex_lock(g_thread_count_mutex);
+ g_thread_count++;
+ ftdm_mutex_unlock(g_thread_count_mutex);
+
+ ftdm_log(FTDM_LOG_DEBUG, "R2 CHANNEL thread starting on %d in state %s.\n",
+ ftdmchan->physical_chan_id,
+ ftdm_channel_state2str(ftdmchan->state));
+
+ if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "OPEN ERROR [%s]\n", ftdmchan->last_error);
+ goto endthread;
+ }
+
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
+
+ assert(interval != 0);
+ ftdm_log(FTDM_LOG_DEBUG, "Got %d interval for chan %d\n", interval, ftdmchan->physical_chan_id);
+
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ /* FIXME: is this needed? */
+ memset(ftdmchan->caller_data.dnis.digits, 0, sizeof(ftdmchan->caller_data.collected));
+ memset(ftdmchan->caller_data.ani.digits, 0, sizeof(ftdmchan->caller_data.collected));
+ }
+
+ memset(&sigev, 0, sizeof(sigev));
+ sigev.chan_id = ftdmchan->chan_id;
+ sigev.span_id = ftdmchan->span_id;
+ sigev.channel = ftdmchan;
+
+ while (ftdm_running()) {
+ int32_t read_enabled = openr2_chan_get_read_enabled(r2chan);
+ ftdm_wait_flag_t flags = read_enabled ? ( FTDM_READ | FTDM_WRITE ) : 0;
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE) && (R2CALL(ftdmchan)->chanstate != ftdmchan->state)) {
+
+ ftdm_log(FTDM_LOG_DEBUG, "Executing state handler on %d:%d for %s\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
+ R2CALL(ftdmchan)->chanstate = ftdmchan->state;
+
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) && !R2CALL(ftdmchan)->accepted &&
+ (ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS ||
+ ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA ||
+ ftdmchan->state == FTDM_CHANNEL_STATE_UP) ) {
+ /* if an accept ack will be required we should not acknowledge the state change just yet,
+ it will be done below after processing the MF signals, otherwise we have a race condition between freetdm calling
+ openr2_chan_answer_call and openr2 accepting the call first, if freetdm calls openr2_chan_answer_call before the accept cycle
+ completes, openr2 will fail to answer the call */
+ ftdm_log(FTDM_LOG_DEBUG, "State ack in chan %d:%d for state %s will have to wait a bit\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
+ } else if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN){
+ /* the down state will be completed in ftdm_channel_done below */
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+ ftdm_channel_complete_state(ftdmchan);
+ }
+
+ switch (ftdmchan->state) {
+
+ /* starting an incoming call */
+ case FTDM_CHANNEL_STATE_COLLECT:
+ {
+ ftdm_log(FTDM_LOG_DEBUG, "COLLECT: Starting processing of incoming call in channel %d with interval %d\n", ftdmchan->physical_chan_id, interval);
+ }
+ break;
+
+ /* starting an outgoing call */
+ case FTDM_CHANNEL_STATE_DIALING:
+ {
+ // FIXME: use user defined calling party
+ ftdm_channel_use(ftdmchan);
+ ftdm_log(FTDM_LOG_DEBUG, "DIALING: Starting processing of outgoing call in channel %d with interval %d\n", ftdmchan->physical_chan_id, interval);
+ if (openr2_chan_make_call(r2chan, ftdmchan->caller_data.cid_num.digits, ftdmchan->caller_data.dnis.digits, OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER)) {
+ ftdm_log(FTDM_LOG_ERROR, "%d:%d Failed to make call in R2 channel, openr2_chan_make_call failed\n", ftdmchan->span_id, ftdmchan->chan_id);
+ ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER;
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ }
+ break;
+
+ /* the call is ringing */
+ case FTDM_CHANNEL_STATE_PROGRESS:
+ case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+ {
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ if (!R2CALL(ftdmchan)->accepted) {
+ ftdm_log(FTDM_LOG_DEBUG, "PROGRESS: Accepting call on channel %d\n", ftdmchan->physical_chan_id);
+ ft_r2_accept_call(ftdmchan);
+ }
+ } else {
+ ftdm_log(FTDM_LOG_DEBUG, "PROGRESS: Notifying progress in channel %d\n", ftdmchan->physical_chan_id);
+ sigev.event_id = FTDM_SIGEVENT_PROGRESS;
+ if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ }
+ }
+ break;
+
+ /* the call was answered */
+ case FTDM_CHANNEL_STATE_UP:
+ {
+ ftdm_log(FTDM_LOG_DEBUG, "UP: Call was answered on channel %d\n", ftdmchan->physical_chan_id);
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ if (!R2CALL(ftdmchan)->accepted) {
+ ftdm_log(FTDM_LOG_DEBUG, "UP: Call has not been accepted, need to accept first\n");
+ // the answering will be done in the on_call_accepted handler
+ ft_r2_accept_call(ftdmchan);
+ R2CALL(ftdmchan)->answer_pending = 1;
+ } else {
+ ft_r2_answer_call(ftdmchan);
+ }
+ } else {
+ ftdm_log(FTDM_LOG_DEBUG, "UP: Notifying of call answered in channel %d\n", ftdmchan->physical_chan_id);
+ sigev.event_id = FTDM_SIGEVENT_UP;
+ if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ }
+ }
+ break;
+
+ /* just got hangup */
+ case FTDM_CHANNEL_STATE_HANGUP:
+ {
+ /* FIXME: the cause should be retrieved from ftdmchan->caller_data.hangup_cause and translated from Q931 to R2 cause */
+ ftdm_log(FTDM_LOG_DEBUG, "HANGUP: Clearing call on channel %d\n", ftdmchan->physical_chan_id);
+ if (!R2CALL(ftdmchan)->disconnect_rcvd) {
+ /* this will disconnect the call, but need to wait for the call end before moving to DOWN */
+ openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
+ } else {
+ /* at this point on_call_end possibly was already called,
+ * but we needed to wait for the freetdm confirmation before moving to DOWN */
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ }
+ }
+ break;
+
+ /* just got hangup from the freetdm side due to abnormal failure */
+ case FTDM_CHANNEL_STATE_CANCEL:
+ {
+ ftdm_log(FTDM_LOG_DEBUG, "CANCEL: Unable to receive call on channel %d\n", ftdmchan->physical_chan_id);
+ openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
+ }
+ break;
+
+ /* finished call for good */
+ case FTDM_CHANNEL_STATE_DOWN:
+ {
+ ftdm_log(FTDM_LOG_DEBUG, "DOWN: Placing channel %d back to the pool of available channels\n", ftdmchan->physical_chan_id);
+ ftdm_channel_done(ftdmchan);
+ goto endthread;
+ }
+ break;
+
+ default:
+ {
+ ftdm_log(FTDM_LOG_ERROR, "%s: Unhandled channel state change in channel %d\n", ftdm_channel_state2str(ftdmchan->state), ftdmchan->physical_chan_id);
+ }
+ break;
+
+ }
+ }
+
+ if (flags) {
+ if (ftdm_channel_wait(ftdmchan, &flags, interval * 2) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_DEBUG, "ftdm_channel_wait did not return FTDM_SUCCESS\n");
+ continue;
+ }
+
+ /* handle timeout events first if any */
+ openr2_chan_run_schedule(r2chan);
+
+ /* openr2 will now try to detect MF tones, make sense out of them, reply if necessary with another tone and trigger
+ * telephony events via the call event interface we provided when creating the R2 context.
+ * openr2 will also call our I/O callbacks to retrieve audio from the channel and call our wait poll I/O registered callback
+ * and will not return from this function until the I/O poll callback returns no pending events
+ * */
+ openr2_chan_process_mf_signaling(r2chan);
+ if (R2CALL(ftdmchan)->state_ack_pending) {
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+ ftdm_channel_complete_state(ftdmchan);
+ R2CALL(ftdmchan)->state_ack_pending = 0;
+ }
+ } else {
+ /* once the MF signaling has end we just loop here waiting for state changes */
+ ftdm_sleep(interval);
+ }
+
+ }
+
+endthread:
+
+ closed_chan = ftdmchan;
+ ftdm_channel_close(&closed_chan);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_INTHREAD);
+ ftdm_log(FTDM_LOG_DEBUG, "R2 channel %d thread ended.\n", ftdmchan->physical_chan_id);
+
+ ftdm_mutex_lock(g_thread_count_mutex);
+ g_thread_count--;
+ ftdm_mutex_unlock(g_thread_count_mutex);
+
+ return NULL;
+}
+
+static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
+{
+ openr2_chan_t *r2chan;
+ ftdm_status_t status;
+ ftdm_span_t *span = (ftdm_span_t *) obj;
+ ftdm_r2_data_t *r2data = span->signal_data;
+ int waitms = 1000;
+ int i;
+
+ ftdm_log(FTDM_LOG_DEBUG, "OpenR2 monitor thread started.\n");
+ r2chan = NULL;
+ for (i = 1; i <= span->chan_count; i++) {
+ r2chan = R2CALL(span->channels[i])->r2chan;
+ openr2_chan_set_idle(r2chan);
+ openr2_chan_process_cas_signaling(r2chan);
+ }
+
+ while (ftdm_running() && ftdm_test_flag(r2data, FTDM_R2_RUNNING)) {
+ status = ftdm_span_poll_event(span, waitms);
+ if (FTDM_FAIL == status) {
+ ftdm_log(FTDM_LOG_ERROR, "Failure Polling event! [%s]\n", span->last_error);
+ continue;
+ }
+ if (FTDM_SUCCESS == status) {
+ ftdm_event_t *event;
+ while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
+ if (event->enum_id == FTDM_OOB_CAS_BITS_CHANGE) {
+ r2chan = R2CALL(event->channel)->r2chan;
+ ftdm_log(FTDM_LOG_DEBUG, "Handling CAS on channel %d.\n", openr2_chan_get_number(r2chan));
+ // we only expect CAS and other OOB events on this thread/loop, once a call is started
+ // the MF events (in-band signaling) are handled in the call thread
+ openr2_chan_process_cas_signaling(r2chan);
+ } else {
+ ftdm_log(FTDM_LOG_DEBUG, "Ignoring event %d on channel %d.\n", event->enum_id, openr2_chan_get_number(r2chan));
+ // XXX TODO: handle alarms here XXX
+ }
+ }
+ } else if (status != FTDM_TIMEOUT) {
+ ftdm_log(FTDM_LOG_ERROR, "ftdm_span_poll_event returned %d.\n", status);
+ } else {
+ //ftdm_log(FTDM_LOG_DEBUG, "timed out waiting for event on span %d\n", span->span_id);
+ }
+ }
+
+ /*
+ FIXME: we should set BLOCKED but at this point I/O routines of freetdm caused segfault
+ for (i = 1; i <= span->chan_count; i++) {
+ r2chan = R2CALL(span->channels[i])->r2chan;
+ openr2_chan_set_blocked(r2chan);
+ }
+ */
+
+ ftdm_clear_flag(r2data, FTDM_R2_RUNNING);
+ ftdm_log(FTDM_LOG_DEBUG, "R2 thread ending.\n");
+
+ return NULL;
+
+}
+
+static FIO_API_FUNCTION(ftdm_r2_api)
+{
+ char *mycmd = NULL, *argv[10] = { 0 };
+ int argc = 0;
+
+ if (data) {
+ mycmd = ftdm_strdup(data);
+ argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+ }
+
+ if (argc == 2) {
+ if (!strcasecmp(argv[0], "kill")) {
+ int span_id = atoi(argv[1]);
+ ftdm_span_t *span = NULL;
+
+ if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) {
+ ftdm_r2_data_t *r2data = span->signal_data;
+
+ if (span->start != ftdm_r2_start) {
+ stream->write_function(stream, "-ERR invalid span.\n");
+ goto done;
+ }
+
+ ftdm_clear_flag(r2data, FTDM_R2_RUNNING);
+ stream->write_function(stream, "+OK killed.\n");
+ goto done;
+ } else {
+ stream->write_function(stream, "-ERR invalid span.\n");
+ goto done;
+ }
+ }
+
+ if (!strcasecmp(argv[0], "status")) {
+ int span_id = atoi(argv[1]);
+ ftdm_r2_data_t *r2data = NULL;
+ ftdm_span_t *span = NULL;
+ openr2_chan_t *r2chan = NULL;
+ openr2_context_t *r2context = NULL;
+ int i = 0;
+
+ if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) {
+ if (span->start != ftdm_r2_start) {
+ stream->write_function(stream, "-ERR not an R2 span.\n");
+ goto done;
+ }
+ if (!(r2data = span->signal_data)) {
+ stream->write_function(stream, "-ERR invalid span. No R2 singal data in span.\n");
+ goto done;
+ }
+ r2context = r2data->r2context;
+ openr2_variant_t r2variant = openr2_context_get_variant(r2context);
+ stream->write_function(stream,
+ "Variant: %s\n"
+ "Max ANI: %d\n"
+ "Max DNIS: %d\n"
+ "ANI First: %s\n"
+ "Immediate Accept: %s\n",
+ openr2_proto_get_variant_string(r2variant),
+ openr2_context_get_max_ani(r2context),
+ openr2_context_get_max_dnis(r2context),
+ openr2_context_get_ani_first(r2context) ? "Yes" : "No",
+ openr2_context_get_immediate_accept(r2context) ? "Yes" : "No");
+ stream->write_function(stream, "\n");
+ stream->write_function(stream, "%4s %-12.12s %-12.12s\n", "Channel", "Tx CAS", "Rx CAS");
+ for (i = 1; i <= span->chan_count; i++) {
+ if (i == 16) continue;
+ r2chan = R2CALL(span->channels[i])->r2chan;
+ stream->write_function(stream, "%4d %-12.12s %-12.12s\n",
+ span->channels[i]->physical_chan_id,
+ openr2_chan_get_tx_cas_string(r2chan),
+ openr2_chan_get_rx_cas_string(r2chan));
+ }
+ stream->write_function(stream, "\n");
+ stream->write_function(stream, "+OK.\n");
+ goto done;
+ } else {
+ stream->write_function(stream, "-ERR invalid span.\n");
+ goto done;
+ }
+ }
+
+ }
+
+ if (argc == 1) {
+ if (!strcasecmp(argv[0], "threads")) {
+ ftdm_mutex_lock(g_thread_count_mutex);
+ stream->write_function(stream, "%d R2 channel threads up\n", g_thread_count);
+ ftdm_mutex_unlock(g_thread_count_mutex);
+ stream->write_function(stream, "+OK.\n");
+ goto done;
+ }
+
+ if (!strcasecmp(argv[0], "version")) {
+ stream->write_function(stream, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision());
+ stream->write_function(stream, "+OK.\n");
+ goto done;
+ }
+
+ if (!strcasecmp(argv[0], "variants")) {
+ int32_t numvariants = 0;
+ const openr2_variant_entry_t *variants = openr2_proto_get_variant_list(&numvariants);
+ if (!variants) {
+ stream->write_function(stream, "-ERR failed to retrieve openr2 variant list.\n");
+ goto done;
+ }
+#define VARIANT_FORMAT "%4s %40s\n"
+ stream->write_function(stream, VARIANT_FORMAT, "Variant Code", "Country");
+ numvariants--;
+ for (; numvariants; numvariants--) {
+ stream->write_function(stream, VARIANT_FORMAT, variants[numvariants].name, variants[numvariants].country);
+ }
+ stream->write_function(stream, "+OK.\n");
+#undef VARIANT_FORMAT
+ goto done;
+ }
+ }
+
+ stream->write_function(stream, "-ERR invalid command.\n");
+
+done:
+
+ ftdm_safe_free(mycmd);
+
+ return FTDM_SUCCESS;
+
+}
+
+static FIO_IO_LOAD_FUNCTION(ftdm_r2_io_init)
+{
+ assert(fio != NULL);
+ memset(&g_ftdm_r2_interface, 0, sizeof(g_ftdm_r2_interface));
+
+ g_ftdm_r2_interface.name = "r2";
+ g_ftdm_r2_interface.api = ftdm_r2_api;
+
+ *fio = &g_ftdm_r2_interface;
+
+ return FTDM_SUCCESS;
+}
+
+static FIO_SIG_LOAD_FUNCTION(ftdm_r2_init)
+{
+ g_mod_data_hash = create_hashtable(10, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+ if (!g_mod_data_hash) {
+ return FTDM_FAIL;
+ }
+ ftdm_mutex_create(&g_thread_count_mutex);
+ return FTDM_SUCCESS;
+}
+
+static FIO_SIG_UNLOAD_FUNCTION(ftdm_r2_destroy)
+{
+ ftdm_hash_iterator_t *i = NULL;
+ ftdm_r2_span_pvt_t *spanpvt = NULL;
+ const void *key = NULL;
+ void *val = NULL;
+ for (i = hashtable_first(g_mod_data_hash); i; i = hashtable_next(i)) {
+ hashtable_this(i, &key, NULL, &val);
+ if (key && val) {
+ spanpvt = val;
+ openr2_context_delete(spanpvt->r2context);
+ hashtable_destroy(spanpvt->r2calls);
+ }
+ }
+ hashtable_destroy(g_mod_data_hash);
+ ftdm_mutex_destroy(&g_thread_count_mutex);
+ return FTDM_SUCCESS;
+}
+
+ftdm_module_t ftdm_module = {
+ "r2",
+ ftdm_r2_io_init,
+ NULL,
+ ftdm_r2_init,
+ ftdm_r2_configure_span,
+ ftdm_r2_destroy
+};
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4
+ */
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/BOOST.limitations (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/BOOST.limitations (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/BOOST.limitations 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,20 @@
+== Boost sigmod current limitations ==
+- we don't support having openzap spans with physical channels
+ belonging to other physical spans. this is due to netborder sangoma abstraction, therefore
+ any openzap span using sigboost must have only channels belonging to the corresponding
+ physical span.
+
+ This is the reason we added group functionality in openzap core, furthermore, previous groups in openzap
+ were only possible through adding of b-channels to a single span, but this forces the user to create groups
+ of channels only whithin the same type of trunk among other things.
+
+- all spans must be configured and then started, cannot configure, start, configure start etc
+ this is due to netborder telesoft abstraction. that requires configuring everything and
+ then starting everything at once.
+
+- sangoma_prid and sangoma_brid on Windows had to be compiled hacking make/Makefile.platform to comment all VC runtime checks,
+ otherwise when running in debug mode exceptions are thrown due to loss of data ie short to char conversions.
+
+== TODO ==
+- proper upper layer management of HW alarms (this must be done in mod_openzap.c)
+
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/boost-tasks.txt (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/boost-tasks.txt (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/boost-tasks.txt 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,146 @@
+== General Design ==
+
+NBE will do its current loading of spans and configuration process through Sangoma Board Manager (SBM).
+After doing SangomaBoardManager::getInstance().configure -> start. It will proceed to initalize
+the openzap stack (just as the TelesoftStack is loaded after starting SMB. The procedure will be:
+
+- create a static or malloced zap_io_interface_t
+- call zap_global_set_logger with the logging hooks.
+- call zap_global_set_memhandler() with the memory hooks.
+- call zap_global_init() to initialize the stack
+- call zap_add_io_iface() to add the I/O iface.
+- iterate over all SBM spans configured for BRI or any boost-managed signaling and:
+ * call zap_span_create(NBE I/O mod, in_ptrSpan, SMB span name)
+ * Fill in some members like:
+ span->trunk_type = E1/T1/J1/FXO/FXS etc ...
+ * iterate over all channels in SMB span and:
+ * zap_span_add_channel(zap_span, sock, type:CAS|BCHAN|DCHAN|ETC)
+ * call zap_configure_span("sangoma_boost", span, sigmsg_callback, "param1", value1, "param2", value1 ...)
+ * zap_span_start(span);
+
+
+At this point, NBE would receive signaling msgs via sigmsg_callback registered when configuring
+and NBE would request hangup or making calls throug openzap API, like zap_set_state_* and zap_channel_outgoing_call() to place calls.
+
+When NBE wants to check for link status.
+
+ zap_get_siglink_state() which would return
+ ZAP_SIG_STATE_UP (D-chan UP, R2 bits in IDLE, ss7?)
+ ZAP_SIG_STATE_SUSPENDED (D-chan in power saving mode?)
+ ZAP_SIG_STATE_DOWN (D-chan down, R2 bits in blocked, ss7?)
+
+ Whenever a state in sig link changes, the sigmsg_callback will be used to notify NBE or any other user.
+
+NOTE: right now hardware alarms notification in openzap is seriously broken,
+see ozmod_libpri.c process_event ... reads an event from hardware (zap_event_t *),
+then checks the event type, if its ZAP_OOB_ALARM_TRAP prepares a zap_sigmsg_t
+(signaling event) setting its event_id to ZAP_OOB_ALARM_TRAP, which is *WRONG*
+because event_id is of type zap_signal_event_t and not zap_oob_event_t!
+this means on alarm the user will get ZAP_SIGEVENT_PROGRESS_MEDIA!! which is
+value 7 that is in conflict with ZAP_OOB_ALARM_TRAP, I think a separate
+callback should be used if the outside user wants to be notified about
+hardware events like HW DTMF or so. Currently there is alreadya generic DTMF
+listener.
+
+== Tasks Stage 1 / OpenZAP and Boost changes (To be tested with FreeSWITCH) ==
+
+- Change malloc and other mem functions in openzap
+ to use internal hooks provided via zap_global_set_memhandler()
+ which would be called before zap_global_init(), this is
+ already done for the logger via zap_global_set_logger()
+
+ question: should the mem routines allow for memory pool ptr?
+ this could be useful to provide a memory pool to
+ the whole module.
+
+ question: should we allow hooks for threads and locking?
+ I think we can skip this one unless needed. They already
+ use their own threading abstraction which is working for
+ Linux and Windows. If we ever need to profile threading
+ we can add profiling hooks.
+
+ question: I had to add openzap calls to the hash table and libteletone implementations, is that acceptable?
+
+- Modify zap_global_init() API
+
+ This API must just initialize vars, mutexes etc.
+ and NOT DO ANY CONFIGURATION LOADING, PARSING, SPAN CREATION and I/O
+ configuration, which is what is currently doing.
+ We don't want zap_global_init() to create the spans based on that configuration
+ since NBE will have its own configuration and will take care of creating
+ the needed data structures on its own.
+
+- Add new zap_std_io_config() API
+
+ This API will parse the standard openzap.conf module and create the spans.
+ This will be used by FS but not by NBE, which will create the openzap spans by itself.
+ The NBE flow to initialize openzap will be:
+
+- Add new API zap_global_add_io_iface(),
+
+ This API will add a new I/O interface structure to the internal openzap hash of I/O structs.
+ This is needed because NBE I/O structure will NOT be loaded from an openzap module (.so/.dll)
+ but rather just registered on runtime (probably from a static structure in NBE code).
+ This openzap hash is used by zap_api_execute() for example, to find the module that can
+ handle a given API, ie (oz libpri status). This is an example of how an openzap I/O interface
+ can decide to implement just the ->api() member to handle commands and NOTHING else,
+ so I/O interfaces not necessary are hardware-related.
+
+- Add new zap_channel_get_siglink_state(zap_channel, zap_siglink_status_t &status)
+
+- Modify mod_openzap.c to read proto= setting in boost spans, this will determine wich boost sig
+ module will handle the configuration and those channels.
+
+ <boost_spans> <span sigmod="bri|ss7|blah"> <param="proto-specific-setting" value="setting"> </span> </boost_spans>
+
+ Then as first config arg to zap_config_span() the boost proto module name would be included as "sigmod" which will be used
+ by ozmod_sangoma_boost to decide which sig module must handle that span configuration
+
+- Create minimal boost mod interface.
+
+ ozmod_boost_ss7 should load sig boost mods and get interface via dlsym(boost_get_interface) boost_get_interface(boost_iface);
+ The boost interface will have
+ * const char *name // boost sigmod name (brid,ss7d)
+ * set_write_boost_msg_cb(callback) // tell the stack how to send us boost messages
+ * set_sig_status_cb(callback); // tell the stack how to notify us about link status changes
+ * write_boost_msg(struct boost_msg) // send a boost msg to the stack
+ * configure_span(zap_span_t span, "configuration", value, "configuration", value) // configure a given span
+ * get_sig_status(openzap_sigstatus_t status)
+ * start(span) // to start a given openzap span
+ * stop(span) // to stop the stack on a given openzap span
+
+- Migrate current sangoma_brid sig module to openzap
+ * Make sangoma_brid a library
+ * Move from using malloc, threading, locking, logging and I/O to openzap functions. Export the boost sigmod interface and its supporting code.
+
+== State 2 Tasks ==
+
+- Create the I/O NBE interface and supporting functions. It must be possible to poll over the span
+ given that ozmod_sangoma_boost BRI module and others may need to *wait* for data. The poll()
+ function in I/O NBE interface would wait on a pthread condition or Windows event, which would
+ be triggered by some external NBE component registered with Sangoma Board Manager (SMB) for d-chan
+ data, whenever d-chan data arrives, saves the data in a buffer and triggers the condition to wakeup
+ any waiter, then the waiter (sangoma_brid or any other boost client) calls zap_channel_read which calls
+ our own I/O NBE interface read method and retrieves the data from the buffer.
+
+ Dropped alternative design:
+ Another option is to add a new API zap_span_push_incoming_data(span/chan, data); However this changes
+ the model openzap has followed and I don't think fits that well, since now we have 2 different models
+ to support in openzap.
+
+== TODO ==
+
+- how about logging specific modules, like, just ozmod_boost, or just the BRI stack?
+ more work to be done so the BRI module uses zap_log instead of current syslog
+ then work to be done to be able to filter logs from specific openzap code? is it worth it?
+
+- remove FORCE_SEGFAULT from sprid
+
+
+=== Shortcomings ==
+
+- we had to drop smg support in the branch where we work on sangoma prid.
+ After all, most people using sangoma_prid is using freeswitch/openzap and not Sangoma Media Gateway
+ The problem is in freeswitch/openzap mode, sangoma_boost ozmod takes care of span events (POLLPRI)
+ where in SMG and Netborder POLLPRI is done typically by sangoma board manager.
+
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftdm_sangoma_boost.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftdm_sangoma_boost.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftdm_sangoma_boost.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#ifndef FTDM_SANGOMA_BOOST_H
+#define FTDM_SANGOMA_BOOST_H
+#include "sangoma_boost_client.h"
+#include "freetdm.h"
+
+#define MAX_CHANS_PER_TRUNKGROUP 1024
+
+typedef enum {
+ FTDM_SANGOMA_BOOST_RUNNING = (1 << 0),
+ FTDM_SANGOMA_BOOST_RESTARTING = (1 << 1)
+} ftdm_sangoma_boost_flag_t;
+
+typedef struct ftdm_sangoma_boost_data {
+ sangomabc_connection_t mcon;
+ sangomabc_connection_t pcon;
+ int iteration;
+ uint32_t flags;
+ boost_sigmod_interface_t *sigmod;
+ ftdm_queue_t *boost_queue;
+} ftdm_sangoma_boost_data_t;
+
+typedef struct ftdm_sangoma_boost_trunkgroup {
+ ftdm_mutex_t *mutex;
+ ftdm_size_t size; /* Number of b-channels in group */
+ unsigned int last_used_index; /* index of last b-channel used */
+ ftdm_channel_t* ftdmchans[MAX_CHANS_PER_TRUNKGROUP];
+ //DAVIDY need to merge congestion timeouts to this struct
+} ftdm_sangoma_boost_trunkgroup_t;
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="ftmod_sangoma_boost"
+ ProjectGUID="{D021EF2A-460D-4827-A0F7-41FDECF46F1B}"
+ RootNamespace="ftmod_sangoma_boost"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_SANGOMA_BOOST_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="freetdm.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=""$(OutDir)""
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_SANGOMA_BOOST_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="ftmod_sangoma_boost.c"
+ >
+ </File>
+ <File
+ RelativePath="sangoma_boost_client.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="sangoma_boost_client.h"
+ >
+ </File>
+ <File
+ RelativePath="sangoma_boost_interface.h"
+ >
+ </File>
+ <File
+ RelativePath="sigboost.h"
+ >
+ </File>
+ <File
+ RelativePath="ftdm_sangoma_boost.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,2273 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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:
+ *
+ * Moises Silva <moy@sangoma.com>
+ * David Yat Sin <dyatsin@sangoma.com>
+ * Nenad Corbic <ncorbic@sangoma.com>
+ *
+ */
+
+/* NOTE:
+On __WINDOWS__ platform this code works with sigmod ONLY, don't try to make sense of any socket code for win
+I basically ifdef out everything that the compiler complained about
+*/
+
+#include "freetdm.h"
+#include "sangoma_boost_client.h"
+#include "ftdm_sangoma_boost.h"
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+/* Boost signaling modules global hash and its mutex */
+ftdm_mutex_t *g_boost_modules_mutex = NULL;
+ftdm_hash_t *g_boost_modules_hash = NULL;
+
+#define MAX_TRUNK_GROUPS 64
+//DAVIDY need to merge congestion_timeouts with ftdm_sangoma_boost_trunkgroups
+static time_t congestion_timeouts[MAX_TRUNK_GROUPS];
+
+static ftdm_sangoma_boost_trunkgroup_t *g_trunkgroups[MAX_TRUNK_GROUPS];
+
+#define BOOST_QUEUE_SIZE 500
+
+/* get freetdm span and chan depending on the span mode */
+#define BOOST_SPAN(ftdmchan) ((ftdm_sangoma_boost_data_t*)(ftdmchan)->span->signal_data)->sigmod ? ftdmchan->physical_span_id : ftdmchan->physical_span_id-1
+#define BOOST_CHAN(ftdmchan) ((ftdm_sangoma_boost_data_t*)(ftdmchan)->span->signal_data)->sigmod ? ftdmchan->physical_chan_id : ftdmchan->physical_chan_id-1
+
+/**
+ * \brief Strange flag
+ */
+typedef enum {
+ SFLAG_FREE_REQ_ID = (1 << 0),
+ SFLAG_SENT_FINAL_MSG = (1 << 1),
+ SFLAG_SENT_ACK = (1 << 2),
+ SFLAG_RECVD_ACK = (1 << 3),
+ SFLAG_HANGUP = (1 << 4),
+ SFLAG_TERMINATING = (1 << 5)
+} sflag_t;
+
+typedef uint16_t sangoma_boost_request_id_t;
+
+/**
+ * \brief SANGOMA boost request status
+ */
+typedef enum {
+ BST_FREE,
+ BST_WAITING,
+ BST_ACK,
+ BST_READY,
+ BST_FAIL
+} sangoma_boost_request_status_t;
+
+/**
+ * \brief SANGOMA boost request structure
+ */
+typedef struct {
+ sangoma_boost_request_status_t status;
+ sangomabc_short_event_t event;
+ ftdm_span_t *span;
+ ftdm_channel_t *ftdmchan;
+ int hangup_cause;
+ int flags;
+} sangoma_boost_request_t;
+
+//#define MAX_REQ_ID FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN * FTDM_MAX_CHANNELS_PHYSICAL_SPAN
+#define MAX_REQ_ID 6000
+
+static uint16_t SETUP_GRID[FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN+1][FTDM_MAX_CHANNELS_PHYSICAL_SPAN+1] = {{ 0 }};
+
+static sangoma_boost_request_t OUTBOUND_REQUESTS[MAX_REQ_ID+1] = {{ 0 }};
+
+static ftdm_mutex_t *request_mutex = NULL;
+
+static uint8_t req_map[MAX_REQ_ID+1] = { 0 };
+static uint8_t nack_map[MAX_REQ_ID+1] = { 0 };
+
+/**
+ * \brief Releases span and channel from setup grid
+ * \param span Span number
+ * \param chan Channel number
+ * \param func Calling function
+ * \param line Line number on request
+ * \return NULL if not found, channel otherwise
+ */
+static void __release_request_id_span_chan(int span, int chan, const char *func, int line)
+{
+ int id;
+
+ ftdm_mutex_lock(request_mutex);
+ if ((id = SETUP_GRID[span][chan])) {
+ assert(id <= MAX_REQ_ID);
+ req_map[id] = 0;
+ SETUP_GRID[span][chan] = 0;
+ }
+ ftdm_mutex_unlock(request_mutex);
+}
+#define release_request_id_span_chan(s, c) __release_request_id_span_chan(s, c, __FUNCTION__, __LINE__)
+
+/**
+ * \brief Releases request ID
+ * \param func Calling function
+ * \param line Line number on request
+ * \return NULL if not found, channel otherwise
+ */
+static void __release_request_id(sangoma_boost_request_id_t r, const char *func, int line)
+{
+ assert(r <= MAX_REQ_ID);
+ ftdm_mutex_lock(request_mutex);
+ req_map[r] = 0;
+ ftdm_mutex_unlock(request_mutex);
+}
+#define release_request_id(r) __release_request_id(r, __FUNCTION__, __LINE__)
+
+static sangoma_boost_request_id_t last_req = 0;
+
+/**
+ * \brief Gets the first available tank request ID
+ * \param func Calling function
+ * \param line Line number on request
+ * \return 0 on failure, request ID on success
+ */
+static sangoma_boost_request_id_t __next_request_id(const char *func, int line)
+{
+ sangoma_boost_request_id_t r = 0, i = 0;
+ int found=0;
+
+ ftdm_mutex_lock(request_mutex);
+ //r = ++last_req;
+ //while(!r || req_map[r]) {
+
+ for (i=1; i<= MAX_REQ_ID; i++){
+ r = ++last_req;
+
+ if (r >= MAX_REQ_ID) {
+ r = i = last_req = 1;
+ }
+
+ if (req_map[r]) {
+ /* Busy find another */
+ continue;
+
+ }
+
+ req_map[r] = 1;
+ found=1;
+ break;
+
+ }
+
+ ftdm_mutex_unlock(request_mutex);
+
+ if (!found) {
+ return 0;
+ }
+
+ return r;
+}
+#define next_request_id() __next_request_id(__FUNCTION__, __LINE__)
+
+/**
+ * \brief Finds the channel that triggered an event
+ * \param span Span where to search the channel
+ * \param event SANGOMA event
+ * \param force Do not wait for the channel to be available if in use
+ * \return NULL if not found, channel otherwise
+ */
+static ftdm_channel_t *find_ftdmchan(ftdm_span_t *span, sangomabc_short_event_t *event, int force)
+{
+ uint32_t i;
+ ftdm_channel_t *ftdmchan = NULL;
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+ uint32_t targetspan = event->span+1;
+ uint32_t targetchan = event->chan+1;
+ if (sangoma_boost_data->sigmod) {
+ /* span is not strictly needed here since we're supposed to get only events for our span */
+ targetspan = event->span;
+ targetchan = event->chan;
+ }
+
+ for(i = 1; i <= span->chan_count; i++) {
+ if (span->channels[i]->physical_span_id == targetspan && span->channels[i]->physical_chan_id == targetchan) {
+ ftdmchan = span->channels[i];
+ if (force || (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE))) {
+ break;
+ } else {
+ ftdmchan = NULL;
+ ftdm_log(FTDM_LOG_DEBUG, "Channel %d:%d ~ %d:%d is already in use.\n",
+ span->channels[i]->span_id,
+ span->channels[i]->chan_id,
+ span->channels[i]->physical_span_id,
+ span->channels[i]->physical_chan_id
+ );
+ break;
+ }
+ }
+ }
+
+ return ftdmchan;
+}
+
+static int check_congestion(int trunk_group)
+{
+ if (congestion_timeouts[trunk_group]) {
+ time_t now = time(NULL);
+
+ if (now >= congestion_timeouts[trunk_group]) {
+ congestion_timeouts[trunk_group] = 0;
+ } else {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * \brief Requests an sangoma boost channel on a span (outgoing call)
+ * \param span Span where to get a channel
+ * \param chan_id Specific channel to get (0 for any)
+ * \param direction Call direction
+ * \param caller_data Caller information
+ * \param ftdmchan Channel to initialise
+ * \return Success or failure
+ */
+static FIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request)
+{
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+ ftdm_status_t status = FTDM_FAIL;
+ sangoma_boost_request_id_t r;
+ sangomabc_event_t event = {0};
+ /* sanity has to be more than 8 seconds.
+ * In PRI specs, timeout is 4 seconds for remote switch to respond to a SETUP,
+ * and PRI stack will retransmit a second SETUP after the first timeout, so
+ * we should allow for at least 8 seconds.
+ */
+ int boost_request_timeout = 10000;
+ sangoma_boost_request_status_t st;
+ char dnis[128] = "";
+ char *gr = NULL;
+ uint32_t count = 0;
+ int tg=0;
+
+ if (sangoma_boost_data->sigmod) {
+ ftdm_log(FTDM_LOG_CRIT, "This function should not be called when sigmod was configured in boost\n");
+ *ftdmchan = NULL;
+ return FTDM_FAIL;
+ }
+
+ if (ftdm_test_flag(span, FTDM_SPAN_SUSPENDED)) {
+ ftdm_log(FTDM_LOG_CRIT, "SPAN is not online.\n");
+ *ftdmchan = NULL;
+ return FTDM_FAIL;
+ }
+
+ ftdm_set_string(dnis, caller_data->dnis.digits);
+
+ r = next_request_id();
+ if (r == 0) {
+ ftdm_log(FTDM_LOG_CRIT, "All tanks ids are busy.\n");
+ *ftdmchan = NULL;
+ return FTDM_FAIL;
+ }
+ sangomabc_call_init(&event, caller_data->cid_num.digits, dnis, r);
+
+ if ((gr = strchr(dnis, '@'))) {
+ *gr++ = '\0';
+ }
+
+ if (gr && *(gr+1)) {
+ tg = atoi(gr+1);
+ if (tg > 0) {
+ tg--;
+ }
+ }
+ event.trunk_group = tg;
+
+ if (check_congestion(tg)) {
+ ftdm_log(FTDM_LOG_CRIT, "All circuits are busy. Trunk Group=%i (BOOST REQUESTED BACK OFF)\n",tg+1);
+ *ftdmchan = NULL;
+ return FTDM_FAIL;
+ }
+
+ ftdm_span_channel_use_count(span, &count);
+
+ if (count >= span->chan_count) {
+ ftdm_log(FTDM_LOG_CRIT, "All circuits are busy.\n");
+ *ftdmchan = NULL;
+ return FTDM_FAIL;
+ }
+
+ if (gr && *(gr+1)) {
+ switch(*gr) {
+ case 'g':
+ event.hunt_group = SIGBOOST_HUNTGRP_SEQ_ASC;
+ break;
+ case 'G':
+ event.hunt_group = SIGBOOST_HUNTGRP_SEQ_DESC;
+ break;
+ case 'r':
+ event.hunt_group = SIGBOOST_HUNTGRP_RR_ASC;
+ break;
+ case 'R':
+ event.hunt_group = SIGBOOST_HUNTGRP_RR_DESC;
+ break;
+ default:
+ ftdm_log(FTDM_LOG_WARNING, "Failed to determine huntgroup (%s)\n", gr);
+ event.hunt_group = SIGBOOST_HUNTGRP_SEQ_ASC;
+ }
+ }
+
+ ftdm_set_string(event.calling_name, caller_data->cid_name);
+ ftdm_set_string(event.rdnis.digits, caller_data->rdnis.digits);
+ if (strlen(caller_data->rdnis.digits)) {
+ event.rdnis.digits_count = strlen(caller_data->rdnis.digits)+1;
+ event.rdnis.ton = caller_data->rdnis.type;
+ event.rdnis.npi = caller_data->rdnis.plan;
+ }
+
+ event.calling.screening_ind = caller_data->screen;
+ event.calling.presentation_ind = caller_data->pres;
+
+ event.calling.ton = caller_data->cid_num.type;
+ event.calling.npi = caller_data->cid_num.plan;
+
+ event.called.ton = caller_data->dnis.type;
+ event.called.npi = caller_data->dnis.plan;
+
+ OUTBOUND_REQUESTS[r].status = BST_WAITING;
+ OUTBOUND_REQUESTS[r].span = span;
+
+ if (sangomabc_connection_write(&sangoma_boost_data->mcon, &event) <= 0) {
+ ftdm_log(FTDM_LOG_CRIT, "Failed to tx boost event [%s]\n", strerror(errno));
+ status = FTDM_FAIL;
+ if (!sangoma_boost_data->sigmod) {
+ *ftdmchan = NULL;
+ }
+ goto done;
+ }
+
+ while(ftdm_running() && OUTBOUND_REQUESTS[r].status == BST_WAITING) {
+ ftdm_sleep(1);
+ if (--boost_request_timeout <= 0) {
+ status = FTDM_FAIL;
+ if (!sangoma_boost_data->sigmod) {
+ *ftdmchan = NULL;
+ }
+ ftdm_log(FTDM_LOG_CRIT, "s%dc%d: Csid:%d Timed out waiting for boost channel request response, current status: BST_WAITING\n", (*ftdmchan)->physical_span_id, (*ftdmchan)->physical_chan_id, r);
+ goto done;
+ }
+ }
+
+ if (OUTBOUND_REQUESTS[r].status == BST_READY && OUTBOUND_REQUESTS[r].ftdmchan) {
+ *ftdmchan = OUTBOUND_REQUESTS[r].ftdmchan;
+ status = FTDM_SUCCESS;
+ } else {
+ status = FTDM_FAIL;
+ if (!sangoma_boost_data->sigmod) {
+ *ftdmchan = NULL;
+ }
+ }
+
+ done:
+
+ st = OUTBOUND_REQUESTS[r].status;
+ OUTBOUND_REQUESTS[r].status = BST_FREE;
+
+ if (status == FTDM_FAIL) {
+ if (st == BST_FAIL) {
+ caller_data->hangup_cause = OUTBOUND_REQUESTS[r].hangup_cause;
+ } else {
+ caller_data->hangup_cause = FTDM_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
+ }
+ }
+
+ if (st == BST_FAIL) {
+ release_request_id(r);
+ } else if (st != BST_READY) {
+ ftdm_assert_return(r <= MAX_REQ_ID, FTDM_FAIL, "Invalid index\n");
+ nack_map[r] = 1;
+ if (sangoma_boost_data->sigmod) {
+ sangomabc_exec_command(&sangoma_boost_data->mcon,
+ BOOST_SPAN((*ftdmchan)),
+ BOOST_CHAN((*ftdmchan)),
+ r,
+ SIGBOOST_EVENT_CALL_START_NACK,
+ 0, 0);
+ } else {
+ sangomabc_exec_command(&sangoma_boost_data->mcon,
+ 0,
+ 0,
+ r,
+ SIGBOOST_EVENT_CALL_START_NACK,
+ 0, 0);
+ }
+ }
+
+ return status;
+}
+
+/**
+ * \brief Starts an sangoma boost channel (outgoing call)
+ * \param ftdmchan Channel to initiate call on
+ * \return Success
+ */
+static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(sangoma_boost_outgoing_call)
+{
+ char dnis[128] = "";
+ sangoma_boost_request_id_t r;
+ sangomabc_event_t event = {0};
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
+ if (!sangoma_boost_data->sigmod) {
+ return FTDM_SUCCESS;
+ }
+ ftdm_set_string(dnis, ftdmchan->caller_data.dnis.digits);
+
+ r = next_request_id();
+ if (r == 0) {
+ ftdm_log(FTDM_LOG_CRIT, "All boost request ids are busy.\n");
+ return FTDM_FAIL;
+ }
+
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
+
+ sangomabc_call_init(&event, ftdmchan->caller_data.cid_num.digits, dnis, r);
+
+ event.span = (uint8_t)ftdmchan->physical_span_id;
+ event.chan = (uint8_t)ftdmchan->physical_chan_id;
+
+ ftdm_set_string(event.calling_name, ftdmchan->caller_data.cid_name);
+ ftdm_set_string(event.rdnis.digits, ftdmchan->caller_data.rdnis.digits);
+ if (strlen(ftdmchan->caller_data.rdnis.digits)) {
+ event.rdnis.digits_count = strlen(ftdmchan->caller_data.rdnis.digits)+1;
+ event.rdnis.ton = ftdmchan->caller_data.rdnis.type;
+ event.rdnis.npi = ftdmchan->caller_data.rdnis.plan;
+ }
+
+ event.calling.screening_ind = ftdmchan->caller_data.screen;
+ event.calling.presentation_ind = ftdmchan->caller_data.pres;
+
+ event.calling.ton = ftdmchan->caller_data.cid_num.type;
+ event.calling.npi = ftdmchan->caller_data.cid_num.plan;
+
+ event.called.ton = ftdmchan->caller_data.dnis.type;
+ event.called.npi = ftdmchan->caller_data.dnis.plan;
+
+ OUTBOUND_REQUESTS[r].status = BST_WAITING;
+ OUTBOUND_REQUESTS[r].span = ftdmchan->span;
+ OUTBOUND_REQUESTS[r].ftdmchan = ftdmchan;
+
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
+
+ ftdm_log(FTDM_LOG_DEBUG, "Dialing number %s over boost channel with request id %d\n", event.called_number_digits, r);
+ if (sangomabc_connection_write(&sangoma_boost_data->mcon, &event) <= 0) {
+ ftdm_log(FTDM_LOG_CRIT, "Failed to tx boost event [%s]\n", strerror(errno));
+ return FTDM_FAIL;
+ }
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Handler for call start ack no media event
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_progress(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ ftdm_channel_t *ftdmchan;
+
+
+ if ((ftdmchan = find_ftdmchan(span, event, 1))) {
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
+ ftdm_mutex_lock(ftdmchan->mutex);
+ if (!sangoma_boost_data->sigmod && ftdmchan->state == FTDM_CHANNEL_STATE_HOLD) {
+ if ((event->flags & SIGBOOST_PROGRESS_MEDIA)) {
+ ftdmchan->init_state = FTDM_CHANNEL_STATE_PROGRESS_MEDIA;
+ ftdm_log(FTDM_LOG_DEBUG, "Channel init state updated to PROGRESS_MEDIA [Csid:%d]\n", event->call_setup_id);
+ } else if ((event->flags & SIGBOOST_PROGRESS_RING)) {
+ ftdmchan->init_state = FTDM_CHANNEL_STATE_PROGRESS;
+ ftdm_log(FTDM_LOG_DEBUG, "Channel init state updated to PROGRESS [Csid:%d]\n", event->call_setup_id);
+ } else {
+ ftdmchan->init_state = FTDM_CHANNEL_STATE_IDLE;
+ ftdm_log(FTDM_LOG_DEBUG, "Channel init state updated to IDLE [Csid:%d]\n", event->call_setup_id);
+ }
+ } else {
+ if ((event->flags & SIGBOOST_PROGRESS_MEDIA)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+ } else if ((event->flags & SIGBOOST_PROGRESS_RING)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+ } else {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE);
+ }
+ }
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ }
+}
+
+/**
+ * \brief Handler for call start ack event
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_start_ack(sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+
+ ftdm_channel_t *ftdmchan = NULL;
+ uint32_t event_span = event->span+1;
+ uint32_t event_chan = event->chan+1;
+
+ if (nack_map[event->call_setup_id]) {
+ return;
+ }
+
+ if (mcon->sigmod) {
+ event_span = event->span;
+ event_chan = event->chan;
+ }
+
+ OUTBOUND_REQUESTS[event->call_setup_id].event = *event;
+ SETUP_GRID[event->span][event->chan] = event->call_setup_id;
+
+ if (mcon->sigmod) {
+ ftdmchan = OUTBOUND_REQUESTS[event->call_setup_id].ftdmchan;
+ } else {
+ ftdmchan = find_ftdmchan(OUTBOUND_REQUESTS[event->call_setup_id].span, event, 0);
+ }
+
+
+ if (ftdmchan) {
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
+ if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to open FTDM channel [%s]\n", ftdmchan->last_error);
+ } else {
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_INUSE);
+ ftdmchan->sflags = SFLAG_RECVD_ACK;
+
+ if ((event->flags & SIGBOOST_PROGRESS_MEDIA)) {
+ if (sangoma_boost_data->sigmod) {
+ ftdm_log(FTDM_LOG_DEBUG, "Channel state changing to PROGRESS_MEDIA [Csid:%d]\n", event->call_setup_id);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+ } else {
+ ftdmchan->init_state = FTDM_CHANNEL_STATE_PROGRESS_MEDIA;
+ ftdm_log(FTDM_LOG_DEBUG, "Channel init state changed to PROGRESS_MEDIA [Csid:%d]\n", event->call_setup_id);
+ }
+ } else if ((event->flags & SIGBOOST_PROGRESS_RING)) {
+ if (sangoma_boost_data->sigmod) {
+ ftdm_log(FTDM_LOG_DEBUG, "Channel state changing to PROGRESS [Csid:%d]\n", event->call_setup_id);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+ } else {
+ ftdmchan->init_state = FTDM_CHANNEL_STATE_PROGRESS;
+ ftdm_log(FTDM_LOG_DEBUG, "Channel init state changed to PROGRESS [Csid:%d]\n", event->call_setup_id);
+ }
+ } else {
+ if (sangoma_boost_data->sigmod) {
+ /* should we set a state here? */
+ } else {
+ ftdmchan->init_state = FTDM_CHANNEL_STATE_IDLE;
+ ftdm_log(FTDM_LOG_DEBUG, "Channel init state changed to IDLE [Csid:%d]\n", event->call_setup_id);
+ }
+ }
+ if (!sangoma_boost_data->sigmod) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HOLD);
+ ftdm_log(FTDM_LOG_DEBUG, "Assigned chan %d:%d (%d:%d) to CSid=%d\n",
+ ftdmchan->span_id, ftdmchan->chan_id, event_span, event_chan, event->call_setup_id);
+ OUTBOUND_REQUESTS[event->call_setup_id].ftdmchan = ftdmchan;
+ }
+ OUTBOUND_REQUESTS[event->call_setup_id].flags = event->flags;
+ OUTBOUND_REQUESTS[event->call_setup_id].status = BST_READY;
+ return;
+ }
+ }
+
+ if (!ftdmchan) {
+ ftdm_log(FTDM_LOG_CRIT, "START ACK CANT FIND A CHAN %d:%d\n", event->span+1,event->chan+1);
+ } else {
+ /* only reason to be here is failed to open channel when we we're in sigmod */
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+ }
+ ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG);
+ sangomabc_exec_command(mcon,
+ event->span,
+ event->chan,
+ event->call_setup_id,
+ SIGBOOST_EVENT_CALL_STOPPED,
+ FTDM_CAUSE_DESTINATION_OUT_OF_ORDER, 0);
+ OUTBOUND_REQUESTS[event->call_setup_id].status = BST_FAIL;
+ OUTBOUND_REQUESTS[event->call_setup_id].hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER;
+}
+
+/**
+ * \brief Handler for call done event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_done(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ ftdm_channel_t *ftdmchan;
+ int r = 0;
+
+ if ((ftdmchan = find_ftdmchan(span, event, 1))) {
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
+ ftdm_mutex_lock(ftdmchan->mutex);
+
+ if (sangoma_boost_data->sigmod) {
+ /* not really completely done, but if we ever get an incoming call before moving to HANGUP_COMPLETE
+ * handle_incoming_call() will take care of moving the state machine to release the channel */
+ sangomabc_exec_command(&sangoma_boost_data->mcon,
+ BOOST_SPAN(ftdmchan),
+ BOOST_CHAN(ftdmchan),
+ 0,
+ SIGBOOST_EVENT_CALL_RELEASED,
+ 0, 0);
+ }
+
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN || ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP_COMPLETE || ftdm_test_sflag(ftdmchan, SFLAG_TERMINATING)) {
+ goto done;
+ }
+
+ ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, 0, r);
+ if (r) {
+ ftdm_set_sflag(ftdmchan, SFLAG_FREE_REQ_ID);
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ return;
+ }
+ }
+
+ done:
+
+ if (ftdmchan) {
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ }
+
+ if (event->call_setup_id) {
+ release_request_id(event->call_setup_id);
+ } else {
+ release_request_id_span_chan(event->span, event->chan);
+ }
+}
+
+/**
+ * \brief Handler for call start nack event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_start_nack(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ ftdm_channel_t *ftdmchan;
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+
+ if (event->release_cause == SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY) {
+ uint32_t count = 0;
+ int delay = 0;
+ int tg=event->trunk_group;
+
+ ftdm_span_channel_use_count(span, &count);
+
+ delay = (int) (count / 100) * 2;
+
+ if (delay > 10) {
+ delay = 10;
+ } else if (delay < 1) {
+ delay = 1;
+ }
+
+ if (tg < 0 || tg >= MAX_TRUNK_GROUPS) {
+ ftdm_log(FTDM_LOG_CRIT, "Invalid All Ckt Busy trunk group number %i\n", tg);
+ tg=0;
+ }
+
+ congestion_timeouts[tg] = time(NULL) + delay;
+ event->release_cause = 17;
+
+ } else if (event->release_cause == SIGBOOST_CALL_SETUP_CSUPID_DBL_USE) {
+ event->release_cause = 17;
+ }
+
+ if (event->call_setup_id) {
+ if (sangoma_boost_data->sigmod) {
+ ftdmchan = OUTBOUND_REQUESTS[event->call_setup_id].ftdmchan;
+ ftdmchan->call_data = (void*)(intptr_t)event->event_id;
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+ } else {
+ sangomabc_exec_command(mcon,
+ 0,
+ 0,
+ event->call_setup_id,
+ SIGBOOST_EVENT_CALL_START_NACK_ACK,
+ 0, 0);
+ OUTBOUND_REQUESTS[event->call_setup_id].event = *event;
+ OUTBOUND_REQUESTS[event->call_setup_id].status = BST_FAIL;
+ OUTBOUND_REQUESTS[event->call_setup_id].hangup_cause = event->release_cause;
+ ftdm_log(FTDM_LOG_DEBUG, "setting outbound request status %d to BST_FAIL\n", event->call_setup_id);
+ }
+ return;
+ } else {
+ if ((ftdmchan = find_ftdmchan(span, event, 1))) {
+ int r = 0;
+
+ /* if there is no call setup id this should not be an outbound channel for sure */
+ ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND), "Yay, outbound flag should not be set here!\n");
+
+ ftdmchan->call_data = (void*)(intptr_t)event->event_id;
+ ftdm_mutex_lock(ftdmchan->mutex);
+ ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, 0, r);
+ if (r == FTDM_STATE_CHANGE_SUCCESS) {
+ ftdmchan->caller_data.hangup_cause = event->release_cause;
+ }
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ if (r) {
+ return;
+ }
+ }
+ }
+
+ if (ftdmchan) {
+ ftdm_set_sflag_locked(ftdmchan, SFLAG_SENT_FINAL_MSG);
+ }
+
+ /* nobody else will do it so we have to do it ourselves */
+ sangomabc_exec_command(mcon,
+ event->span,
+ event->chan,
+ 0,
+ SIGBOOST_EVENT_CALL_START_NACK_ACK,
+ 0, 0);
+}
+
+static void handle_call_released(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ ftdm_channel_t *ftdmchan;
+
+ if ((ftdmchan = find_ftdmchan(span, event, 1))) {
+ ftdm_log(FTDM_LOG_DEBUG, "Releasing completely chan s%dc%d\n", event->span, event->chan);
+ ftdm_channel_done(ftdmchan);
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "Odd, We could not find chan: s%dc%d to release the call completely!!\n", event->span, event->chan);
+ }
+}
+
+/**
+ * \brief Handler for call stop event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_stop(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ ftdm_channel_t *ftdmchan;
+
+ if ((ftdmchan = find_ftdmchan(span, event, 1))) {
+ int r = 0;
+
+ ftdm_mutex_lock(ftdmchan->mutex);
+
+ if (ftdm_test_sflag(ftdmchan, SFLAG_HANGUP)) {
+ /* racing condition where both sides initiated a hangup
+ * Do not change current state as channel is already clearing
+ * itself through local initiated hangup */
+
+ sangomabc_exec_command(mcon,
+ BOOST_SPAN(ftdmchan),
+ BOOST_CHAN(ftdmchan),
+ 0,
+ SIGBOOST_EVENT_CALL_STOPPED_ACK,
+ 0, 0);
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ return;
+ } else if (ftdmchan->state == FTDM_CHANNEL_STATE_HOLD) {
+ ftdmchan->init_state = FTDM_CHANNEL_STATE_TERMINATING;
+ ftdm_log(FTDM_LOG_DEBUG, "Channel init state updated to TERMINATING [Csid:%d]\n", event->call_setup_id);
+ OUTBOUND_REQUESTS[event->call_setup_id].hangup_cause = event->release_cause;
+ ftdmchan->caller_data.hangup_cause = event->release_cause;
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ return;
+ } else {
+ ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, 0, r);
+ }
+
+ if (r == FTDM_STATE_CHANGE_SUCCESS) {
+ ftdmchan->caller_data.hangup_cause = event->release_cause;
+ }
+
+ if (r) {
+ ftdm_set_sflag(ftdmchan, SFLAG_FREE_REQ_ID);
+ }
+
+ ftdm_mutex_unlock(ftdmchan->mutex);
+
+ if (r) {
+ return;
+ }
+ } else { /* we have to do it ourselves.... */
+ ftdm_log(FTDM_LOG_ERROR, "Odd, We could not find chan: s%dc%d\n", event->span, event->chan);
+ release_request_id_span_chan(event->span, event->chan);
+ }
+}
+
+/**
+ * \brief Handler for call answer event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_answer(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ ftdm_channel_t *ftdmchan;
+
+ if ((ftdmchan = find_ftdmchan(span, event, 1))) {
+ ftdm_mutex_lock(ftdmchan->mutex);
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_HOLD) {
+ ftdmchan->init_state = FTDM_CHANNEL_STATE_UP;
+ } else {
+ int r = 0;
+ ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_UP, 0, r);
+ }
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ } else {
+ ftdm_log(FTDM_LOG_CRIT, "ANSWER CANT FIND A CHAN %d:%d\n", event->span+1,event->chan+1);
+ sangomabc_exec_command(mcon,
+ event->span,
+ event->chan,
+ event->call_setup_id,
+ SIGBOOST_EVENT_CALL_STOPPED,
+ FTDM_CAUSE_DESTINATION_OUT_OF_ORDER, 0);
+ }
+}
+
+static __inline__ void advance_chan_states(ftdm_channel_t *ftdmchan);
+
+/**
+ * \brief Handler for call start event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_event_t *event)
+{
+ ftdm_channel_t *ftdmchan;
+
+ if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 0))) {
+ if ((ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 1))) {
+ int r;
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_UP) {
+ ftdm_log(FTDM_LOG_CRIT, "ZCHAN STATE UP -> Changed to TERMINATING %d:%d\n", event->span+1,event->chan+1);
+ ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, 0, r);
+ } else if (ftdm_test_sflag(ftdmchan, SFLAG_HANGUP)) {
+ ftdm_log(FTDM_LOG_CRIT, "ZCHAN STATE HANGUP -> Changed to HANGUP COMPLETE %d:%d\n", event->span+1,event->chan+1);
+ ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, 0, r);
+ } else {
+ ftdm_log(FTDM_LOG_CRIT, "ZCHAN STATE INVALID %s on IN CALL %d:%d\n", ftdm_channel_state2str(ftdmchan->state),event->span+1,event->chan+1);
+
+ }
+ ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG);
+ ftdmchan=NULL;
+ }
+ ftdm_log(FTDM_LOG_CRIT, "START CANT FIND CHAN %d:%d\n", event->span+1,event->chan+1);
+ goto error;
+ }
+
+ if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_CRIT, "START CANT OPEN CHAN %d:%d\n", event->span+1,event->chan+1);
+ goto error;
+ }
+
+ ftdm_log(FTDM_LOG_DEBUG, "Got call start from s%dc%d mapped to freetdm logical s%dc%d, physical s%dc%d\n",
+ event->span, event->chan,
+ ftdmchan->span_id, ftdmchan->chan_id,
+ ftdmchan->physical_span_id, ftdmchan->physical_chan_id);
+
+ ftdmchan->sflags = 0;
+ ftdm_set_string(ftdmchan->caller_data.cid_num.digits, (char *)event->calling.digits);
+ ftdm_set_string(ftdmchan->caller_data.cid_name, (char *)event->calling.digits);
+ ftdm_set_string(ftdmchan->caller_data.ani.digits, (char *)event->calling.digits);
+ ftdm_set_string(ftdmchan->caller_data.dnis.digits, (char *)event->called.digits);
+ ftdm_set_string(ftdmchan->caller_data.rdnis.digits, (char *)event->rdnis.digits);
+
+ if (strlen(event->calling_name)) {
+ ftdm_set_string(ftdmchan->caller_data.cid_name, (char *)event->calling_name);
+ }
+
+ ftdmchan->caller_data.cid_num.plan = event->calling.npi;
+ ftdmchan->caller_data.cid_num.type = event->calling.ton;
+
+ ftdmchan->caller_data.ani.plan = event->calling.npi;
+ ftdmchan->caller_data.ani.type = event->calling.ton;
+
+ ftdmchan->caller_data.dnis.plan = event->called.npi;
+ ftdmchan->caller_data.dnis.type = event->called.ton;
+
+ ftdmchan->caller_data.rdnis.plan = event->rdnis.npi;
+ ftdmchan->caller_data.rdnis.type = event->rdnis.ton;
+
+ ftdmchan->caller_data.screen = event->calling.screening_ind;
+ ftdmchan->caller_data.pres = event->calling.presentation_ind;
+
+ if (event->custom_data_size) {
+ char* p = NULL;
+
+ p = strstr((char*)event->custom_data,"PRI001-ANI2-");
+ if (p!=NULL) {
+ int ani2 = 0;
+ sscanf(p, "PRI001-ANI2-%d", &ani2);
+ snprintf(ftdmchan->caller_data.aniII, 5, "%.2d", ani2);
+ }
+ }
+
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
+ return;
+
+ error:
+ sangomabc_exec_command(mcon,
+ event->span,
+ event->chan,
+ 0,
+ SIGBOOST_EVENT_CALL_START_NACK,
+ 0, 0);
+
+}
+
+static void handle_call_loop_start(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ ftdm_status_t res = FTDM_FAIL;
+ ftdm_channel_t *ftdmchan;
+
+ if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 0))) {
+ ftdm_log(FTDM_LOG_CRIT, "CANNOT START LOOP, CHAN NOT AVAILABLE %d:%d\n", event->span+1,event->chan+1);
+ return;
+ }
+
+ if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_CRIT, "CANNOT START LOOP, CANT OPEN CHAN %d:%d\n", event->span+1,event->chan+1);
+ return;
+ }
+
+ ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_IN_LOOP, 0, res);
+ if (res != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_CRIT, "yay, could not set the state of the channel to IN_LOOP, loop will fail\n");
+ ftdm_channel_done(ftdmchan);
+ return;
+ }
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_LOOP, NULL);
+}
+
+static void handle_call_loop_stop(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ ftdm_channel_t *ftdmchan;
+ ftdm_status_t res = FTDM_FAIL;
+ if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 1))) {
+ ftdm_log(FTDM_LOG_CRIT, "CANNOT STOP LOOP, INVALID CHAN REQUESTED %d:%d\n", event->span+1,event->chan+1);
+ return;
+ }
+ if (ftdmchan->state != FTDM_CHANNEL_STATE_IN_LOOP) {
+ ftdm_log(FTDM_LOG_ERROR, "Got stop loop request in a channel that is not in loop, ignoring ...\n");
+ return;
+ }
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_LOOP, NULL);
+ /* even when we did not sent a msg we set this flag to avoid sending call stop in the DOWN state handler */
+ ftdm_set_flag(ftdmchan, SFLAG_SENT_FINAL_MSG);
+ ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_DOWN, 0, res);
+}
+
+/**
+ * \brief Handler for heartbeat event
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_heartbeat(sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ int err;
+
+ err = sangomabc_connection_writep(mcon, (sangomabc_event_t*)event);
+
+ if (err <= 0) {
+ ftdm_log(FTDM_LOG_CRIT, "Failed to tx on boost connection [%s]: %s\n", strerror(errno));
+ }
+ return;
+}
+
+/**
+ * \brief Handler for restart ack event
+ * \param mcon sangoma boost connection
+ * \param span Span where event was fired
+ * \param event Event to handle
+ */
+static void handle_restart_ack(sangomabc_connection_t *mcon, ftdm_span_t *span, sangomabc_short_event_t *event)
+{
+ ftdm_log(FTDM_LOG_DEBUG, "RECV RESTART ACK\n");
+}
+
+/**
+ * \brief Handler for restart event
+ * \param mcon sangoma boost connection
+ * \param span Span where event was fired
+ * \param event Event to handle
+ */
+static void handle_restart(sangomabc_connection_t *mcon, ftdm_span_t *span, sangomabc_short_event_t *event)
+{
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+
+ mcon->rxseq_reset = 0;
+ ftdm_set_flag((&sangoma_boost_data->mcon), MSU_FLAG_DOWN);
+ ftdm_set_flag_locked(span, FTDM_SPAN_SUSPENDED);
+ ftdm_set_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RESTARTING);
+
+}
+
+/**
+ * \brief Handler for incoming digit event
+ * \param mcon sangoma boost connection
+ * \param span Span where event was fired
+ * \param event Event to handle
+ */
+static void handle_incoming_digit(sangomabc_connection_t *mcon, ftdm_span_t *span, sangomabc_event_t *event)
+{
+ ftdm_channel_t *ftdmchan = NULL;
+ char digits[MAX_DIALED_DIGITS + 2] = "";
+
+ if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t *)event, 1))) {
+ ftdm_log(FTDM_LOG_ERROR, "Invalid channel\n");
+ return;
+ }
+
+ if (event->called_number_digits_count == 0) {
+ ftdm_log(FTDM_LOG_WARNING, "Error Incoming digit with len %s %d [w%dg%d]\n",
+ event->called_number_digits,
+ event->called_number_digits_count,
+ event->span+1, event->chan+1);
+ return;
+ }
+
+ ftdm_log(FTDM_LOG_WARNING, "Incoming digit with len %s %d [w%dg%d]\n",
+ event->called_number_digits,
+ event->called_number_digits_count,
+ event->span+1, event->chan+1);
+
+ memcpy(digits, event->called_number_digits, event->called_number_digits_count);
+ ftdm_channel_queue_dtmf(ftdmchan, digits);
+
+ return;
+}
+
+
+/**
+ * \brief Checks if span has state changes pending and processes
+ * \param span Span where event was fired
+ * \param event Event to handle
+ * \return The locked FTDM channel associated to the event if any, NULL otherwise
+ */
+static ftdm_channel_t* event_process_states(ftdm_span_t *span, sangomabc_short_event_t *event)
+{
+ ftdm_channel_t *ftdmchan = NULL;
+
+ switch (event->event_id) {
+ case SIGBOOST_EVENT_CALL_START_NACK:
+ case SIGBOOST_EVENT_CALL_START_NACK_ACK:
+ if (event->call_setup_id) {
+ return NULL;
+ }
+ //if event->span and event->chan is valid, fall-through
+ case SIGBOOST_EVENT_CALL_START:
+ case SIGBOOST_EVENT_CALL_START_ACK:
+ case SIGBOOST_EVENT_CALL_STOPPED:
+ case SIGBOOST_EVENT_CALL_PROGRESS:
+ case SIGBOOST_EVENT_CALL_ANSWERED:
+ case SIGBOOST_EVENT_CALL_STOPPED_ACK:
+ case SIGBOOST_EVENT_DIGIT_IN:
+ case SIGBOOST_EVENT_INSERT_CHECK_LOOP:
+ case SIGBOOST_EVENT_REMOVE_CHECK_LOOP:
+ case SIGBOOST_EVENT_CALL_RELEASED:
+ if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 1))) {
+ ftdm_log(FTDM_LOG_DEBUG, "PROCESS STATES CANT FIND CHAN %d:%d\n", event->span+1,event->chan+1);
+ return NULL;
+ }
+ break;
+ case SIGBOOST_EVENT_HEARTBEAT:
+ case SIGBOOST_EVENT_SYSTEM_RESTART_ACK:
+ case SIGBOOST_EVENT_SYSTEM_RESTART:
+ case SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE:
+ return NULL;
+ default:
+ ftdm_log(FTDM_LOG_CRIT, "Unhandled event id:%d\n", event->event_id);
+ return NULL;
+ }
+
+ ftdm_mutex_lock(ftdmchan->mutex);
+ advance_chan_states(ftdmchan);
+ return ftdmchan;
+}
+
+/**
+ * \brief Handler for sangoma boost event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static int parse_sangoma_event(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ ftdm_channel_t* ftdmchan = NULL;
+
+ if (!ftdm_running()) {
+ ftdm_log(FTDM_LOG_WARNING, "System is shutting down.\n");
+ return -1;
+ }
+
+ ftdm_assert_return(event->call_setup_id <= MAX_REQ_ID, -1, "Unexpected call setup id\n");
+
+ /* process all pending state changes for that channel before
+ * processing the new boost event */
+ ftdmchan = event_process_states(span, event);
+
+ switch(event->event_id) {
+ case SIGBOOST_EVENT_CALL_START:
+ handle_call_start(span, mcon, (sangomabc_event_t*)event);
+ break;
+ case SIGBOOST_EVENT_CALL_STOPPED:
+ handle_call_stop(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_RELEASED:
+ handle_call_released(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_START_ACK:
+ handle_call_start_ack(mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_PROGRESS:
+ handle_call_progress(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_START_NACK:
+ handle_call_start_nack(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_ANSWERED:
+ handle_call_answer(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_HEARTBEAT:
+ handle_heartbeat(mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_STOPPED_ACK:
+ handle_call_done(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_START_NACK_ACK:
+ handle_call_done(span, mcon, event);
+ nack_map[event->call_setup_id] = 0;
+ break;
+ case SIGBOOST_EVENT_INSERT_CHECK_LOOP:
+ handle_call_loop_start(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_REMOVE_CHECK_LOOP:
+ handle_call_loop_stop(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_SYSTEM_RESTART_ACK:
+ handle_restart_ack(mcon, span, event);
+ break;
+ case SIGBOOST_EVENT_SYSTEM_RESTART:
+ handle_restart(mcon, span, event);
+ break;
+ case SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE:
+ //handle_gap_abate(event);
+ break;
+ case SIGBOOST_EVENT_DIGIT_IN:
+ handle_incoming_digit(mcon, span, (sangomabc_event_t*)event);
+ break;
+ default:
+ ftdm_log(FTDM_LOG_WARNING, "No handler implemented for [%s]\n", sangomabc_event_id_name(event->event_id));
+ break;
+ }
+
+ if(ftdmchan != NULL) {
+ advance_chan_states(ftdmchan);
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ }
+
+ return 0;
+
+}
+
+/**
+ * \brief Handler for channel state change
+ * \param ftdmchan Channel to handle
+ */
+static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
+{
+
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
+ sangomabc_connection_t *mcon = &sangoma_boost_data->mcon;
+ ftdm_sigmsg_t sig;
+ ftdm_status_t status;
+
+ ftdm_log(FTDM_LOG_DEBUG, "%d:%d PROCESSING STATE [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = ftdmchan->chan_id;
+ sig.span_id = ftdmchan->span_id;
+ sig.channel = ftdmchan;
+
+ switch (ftdmchan->state) {
+ case FTDM_CHANNEL_STATE_DOWN:
+ {
+ int call_stopped_ack_sent = 0;
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
+
+ if (ftdm_test_sflag(ftdmchan, SFLAG_FREE_REQ_ID)) {
+ release_request_id_span_chan(ftdmchan->physical_span_id-1, ftdmchan->physical_chan_id-1);
+ }
+
+ if (!ftdm_test_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG)) {
+ ftdm_set_sflag_locked(ftdmchan, SFLAG_SENT_FINAL_MSG);
+
+ if (ftdmchan->call_data && ((uint32_t)(intptr_t)ftdmchan->call_data == SIGBOOST_EVENT_CALL_START_NACK)) {
+ sangomabc_exec_command(mcon,
+ BOOST_SPAN(ftdmchan),
+ BOOST_CHAN(ftdmchan),
+ 0,
+ SIGBOOST_EVENT_CALL_START_NACK_ACK,
+ 0, 0);
+
+ } else {
+ /* we got a call stop msg, time to reply with call stopped ack */
+ sangomabc_exec_command(mcon,
+ BOOST_SPAN(ftdmchan),
+ BOOST_CHAN(ftdmchan),
+ 0,
+ SIGBOOST_EVENT_CALL_STOPPED_ACK,
+ 0, 0);
+ call_stopped_ack_sent = 1;
+ }
+ }
+ ftdmchan->sflags = 0;
+ ftdmchan->call_data = NULL;
+ if (sangoma_boost_data->sigmod && call_stopped_ack_sent) {
+ /* we dont want to call ftdm_channel_done just yet until call released is received */
+ ftdm_log(FTDM_LOG_DEBUG, "Waiting for call release confirmation before declaring chan %d:%d as available \n",
+ ftdmchan->span_id, ftdmchan->chan_id);
+ } else {
+ ftdm_channel_done(ftdmchan);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+ {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ sig.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
+ if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ } else {
+ if (!ftdm_test_sflag(ftdmchan, SFLAG_SENT_ACK)) {
+ ftdm_set_sflag(ftdmchan, SFLAG_SENT_ACK);
+ sangomabc_exec_command(mcon,
+ BOOST_SPAN(ftdmchan),
+ BOOST_CHAN(ftdmchan),
+ 0,
+ SIGBOOST_EVENT_CALL_START_ACK,
+ 0, SIGBOOST_PROGRESS_MEDIA);
+ }
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_PROGRESS:
+ {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ sig.event_id = FTDM_SIGEVENT_PROGRESS;
+ if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ } else {
+ if (!ftdm_test_sflag(ftdmchan, SFLAG_SENT_ACK)) {
+ ftdm_set_sflag(ftdmchan, SFLAG_SENT_ACK);
+ sangomabc_exec_command(mcon,
+ BOOST_SPAN(ftdmchan),
+ BOOST_CHAN(ftdmchan),
+ 0,
+ SIGBOOST_EVENT_CALL_START_ACK,
+ 0, SIGBOOST_PROGRESS_RING);
+ }
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_IDLE:
+ case FTDM_CHANNEL_STATE_HOLD:
+ {
+ /* twiddle */
+ }
+ break;
+ case FTDM_CHANNEL_STATE_RING:
+ {
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ sig.event_id = FTDM_SIGEVENT_START;
+ if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_RESTART:
+ {
+ sig.event_id = FTDM_SIGEVENT_RESTART;
+ status = ftdm_span_send_signal(ftdmchan->span, &sig);
+ ftdm_set_sflag_locked(ftdmchan, SFLAG_SENT_FINAL_MSG);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ }
+ break;
+ case FTDM_CHANNEL_STATE_UP:
+ {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ sig.event_id = FTDM_SIGEVENT_UP;
+ if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ } else {
+ if (!(ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MEDIA))) {
+ sangomabc_exec_command(mcon,
+ BOOST_SPAN(ftdmchan),
+ BOOST_CHAN(ftdmchan),
+ 0,
+ SIGBOOST_EVENT_CALL_START_ACK,
+ 0, 0);
+ }
+
+ sangomabc_exec_command(mcon,
+ BOOST_SPAN(ftdmchan),
+ BOOST_CHAN(ftdmchan),
+ 0,
+ SIGBOOST_EVENT_CALL_ANSWERED,
+ 0, 0);
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_DIALING:
+ {
+ }
+ break;
+ case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
+ {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ }
+ break;
+ case FTDM_CHANNEL_STATE_HANGUP:
+ {
+ ftdm_set_sflag_locked(ftdmchan, SFLAG_HANGUP);
+
+ if (ftdm_test_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG) || ftdm_test_sflag(ftdmchan, SFLAG_TERMINATING)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
+ } else {
+ ftdm_set_sflag_locked(ftdmchan, SFLAG_SENT_FINAL_MSG);
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_ANSWERED) ||
+ ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS) ||
+ ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MEDIA) ||
+ ftdm_test_sflag(ftdmchan, SFLAG_RECVD_ACK)) {
+ sangomabc_exec_command(mcon,
+ BOOST_SPAN(ftdmchan),
+ BOOST_CHAN(ftdmchan),
+ 0,
+ SIGBOOST_EVENT_CALL_STOPPED,
+ ftdmchan->caller_data.hangup_cause, 0);
+ } else {
+ sangomabc_exec_command(mcon,
+ BOOST_SPAN(ftdmchan),
+ BOOST_CHAN(ftdmchan),
+ 0,
+ SIGBOOST_EVENT_CALL_START_NACK,
+ ftdmchan->caller_data.hangup_cause, 0);
+ }
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_TERMINATING:
+ {
+ ftdm_set_sflag_locked(ftdmchan, SFLAG_TERMINATING);
+ sig.event_id = FTDM_SIGEVENT_STOP;
+ status = ftdm_span_send_signal(ftdmchan->span, &sig);
+ }
+ break;
+ case FTDM_CHANNEL_STATE_IN_LOOP:
+ {
+ /* nothing to do, we sent the FTDM_COMMAND_ENABLE_LOOP command in handle_call_loop_start() right away */
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static __inline__ void advance_chan_states(ftdm_channel_t *ftdmchan)
+{
+ while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+ state_advance(ftdmchan);
+ ftdm_channel_complete_state(ftdmchan);
+ }
+}
+
+/**
+ * \brief Initialises outgoing requests array
+ */
+static __inline__ void init_outgoing_array(void)
+{
+ memset(&OUTBOUND_REQUESTS, 0, sizeof(OUTBOUND_REQUESTS));
+
+}
+
+/**
+ * \brief Checks current state on a span
+ * \param span Span to check status on
+ */
+static __inline__ void check_state(ftdm_span_t *span)
+{
+ ftdm_channel_t *ftdmchan = NULL;
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+ int susp = ftdm_test_flag(span, FTDM_SPAN_SUSPENDED);
+
+ if (susp && ftdm_check_state_all(span, FTDM_CHANNEL_STATE_DOWN)) {
+ susp = 0;
+ }
+
+ if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE) || susp) {
+ uint32_t j;
+ ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
+ if (susp) {
+ for (j = 0; j <= span->chan_count; j++) {
+ ftdm_mutex_lock(span->channels[j]->mutex);
+ ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
+ ftdm_channel_set_state(span->channels[j], FTDM_CHANNEL_STATE_RESTART, 0);
+ state_advance(span->channels[j]);
+ ftdm_channel_complete_state(span->channels[j]);
+ ftdm_mutex_unlock(span->channels[j]->mutex);
+ }
+ } else {
+ while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans))) {
+ /* it can happen that someone else processed the chan states
+ * but without taking the chan out of the queue, so check th
+ * flag before advancing the state */
+ ftdm_mutex_lock(ftdmchan->mutex);
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+ state_advance(ftdmchan);
+ ftdm_channel_complete_state(ftdmchan);
+ }
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ }
+ }
+ }
+
+ if (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RESTARTING)) {
+ if (ftdm_check_state_all(span, FTDM_CHANNEL_STATE_DOWN)) {
+ sangomabc_exec_command(&sangoma_boost_data->mcon,
+ 0,
+ 0,
+ -1,
+ SIGBOOST_EVENT_SYSTEM_RESTART_ACK,
+ 0, 0);
+ ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RESTARTING);
+ ftdm_clear_flag_locked(span, FTDM_SPAN_SUSPENDED);
+ ftdm_clear_flag((&sangoma_boost_data->mcon), MSU_FLAG_DOWN);
+ init_outgoing_array();
+ }
+ }
+}
+
+
+/**
+ * \brief Checks for events on a span
+ * \param span Span to check for events
+ */
+static __inline__ ftdm_status_t check_events(ftdm_span_t *span, int ms_timeout)
+{
+ ftdm_status_t status;
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+
+ status = ftdm_span_poll_event(span, ms_timeout);
+
+ switch(status) {
+ case FTDM_SUCCESS:
+ {
+ ftdm_event_t *event;
+ while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
+ switch (event->enum_id) {
+ case FTDM_OOB_ALARM_TRAP:
+ if (sangoma_boost_data->sigmod) {
+ sangoma_boost_data->sigmod->on_hw_link_status_change(event->channel, FTDM_HW_LINK_DISCONNECTED);
+ }
+ break;
+ case FTDM_OOB_ALARM_CLEAR:
+ if (sangoma_boost_data->sigmod) {
+ sangoma_boost_data->sigmod->on_hw_link_status_change(event->channel, FTDM_HW_LINK_CONNECTED);
+ }
+ break;
+ }
+ }
+ }
+ break;
+ case FTDM_FAIL:
+ {
+ if (!ftdm_running()) {
+ break;
+ }
+ ftdm_log(FTDM_LOG_ERROR, "Boost Check Event Failure Failure: %s\n", span->last_error);
+ return FTDM_FAIL;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Main thread function for sangoma boost span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *ftdm_sangoma_events_run(ftdm_thread_t *me, void *obj)
+{
+ ftdm_span_t *span = (ftdm_span_t *) obj;
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+ unsigned errs = 0;
+
+ while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING) && ftdm_running()) {
+ if (check_events(span,100) != FTDM_SUCCESS) {
+ if (errs++ > 50) {
+ ftdm_log(FTDM_LOG_ERROR, "Too many event errors, quitting sangoma events thread\n");
+ return NULL;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static ftdm_status_t ftdm_boost_connection_open(ftdm_span_t *span)
+{
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+ if (sangoma_boost_data->sigmod) {
+ if (sangoma_boost_data->sigmod->start_span(span) != FTDM_SUCCESS) {
+ return FTDM_FAIL;
+ }
+ ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RESTARTING);
+ ftdm_clear_flag_locked(span, FTDM_SPAN_SUSPENDED);
+ ftdm_clear_flag((&sangoma_boost_data->mcon), MSU_FLAG_DOWN);
+ }
+
+ sangoma_boost_data->pcon = sangoma_boost_data->mcon;
+
+ /* when sigmod is present, all arguments: local_ip etc, are ignored by sangomabc_connection_open */
+ if (sangomabc_connection_open(&sangoma_boost_data->mcon,
+ sangoma_boost_data->mcon.cfg.local_ip,
+ sangoma_boost_data->mcon.cfg.local_port,
+ sangoma_boost_data->mcon.cfg.remote_ip,
+ sangoma_boost_data->mcon.cfg.remote_port) < 0) {
+ ftdm_log(FTDM_LOG_ERROR, "Error: Opening MCON Socket [%d] %s\n", sangoma_boost_data->mcon.socket, strerror(errno));
+ return FTDM_FAIL;
+ }
+
+ if (sangomabc_connection_open(&sangoma_boost_data->pcon,
+ sangoma_boost_data->pcon.cfg.local_ip,
+ ++sangoma_boost_data->pcon.cfg.local_port,
+ sangoma_boost_data->pcon.cfg.remote_ip,
+ ++sangoma_boost_data->pcon.cfg.remote_port) < 0) {
+ ftdm_log(FTDM_LOG_ERROR, "Error: Opening PCON Socket [%d] %s\n", sangoma_boost_data->pcon.socket, strerror(errno));
+ return FTDM_FAIL;
+ }
+
+ /* try to create the boost sockets interrupt objects */
+ if (ftdm_interrupt_create(&sangoma_boost_data->pcon.sock_interrupt, sangoma_boost_data->pcon.socket) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Span %s could not create its boost msock interrupt!\n", span->name);
+ return FTDM_FAIL;
+ }
+
+ if (ftdm_interrupt_create(&sangoma_boost_data->mcon.sock_interrupt, sangoma_boost_data->mcon.socket) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Span %s could not create its boost psock interrupt!\n", span->name);
+ return FTDM_FAIL;
+ }
+
+ return FTDM_SUCCESS;
+}
+
+/*!
+ \brief wait for a boost event
+ \return -1 on error, 0 on timeout, 1 when there are events
+ */
+static int ftdm_boost_wait_event(ftdm_span_t *span)
+{
+ ftdm_status_t res;
+ ftdm_interrupt_t *ints[3];
+ int numints;
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+
+ ftdm_queue_get_interrupt(span->pendingchans, &ints[0]);
+ numints = 1;
+ /* if in queue mode wait for both the pendingchans queue and the boost msg queue */
+ if (sangoma_boost_data->sigmod) {
+ ftdm_queue_get_interrupt(sangoma_boost_data->boost_queue, &ints[1]);
+ numints = 2;
+ }
+#ifndef __WINDOWS__
+ else {
+ /* socket mode ... */
+ ints[1] = sangoma_boost_data->mcon.sock_interrupt;
+ ints[2] = sangoma_boost_data->pcon.sock_interrupt;
+ numints = 3;
+ sangoma_boost_data->iteration = 0;
+ }
+#endif
+ res = ftdm_interrupt_multiple_wait(ints, numints, -1);
+ if (FTDM_SUCCESS != res) {
+ ftdm_log(FTDM_LOG_CRIT, "Unexpected return value from interrupt waiting: %d\n", res);
+ return -1;
+ }
+ return 0;
+}
+
+
+static sangomabc_event_t *ftdm_boost_read_event(ftdm_span_t *span)
+{
+ sangomabc_event_t *event = NULL;
+ sangomabc_connection_t *mcon, *pcon;
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+
+ mcon = &sangoma_boost_data->mcon;
+ pcon = &sangoma_boost_data->pcon;
+
+ event = sangomabc_connection_readp(pcon, sangoma_boost_data->iteration);
+
+ /* if there is no event and this is not a sigmod-driven span it's time to try the other connection for events */
+ if (!event && !sangoma_boost_data->sigmod) {
+ event = sangomabc_connection_read(mcon, sangoma_boost_data->iteration);
+ }
+
+ return event;
+}
+
+/**
+ * \brief Main thread function for sangoma boost span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *ftdm_sangoma_boost_run(ftdm_thread_t *me, void *obj)
+{
+ ftdm_span_t *span = (ftdm_span_t *) obj;
+ sangomabc_connection_t *mcon, *pcon;
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+
+ mcon = &sangoma_boost_data->mcon;
+ pcon = &sangoma_boost_data->pcon;
+
+ /* sigmod overrides socket functionality if not null */
+ if (sangoma_boost_data->sigmod) {
+ mcon->span = span;
+ pcon->span = span;
+ /* everything could be retrieved through span, but let's use shortcuts */
+ mcon->sigmod = sangoma_boost_data->sigmod;
+ pcon->sigmod = sangoma_boost_data->sigmod;
+ mcon->boost_queue = sangoma_boost_data->boost_queue;
+ pcon->boost_queue = sangoma_boost_data->boost_queue;
+ }
+
+ if (ftdm_boost_connection_open(span) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "ftdm_boost_connection_open failed\n");
+ goto end;
+ }
+
+ init_outgoing_array();
+ if (!sangoma_boost_data->sigmod) {
+ sangomabc_exec_commandp(pcon,
+ 0,
+ 0,
+ -1,
+ SIGBOOST_EVENT_SYSTEM_RESTART,
+ 0);
+ ftdm_set_flag(mcon, MSU_FLAG_DOWN);
+ }
+
+ while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING)) {
+ sangomabc_event_t *event = NULL;
+
+ if (!ftdm_running()) {
+ if (!sangoma_boost_data->sigmod) {
+ sangomabc_exec_commandp(pcon,
+ 0,
+ 0,
+ -1,
+ SIGBOOST_EVENT_SYSTEM_RESTART,
+ 0);
+ ftdm_set_flag(mcon, MSU_FLAG_DOWN);
+ }
+ ftdm_log(FTDM_LOG_DEBUG, "ftdm is no longer running\n");
+ break;
+ }
+
+ if (ftdm_boost_wait_event(span) < 0) {
+ ftdm_log(FTDM_LOG_ERROR, "ftdm_boost_wait_event failed\n");
+ goto error;
+ }
+
+ while ((event = ftdm_boost_read_event(span))) {
+ parse_sangoma_event(span, pcon, (sangomabc_short_event_t*)event);
+ sangoma_boost_data->iteration++;
+ }
+
+ check_state(span);
+ }
+
+ goto end;
+
+error:
+ ftdm_log(FTDM_LOG_CRIT, "Boost event processing Error!\n");
+
+end:
+ if (!sangoma_boost_data->sigmod) {
+ sangomabc_connection_close(&sangoma_boost_data->mcon);
+ sangomabc_connection_close(&sangoma_boost_data->pcon);
+ }
+
+ ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING);
+
+ ftdm_log(FTDM_LOG_DEBUG, "Sangoma Boost thread ended.\n");
+ return NULL;
+}
+
+/**
+ * \brief Loads sangoma boost signaling module
+ * \param fio FreeTDM IO interface
+ * \return Success
+ */
+static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_boost_init)
+{
+ g_boost_modules_hash = create_hashtable(10, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+ if (!g_boost_modules_hash) {
+ return FTDM_FAIL;
+ }
+ ftdm_mutex_create(&request_mutex);
+ ftdm_mutex_create(&g_boost_modules_mutex);
+ memset(&g_trunkgroups[0], 0, sizeof(g_trunkgroups));
+ return FTDM_SUCCESS;
+}
+
+static FIO_SIG_UNLOAD_FUNCTION(ftdm_sangoma_boost_destroy)
+{
+ ftdm_hash_iterator_t *i = NULL;
+ boost_sigmod_interface_t *sigmod = NULL;
+ const void *key = NULL;
+ void *val = NULL;
+ ftdm_dso_lib_t lib;
+
+ for (i = hashtable_first(g_boost_modules_hash); i; i = hashtable_next(i)) {
+ hashtable_this(i, &key, NULL, &val);
+ if (key && val) {
+ sigmod = val;
+ lib = sigmod->pvt;
+ ftdm_dso_destroy(&lib);
+ }
+ }
+
+ hashtable_destroy(g_boost_modules_hash);
+ ftdm_mutex_destroy(&request_mutex);
+ ftdm_mutex_destroy(&g_boost_modules_mutex);
+ return FTDM_SUCCESS;
+}
+
+static ftdm_status_t ftdm_sangoma_boost_start(ftdm_span_t *span)
+{
+ int err;
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+ ftdm_set_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING);
+ err=ftdm_thread_create_detached(ftdm_sangoma_boost_run, span);
+ if (err) {
+ ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING);
+ return err;
+ }
+ // launch the events thread to handle HW DTMF and possibly
+ // other events in the future
+ err=ftdm_thread_create_detached(ftdm_sangoma_events_run, span);
+ if (err) {
+ ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING);
+ }
+ return err;
+}
+
+static ftdm_status_t ftdm_sangoma_boost_stop(ftdm_span_t *span)
+{
+ int cnt = 10;
+ ftdm_status_t status = FTDM_SUCCESS;
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+ if (sangoma_boost_data->sigmod) {
+
+ /* FIXME: we should make sure the span thread is stopped (use pthread_kill or freetdm thread kill function) */
+ /* I think stopping the span before destroying the queue makes sense
+ otherwise may be boost events would still arrive when the queue is already destroyed! */
+ status = sangoma_boost_data->sigmod->stop_span(span);
+
+ ftdm_queue_enqueue(sangoma_boost_data->boost_queue, NULL);
+ while(ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING) && cnt-- > 0) {
+ ftdm_log(FTDM_LOG_DEBUG, "Waiting for boost thread\n");
+ ftdm_sleep(500);
+ }
+ ftdm_queue_destroy(&sangoma_boost_data->boost_queue);
+ return status;
+ }
+ return status;
+}
+
+static ftdm_state_map_t boost_state_map = {
+ {
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_ANY_STATE},
+ {FTDM_CHANNEL_STATE_RESTART, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_RESTART, FTDM_END},
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+ {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_DIALING, FTDM_CHANNEL_STATE_IDLE, FTDM_CHANNEL_STATE_HOLD, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_HOLD, FTDM_END},
+ {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS,
+ FTDM_CHANNEL_STATE_IDLE, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_IDLE, FTDM_CHANNEL_STATE_DIALING, FTDM_END},
+ {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_IDLE, FTDM_CHANNEL_STATE_DIALING, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_HANGUP, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_UP, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
+ },
+
+ /****************************************/
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_ANY_STATE},
+ {FTDM_CHANNEL_STATE_RESTART, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_RESTART, FTDM_END},
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_DOWN},
+ {FTDM_CHANNEL_STATE_IN_LOOP, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_IN_LOOP},
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+ {FTDM_CHANNEL_STATE_RING, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_RING, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA,FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_UP, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+ },
+
+
+ }
+};
+
+static BOOST_WRITE_MSG_FUNCTION(ftdm_boost_write_msg)
+{
+ sangomabc_short_event_t *shortmsg = NULL;
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = NULL;
+ sangomabc_queue_element_t *element = NULL;
+
+ ftdm_assert_return(msg != NULL, FTDM_FAIL, "Boost message to write was null");
+
+ if (!span) {
+ shortmsg = msg;
+ ftdm_log(FTDM_LOG_ERROR, "Unexpected boost message %d\n", shortmsg->event_id);
+ return FTDM_FAIL;
+ }
+ /* duplicate the event and enqueue it */
+ element = ftdm_calloc(1, sizeof(*element));
+ if (!element) {
+ return FTDM_FAIL;
+ }
+ memcpy(element->boostmsg, msg, msglen);
+ element->size = msglen;
+
+ sangoma_boost_data = span->signal_data;
+ return ftdm_queue_enqueue(sangoma_boost_data->boost_queue, element);
+}
+
+static BOOST_SIG_STATUS_CB_FUNCTION(ftdm_boost_sig_status_change)
+{
+ ftdm_sigmsg_t sig;
+ ftdm_log(FTDM_LOG_NOTICE, "%d:%d Signaling link status changed to %s\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_signaling_status2str(status));
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = ftdmchan->chan_id;
+ sig.span_id = ftdmchan->span_id;
+ sig.channel = ftdmchan;
+ sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
+ sig.raw_data = &status;
+ ftdm_span_send_signal(ftdmchan->span, &sig);
+ return;
+}
+
+static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(sangoma_boost_set_channel_sig_status)
+{
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
+ if (!sangoma_boost_data->sigmod) {
+ ftdm_log(FTDM_LOG_ERROR, "Cannot set signaling status in boost channel with no signaling module configured\n");
+ return FTDM_FAIL;
+ }
+ if (!sangoma_boost_data->sigmod->set_channel_sig_status) {
+ ftdm_log(FTDM_LOG_ERROR, "Cannot set signaling status in boost channel: method not implemented\n");
+ return FTDM_NOTIMPL;
+ }
+ return sangoma_boost_data->sigmod->set_channel_sig_status(ftdmchan, status);
+}
+
+static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(sangoma_boost_get_channel_sig_status)
+{
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
+ if (!sangoma_boost_data->sigmod) {
+ ftdm_log(FTDM_LOG_ERROR, "Cannot get signaling status in boost channel with no signaling module configured\n");
+ return FTDM_FAIL;
+ }
+ if (!sangoma_boost_data->sigmod->get_channel_sig_status) {
+ ftdm_log(FTDM_LOG_ERROR, "Cannot get signaling status in boost channel: method not implemented\n");
+ return FTDM_NOTIMPL;
+ }
+ return sangoma_boost_data->sigmod->get_channel_sig_status(ftdmchan, status);
+}
+
+static FIO_SPAN_SET_SIG_STATUS_FUNCTION(sangoma_boost_set_span_sig_status)
+{
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+ if (!sangoma_boost_data->sigmod) {
+ ftdm_log(FTDM_LOG_ERROR, "Cannot set signaling status in boost span with no signaling module configured\n");
+ return FTDM_FAIL;
+ }
+ if (!sangoma_boost_data->sigmod->set_span_sig_status) {
+ ftdm_log(FTDM_LOG_ERROR, "Cannot set signaling status in boost span: method not implemented\n");
+ return FTDM_NOTIMPL;
+ }
+ return sangoma_boost_data->sigmod->set_span_sig_status(span, status);
+}
+
+static FIO_SPAN_GET_SIG_STATUS_FUNCTION(sangoma_boost_get_span_sig_status)
+{
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+ if (!sangoma_boost_data->sigmod) {
+ ftdm_log(FTDM_LOG_ERROR, "Cannot get signaling status in boost span with no signaling module configured\n");
+ return FTDM_FAIL;
+ }
+ if (!sangoma_boost_data->sigmod->get_span_sig_status) {
+ ftdm_log(FTDM_LOG_ERROR, "Cannot get signaling status in boost span: method not implemented\n");
+ return FTDM_NOTIMPL;
+ }
+ return sangoma_boost_data->sigmod->get_span_sig_status(span, status);
+}
+
+/* TODO: move these ones to a common private header so other ISDN mods can use them */
+static void ftdm_span_set_npi(const char *npi_string, uint8_t *target)
+{
+ if (!strcasecmp(npi_string, "isdn") || !strcasecmp(npi_string, "e164")) {
+ *target = FTDM_NPI_ISDN;
+ } else if (!strcasecmp(npi_string, "data")) {
+ *target = FTDM_NPI_DATA;
+ } else if (!strcasecmp(npi_string, "telex")) {
+ *target = FTDM_NPI_TELEX;
+ } else if (!strcasecmp(npi_string, "national")) {
+ *target = FTDM_NPI_NATIONAL;
+ } else if (!strcasecmp(npi_string, "private")) {
+ *target = FTDM_NPI_PRIVATE;
+ } else if (!strcasecmp(npi_string, "reserved")) {
+ *target = FTDM_NPI_RESERVED;
+ } else if (!strcasecmp(npi_string, "unknown")) {
+ *target = FTDM_NPI_UNKNOWN;
+ } else {
+ ftdm_log(FTDM_LOG_WARNING, "Invalid NPI value (%s)\n", npi_string);
+ *target = FTDM_NPI_UNKNOWN;
+ }
+}
+
+static void ftdm_span_set_ton(const char *ton_string, uint8_t *target)
+{
+ if (!strcasecmp(ton_string, "national")) {
+ *target = FTDM_TON_NATIONAL;
+ } else if (!strcasecmp(ton_string, "international")) {
+ *target = FTDM_TON_INTERNATIONAL;
+ } else if (!strcasecmp(ton_string, "local")) {
+ *target = FTDM_TON_SUBSCRIBER_NUMBER;
+ } else if (!strcasecmp(ton_string, "unknown")) {
+ *target = FTDM_TON_UNKNOWN;
+ } else {
+ ftdm_log(FTDM_LOG_WARNING, "Invalid TON value (%s)\n", ton_string);
+ *target = FTDM_TON_UNKNOWN;
+ }
+}
+
+
+/**
+ * \brief Initialises an sangoma boost span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span)
+{
+#define FAIL_CONFIG_RETURN(retstatus) \
+ if (sangoma_boost_data) \
+ ftdm_safe_free(sangoma_boost_data); \
+ if (err) \
+ ftdm_safe_free(err) \
+ if (hash_locked) \
+ ftdm_mutex_unlock(g_boost_modules_mutex); \
+ if (lib) \
+ ftdm_dso_destroy(&lib); \
+ return retstatus;
+
+ boost_sigmod_interface_t *sigmod_iface = NULL;
+ ftdm_sangoma_boost_data_t *sangoma_boost_data = NULL;
+ const char *local_ip = "127.0.0.65", *remote_ip = "127.0.0.66";
+ const char *sigmod = NULL;
+ int local_port = 53000, remote_port = 53000;
+ const char *var = NULL, *val = NULL;
+ int hash_locked = 0;
+ ftdm_dso_lib_t lib = NULL;
+ char path[255] = "";
+ char *err = NULL;
+ unsigned paramindex = 0;
+ ftdm_status_t rc = FTDM_SUCCESS;
+
+ for (; ftdm_parameters[paramindex].var; paramindex++) {
+ var = ftdm_parameters[paramindex].var;
+ val = ftdm_parameters[paramindex].val;
+ if (!strcasecmp(var, "sigmod")) {
+ sigmod = val;
+ } else if (!strcasecmp(var, "local_ip")) {
+ local_ip = val;
+ } else if (!strcasecmp(var, "remote_ip")) {
+ remote_ip = val;
+ } else if (!strcasecmp(var, "local_port")) {
+ local_port = atoi(val);
+ } else if (!strcasecmp(var, "remote_port")) {
+ remote_port = atoi(val);
+ } else if (!strcasecmp(var, "outbound-called-ton")) {
+ ftdm_span_set_ton(val, &span->default_caller_data.dnis.type);
+ } else if (!strcasecmp(var, "outbound-called-npi")) {
+ ftdm_span_set_npi(val, &span->default_caller_data.dnis.plan);
+ } else if (!strcasecmp(var, "outbound-calling-ton")) {
+ ftdm_span_set_ton(val, &span->default_caller_data.cid_num.type);
+ } else if (!strcasecmp(var, "outbound-calling-npi")) {
+ ftdm_span_set_npi(val, &span->default_caller_data.cid_num.plan);
+ } else if (!strcasecmp(var, "outbound-rdnis-ton")) {
+ ftdm_span_set_ton(val, &span->default_caller_data.rdnis.type);
+ } else if (!strcasecmp(var, "outbound-rdnis-npi")) {
+ ftdm_span_set_npi(val, &span->default_caller_data.rdnis.plan);
+ } else if (!sigmod) {
+ snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+ FAIL_CONFIG_RETURN(FTDM_FAIL);
+ }
+ }
+
+ if (!sigmod) {
+ if (!local_ip && local_port && remote_ip && remote_port && sig_cb) {
+ ftdm_set_string(span->last_error, "missing Sangoma boost IP parameters");
+ FAIL_CONFIG_RETURN(FTDM_FAIL);
+ }
+ }
+
+ sangoma_boost_data = ftdm_calloc(1, sizeof(*sangoma_boost_data));
+ if (!sangoma_boost_data) {
+ FAIL_CONFIG_RETURN(FTDM_FAIL);
+ }
+
+ /* WARNING: be sure to release this mutex on errors inside this if() */
+ ftdm_mutex_lock(g_boost_modules_mutex);
+ hash_locked = 1;
+ if (sigmod && !(sigmod_iface = hashtable_search(g_boost_modules_hash, (void *)sigmod))) {
+ ftdm_build_dso_path(sigmod, path, sizeof(path));
+ lib = ftdm_dso_open(path, &err);
+ if (!lib) {
+ ftdm_log(FTDM_LOG_ERROR, "Error loading Sangoma boost signaling module '%s': %s\n", path, err);
+ snprintf(span->last_error, sizeof(span->last_error), "Failed to load sangoma boost signaling module %s", path);
+
+ FAIL_CONFIG_RETURN(FTDM_FAIL);
+ }
+ if (!(sigmod_iface = (boost_sigmod_interface_t *)ftdm_dso_func_sym(lib, BOOST_INTERFACE_NAME_STR, &err))) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to read Sangoma boost signaling module interface '%s': %s\n", path, err);
+ snprintf(span->last_error, sizeof(span->last_error), "Failed to read Sangoma boost signaling module interface '%s': %s", path, err);
+
+ FAIL_CONFIG_RETURN(FTDM_FAIL);
+ }
+ rc = sigmod_iface->on_load();
+ if (rc != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to load Sangoma boost signaling module interface '%s': on_load method failed (%d)\n", path, rc);
+ FAIL_CONFIG_RETURN(FTDM_FAIL);
+ }
+ sigmod_iface->pvt = lib;
+ sigmod_iface->set_write_msg_cb(ftdm_boost_write_msg);
+ sigmod_iface->set_sig_status_cb(ftdm_boost_sig_status_change);
+ hashtable_insert(g_boost_modules_hash, (void *)sigmod_iface->name, sigmod_iface, HASHTABLE_FLAG_NONE);
+ lib = NULL; /* destroying the lib will be done when going down and NOT on FAIL_CONFIG_RETURN */
+ }
+ ftdm_mutex_unlock(g_boost_modules_mutex);
+ hash_locked = 0;
+
+ if (sigmod_iface) {
+ /* try to create the boost queue */
+ if (ftdm_queue_create(&sangoma_boost_data->boost_queue, BOOST_QUEUE_SIZE) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Span %s could not create its boost queue!\n", span->name);
+ FAIL_CONFIG_RETURN(FTDM_FAIL);
+ }
+ ftdm_log(FTDM_LOG_NOTICE, "Span %s will use Sangoma Boost Signaling Module %s\n", span->name, sigmod_iface->name);
+ sangoma_boost_data->sigmod = sigmod_iface;
+ sigmod_iface->configure_span(span, ftdm_parameters);
+ } else {
+ ftdm_log(FTDM_LOG_NOTICE, "Span %s will use boost socket mode\n", span->name);
+ ftdm_set_string(sangoma_boost_data->mcon.cfg.local_ip, local_ip);
+ sangoma_boost_data->mcon.cfg.local_port = local_port;
+ ftdm_set_string(sangoma_boost_data->mcon.cfg.remote_ip, remote_ip);
+ sangoma_boost_data->mcon.cfg.remote_port = remote_port;
+ }
+ span->signal_cb = sig_cb;
+ span->start = ftdm_sangoma_boost_start;
+ span->stop = ftdm_sangoma_boost_stop;
+ span->signal_data = sangoma_boost_data;
+ span->signal_type = FTDM_SIGTYPE_SANGOMABOOST;
+ span->outgoing_call = sangoma_boost_outgoing_call;
+ span->channel_request = sangoma_boost_channel_request;
+ span->get_channel_sig_status = sangoma_boost_get_channel_sig_status;
+ span->set_channel_sig_status = sangoma_boost_set_channel_sig_status;
+ span->get_span_sig_status = sangoma_boost_get_span_sig_status;
+ span->set_span_sig_status = sangoma_boost_set_span_sig_status;
+ span->state_map = &boost_state_map;
+ span->suggest_chan_id = 0;
+ if (sigmod_iface) {
+ /* the core will do the hunting */
+ span->channel_request = NULL;
+ }
+ ftdm_set_flag_locked(span, FTDM_SPAN_SUSPENDED);
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief FreeTDM sangoma boost signaling module definition
+ */
+EX_DECLARE_DATA ftdm_module_t ftdm_module = {
+ /*.name =*/ "sangoma_boost",
+ /*.io_load =*/ NULL,
+ /*.io_unload =*/ NULL,
+ /*.sig_load = */ ftdm_sangoma_boost_init,
+ /*.sig_configure =*/ NULL,
+ /*.sig_unload = */ftdm_sangoma_boost_destroy,
+ /*.configure_span_signaling = */ ftdm_sangoma_boost_configure_span
+};
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,575 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ * 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.
+ */
+
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include "freetdm.h"
+#include "sangoma_boost_client.h"
+
+#ifndef HAVE_GETHOSTBYNAME_R
+extern int gethostbyname_r (const char *__name,
+ struct hostent *__result_buf,
+ char *__buf, size_t __buflen,
+ struct hostent **__result,
+ int *__h_errnop);
+#endif
+
+struct sangomabc_map {
+ uint32_t event_id;
+ const char *name;
+};
+
+static struct sangomabc_map sangomabc_table[] = {
+ {SIGBOOST_EVENT_CALL_START, "CALL_START"},
+ {SIGBOOST_EVENT_CALL_START_ACK, "CALL_START_ACK"},
+ {SIGBOOST_EVENT_CALL_START_NACK, "CALL_START_NACK"},
+ {SIGBOOST_EVENT_CALL_PROGRESS, "CALL PROGRESS"},
+ {SIGBOOST_EVENT_CALL_START_NACK_ACK, "CALL_START_NACK_ACK"},
+ {SIGBOOST_EVENT_CALL_ANSWERED, "CALL_ANSWERED"},
+ {SIGBOOST_EVENT_CALL_STOPPED, "CALL_STOPPED"},
+ {SIGBOOST_EVENT_CALL_STOPPED_ACK, "CALL_STOPPED_ACK"},
+ {SIGBOOST_EVENT_CALL_RELEASED, "CALL_RELEASED"},
+ {SIGBOOST_EVENT_SYSTEM_RESTART, "SYSTEM_RESTART"},
+ {SIGBOOST_EVENT_SYSTEM_RESTART_ACK, "SYSTEM_RESTART_ACK"},
+ {SIGBOOST_EVENT_HEARTBEAT, "HEARTBEAT"},
+ {SIGBOOST_EVENT_INSERT_CHECK_LOOP, "LOOP START"},
+ {SIGBOOST_EVENT_REMOVE_CHECK_LOOP, "LOOP STOP"},
+ {SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE, "AUTO_CALL_GAP_ABATE"},
+ {SIGBOOST_EVENT_DIGIT_IN, "DIGIT_IN"}
+};
+
+
+
+static void sangomabc_print_event_call(sangomabc_connection_t *mcon, sangomabc_event_t *event, int priority, int dir, const char *file, const char *func, int line)
+{
+ if (event->event_id == SIGBOOST_EVENT_HEARTBEAT)
+ return;
+
+ ftdm_log(file, func, line, FTDM_LOG_LEVEL_DEBUG, "%s EVENT (%s): %s:(%X) [w%dg%d] CSid=%i Seq=%i Cn=[%s] Cd=[%s] Ci=[%s] Rdnis=[%s]\n",
+ dir ? "TX":"RX",
+ priority ? "P":"N",
+ sangomabc_event_id_name(event->event_id),
+ event->event_id,
+ event->span,
+ event->chan,
+ event->call_setup_id,
+ event->fseqno,
+ strlen(event->calling_name)?event->calling_name:"N/A",
+ (event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
+ (event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A"),
+ event->isup_in_rdnis);
+
+}
+static void sangomabc_print_event_short(sangomabc_connection_t *mcon, sangomabc_short_event_t *event, int priority, int dir, const char *file, const char *func, int line)
+{
+ if (event->event_id == SIGBOOST_EVENT_HEARTBEAT)
+ return;
+ ftdm_log(file, func, line, FTDM_LOG_LEVEL_DEBUG, "%s EVENT (%s): %s:(%X) [s%dc%d] Rc=%i CSid=%i Seq=%i \n",
+ dir ? "TX":"RX",
+ priority ? "P":"N",
+ sangomabc_event_id_name(event->event_id),
+ event->event_id,
+ event->span,
+ event->chan,
+ event->release_cause,
+ event->call_setup_id,
+ event->fseqno);
+}
+
+
+static int create_conn_socket(sangomabc_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
+{
+#ifndef WIN32
+ int rc;
+ struct hostent *result, *local_result;
+ char buf[512], local_buf[512];
+ int err = 0, local_err = 0;
+
+ if (mcon->sigmod) {
+ ftdm_log(FTDM_LOG_WARNING, "I should not be called on a sigmod-managed connection!\n");
+ return 0;
+ }
+
+ memset(&mcon->remote_hp, 0, sizeof(mcon->remote_hp));
+ memset(&mcon->local_hp, 0, sizeof(mcon->local_hp));
+#ifdef HAVE_NETINET_SCTP_H
+ ftdm_log(FTDM_LOG_DEBUG, "Creating SCTP socket L=%s:%d R=%s:%d\n",
+ local_ip, local_port, ip, port);
+ mcon->socket = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+#else
+ ftdm_log(FTDM_LOG_DEBUG, "Creating UDP socket L=%s:%d R=%s:%d\n",
+ local_ip, local_port, ip, port);
+ mcon->socket = socket(AF_INET, SOCK_DGRAM, 0);
+#endif
+
+ if (mcon->socket >= 0) {
+ int flag;
+
+ flag = 1;
+#ifdef HAVE_GETHOSTBYNAME_R_FIVE
+ gethostbyname_r(ip, &mcon->remote_hp, buf, sizeof(buf), &err);
+ gethostbyname_r(local_ip, &mcon->local_hp, local_buf, sizeof(local_buf), &local_err);
+ if (!err && !local_err) {
+#else
+ gethostbyname_r(ip, &mcon->remote_hp, buf, sizeof(buf), &result, &err);
+ gethostbyname_r(local_ip, &mcon->local_hp, local_buf, sizeof(local_buf), &local_result, &local_err);
+ if (result && local_result) {
+#endif
+ mcon->remote_addr.sin_family = mcon->remote_hp.h_addrtype;
+ memcpy((char *) &mcon->remote_addr.sin_addr.s_addr, mcon->remote_hp.h_addr_list[0], mcon->remote_hp.h_length);
+ mcon->remote_addr.sin_port = htons(port);
+
+ mcon->local_addr.sin_family = mcon->local_hp.h_addrtype;
+ memcpy((char *) &mcon->local_addr.sin_addr.s_addr, mcon->local_hp.h_addr_list[0], mcon->local_hp.h_length);
+ mcon->local_addr.sin_port = htons(local_port);
+
+#ifdef HAVE_NETINET_SCTP_H
+ setsockopt(mcon->socket, IPPROTO_SCTP, SCTP_NODELAY,
+ (char *)&flag, sizeof(int));
+#endif
+
+ if ((rc = bind(mcon->socket,
+ (struct sockaddr *) &mcon->local_addr,
+ sizeof(mcon->local_addr))) < 0) {
+ close(mcon->socket);
+ mcon->socket = -1;
+ } else {
+#ifdef HAVE_NETINET_SCTP_H
+ rc=listen(mcon->socket, 100);
+ if (rc) {
+ close(mcon->socket);
+ mcon->socket = -1;
+ }
+#endif
+ }
+ }
+ }
+
+ return mcon->socket;
+#else
+ return 0;
+#endif // ifndef WIN32
+}
+
+int sangomabc_connection_close(sangomabc_connection_t *mcon)
+{
+#ifndef WIN32
+ if (mcon->sigmod) {
+ ftdm_log(FTDM_LOG_WARNING, "I should not be called on a sigmod-managed connection!\n");
+ return 0;
+ }
+ if (mcon->socket > -1) {
+ close(mcon->socket);
+ }
+
+ if (mcon->mutex) {
+ ftdm_mutex_lock(mcon->mutex);
+ ftdm_mutex_unlock(mcon->mutex);
+ ftdm_mutex_destroy(&mcon->mutex);
+ }
+ memset(mcon, 0, sizeof(*mcon));
+ mcon->socket = -1;
+#endif
+ return 0;
+}
+
+int sangomabc_connection_open(sangomabc_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
+{
+ ftdm_mutex_create(&mcon->mutex);
+ if (mcon->sigmod) {
+ /*value of mcon->socket will be ignored in sigmod mode */
+ return 0;
+ }
+#ifndef WIN32
+ create_conn_socket(mcon, local_ip, local_port, ip, port);
+ return mcon->socket;
+#else
+ return 0;
+#endif
+}
+
+
+int sangomabc_exec_command(sangomabc_connection_t *mcon, int span, int chan, int id, int cmd, int cause, int flags)
+{
+ sangomabc_short_event_t oevent;
+ int retry = 5;
+
+ sangomabc_event_init(&oevent, cmd, chan, span);
+ oevent.release_cause = (uint8_t)cause;
+ oevent.flags = flags;
+
+ if (cmd == SIGBOOST_EVENT_SYSTEM_RESTART || cmd == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
+ mcon->rxseq_reset = 1;
+ mcon->txseq = 0;
+ mcon->rxseq = 0;
+ mcon->txwindow = 0;
+ }
+
+ if (id >= 0) {
+ oevent.call_setup_id = (uint16_t)id;
+ }
+
+ while (sangomabc_connection_write(mcon, (sangomabc_event_t*)&oevent) <= 0) {
+ if (--retry <= 0) {
+ ftdm_log(FTDM_LOG_CRIT, "Failed to tx on boost socket: %s\n", strerror(errno));
+ return -1;
+ } else {
+ ftdm_log(FTDM_LOG_WARNING, "Failed to tx on boost socket: %s :retry %i\n", strerror(errno), retry);
+ ftdm_sleep(1);
+ }
+ }
+
+ return 0;
+}
+
+
+int sangomabc_exec_commandp(sangomabc_connection_t *pcon, int span, int chan, int id, int cmd, int cause)
+{
+ sangomabc_short_event_t oevent;
+ int retry = 5;
+
+ sangomabc_event_init(&oevent, cmd, chan, span);
+ oevent.release_cause = (uint8_t)cause;
+
+ if (id >= 0) {
+ oevent.call_setup_id = (uint16_t)id;
+ }
+
+ while (sangomabc_connection_writep(pcon, (sangomabc_event_t*)&oevent) <= 0) {
+ if (--retry <= 0) {
+ ftdm_log(FTDM_LOG_CRIT, "Failed to tx on boost socket: %s\n", strerror(errno));
+ return -1;
+ } else {
+ ftdm_log(FTDM_LOG_WARNING, "Failed to tx on boost socket: %s :retry %i\n", strerror(errno), retry);
+ ftdm_sleep(1);
+ }
+ }
+
+ return 0;
+}
+
+sangomabc_event_t *__sangomabc_connection_read(sangomabc_connection_t *mcon, int iteration, const char *file, const char *func, int line)
+{
+#ifndef WIN32
+ unsigned int fromlen = sizeof(struct sockaddr_in);
+#endif
+ int bytes = 0;
+ int msg_ok = 0;
+ sangomabc_queue_element_t *e = NULL;
+
+ if (mcon->sigmod) {
+ e = ftdm_queue_dequeue(mcon->boost_queue);
+ if (e) {
+ bytes = e->size;
+ memcpy(&mcon->event, e->boostmsg, bytes);
+ ftdm_safe_free(e);
+ }
+ }
+#ifndef WIN32
+ else {
+ bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT,
+ (struct sockaddr *) &mcon->local_addr, &fromlen);
+ }
+#endif
+ if (bytes <= 0) {
+ return NULL;
+ }
+
+ if (mcon->event.version != SIGBOOST_VERSION) {
+ ftdm_log(FTDM_LOG_CRIT, "Invalid Boost Version %i Expecting %i\n",mcon->event.version, SIGBOOST_VERSION);
+ }
+
+ if ((bytes >= MIN_SIZE_CALLSTART_MSG) && boost_full_event(mcon->event.event_id)) {
+ msg_ok=1;
+
+ } else if (bytes == sizeof(sangomabc_short_event_t)) {
+ msg_ok=1;
+
+ } else {
+ msg_ok=0;
+ }
+
+ if (msg_ok) {
+ if (sangomabc_test_flag(mcon, MSU_FLAG_DOWN)) {
+ if (mcon->event.event_id != SIGBOOST_EVENT_SYSTEM_RESTART &&
+ mcon->event.event_id != SIGBOOST_EVENT_SYSTEM_RESTART_ACK &&
+ mcon->event.event_id != SIGBOOST_EVENT_HEARTBEAT) {
+ ftdm_log(file, func, line, FTDM_LOG_LEVEL_WARNING, "Not reading packets when connection is down. [%s]\n",
+ sangomabc_event_id_name(mcon->event.event_id));
+ return NULL;
+ }
+ }
+
+ if (boost_full_event(mcon->event.event_id)) {
+ sangomabc_print_event_call(mcon, &mcon->event, 0, 0, file, func, line);
+ } else {
+ sangomabc_print_event_short(mcon, (sangomabc_short_event_t*)&mcon->event, 0, 0, file, func, line);
+ }
+
+#if 0
+/* NC: NOT USED ANY MORE */
+ if (mcon->rxseq_reset) {
+ //if (mcon->event.event_id == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
+ ftdm_log(FTDM_LOG_DEBUG, "Rx sync ok\n");
+ mcon->rxseq = mcon->event.fseqno;
+ return &mcon->event;
+ //}
+ errno=EAGAIN;
+ ftdm_log(FTDM_LOG_DEBUG, "Waiting for rx sync...\n");
+ return NULL;
+ }
+#endif
+
+ mcon->txwindow = mcon->txseq - mcon->event.bseqno;
+ mcon->rxseq++;
+
+#if 0
+ if (mcon->rxseq != mcon->event.fseqno) {
+ ftdm_log(FTDM_LOG_CRIT, "Invalid Sequence Number Expect=%i Rx=%i\n", mcon->rxseq, mcon->event.fseqno);
+ return NULL;
+ }
+#endif
+
+ return &mcon->event;
+ } else {
+ if (iteration == 0) {
+ ftdm_log(FTDM_LOG_CRIT, "NC - Invalid Event length from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+sangomabc_event_t *__sangomabc_connection_readp(sangomabc_connection_t *mcon, int iteration, const char *file, const char *func, int line)
+{
+#ifndef WIN32
+ unsigned int fromlen = sizeof(struct sockaddr_in);
+#endif
+ int bytes = 0;
+
+ if (mcon->sigmod) {
+ /* priority stuff is handled just the same when there is a sigmod */
+ return sangomabc_connection_read(mcon, iteration);
+ }
+#ifndef WIN32
+ else {
+ bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT, (struct sockaddr *) &mcon->local_addr, &fromlen);
+ }
+#endif
+ if (bytes <= 0) {
+ return NULL;
+ }
+
+ if (mcon->event.version != SIGBOOST_VERSION) {
+ ftdm_log(FTDM_LOG_CRIT, "Invalid Boost Version %i Expecting %i\n",mcon->event.version, SIGBOOST_VERSION);
+ }
+
+ if (bytes == sizeof(sangomabc_short_event_t)) {
+
+ if (boost_full_event(mcon->event.event_id)) {
+ sangomabc_print_event_call(mcon, &mcon->event, 1, 0, file, func, line);
+ } else {
+ sangomabc_print_event_short(mcon, (sangomabc_short_event_t*)&mcon->event, 1, 0, file, func, line);
+ }
+
+ return &mcon->event;
+ } else {
+ if (iteration == 0) {
+ ftdm_log(FTDM_LOG_CRIT, "Critical Error: PQ Invalid Event lenght from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+
+int __sangomabc_connection_write(sangomabc_connection_t *mcon, sangomabc_event_t *event, const char *file, const char *func, int line)
+{
+ int err = 0;
+ int event_size=MIN_SIZE_CALLSTART_MSG+event->isup_in_rdnis_size;
+
+ ftdm_assert_return(event != NULL, -1, "No event!");
+ ftdm_assert_return(mcon->socket >= 0, -1, "No mcon->socket!");
+ ftdm_assert_return(mcon->mutex != NULL, -1, "No mcon->mutex!");
+
+ ftdm_assert_return(event->span <= FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN, -1, "Invalid span when writing boost event\n");
+ ftdm_assert_return(event->chan <= FTDM_MAX_CHANNELS_PHYSICAL_SPAN, -1, "Invalid chan when writing boost event\n");
+
+ if (!boost_full_event(event->event_id)) {
+ event_size=sizeof(sangomabc_short_event_t);
+ }
+
+ if (sangomabc_test_flag(mcon, MSU_FLAG_DOWN)) {
+ if (event->event_id != SIGBOOST_EVENT_SYSTEM_RESTART &&
+ event->event_id != SIGBOOST_EVENT_SYSTEM_RESTART_ACK &&
+ event->event_id != SIGBOOST_EVENT_HEARTBEAT) {
+ ftdm_log(file, func, line, FTDM_LOG_LEVEL_WARNING, "Not writing packets when connection is down. [%s]\n",
+ sangomabc_event_id_name(event->event_id));
+ return 0;
+ }
+ }
+
+ ftdm_mutex_lock(mcon->mutex);
+ if (event->event_id == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
+ mcon->txseq=0;
+ mcon->rxseq=0;
+ event->fseqno=0;
+ } else {
+ event->fseqno = mcon->txseq++;
+ }
+ event->bseqno = mcon->rxseq;
+ event->version = SIGBOOST_VERSION;
+
+ if (boost_full_event(event->event_id)) {
+ sangomabc_print_event_call(mcon, event, 0, 1, file, func, line);
+ } else {
+ sangomabc_print_event_short(mcon, (sangomabc_short_event_t*)event, 0, 1, file, func, line);
+ }
+
+ if (mcon->sigmod) {
+ mcon->sigmod->write_msg(mcon->span, event, event_size);
+ err = event_size;
+ }
+#ifndef WIN32
+ else {
+ err = sendto(mcon->socket, event, event_size, 0, (struct sockaddr *) &mcon->remote_addr, sizeof(mcon->remote_addr));
+ }
+#endif
+
+ ftdm_mutex_unlock(mcon->mutex);
+
+ ftdm_assert_return(err == event_size, -1, "Failed to send the boost message completely!");
+
+ return err;
+}
+
+
+int __sangomabc_connection_writep(sangomabc_connection_t *mcon, sangomabc_event_t *event, const char *file, const char *func, int line)
+{
+ int err = 0;
+ int event_size=sizeof(sangomabc_event_t);
+
+ if (!mcon->sigmod) {
+ ftdm_assert_return(event != NULL, -1, "No event!");
+ ftdm_assert_return(mcon->socket >= 0, -1, "No mcon->socket!");
+ ftdm_assert_return(mcon->mutex != NULL, -1, "No mcon->mutex!");
+ }
+
+ if (!boost_full_event(event->event_id)) {
+ event_size=sizeof(sangomabc_short_event_t);
+ }
+
+ ftdm_mutex_lock(mcon->mutex);
+ event->version = SIGBOOST_VERSION;
+ if (mcon->sigmod) {
+ mcon->sigmod->write_msg(mcon->span, event, event_size);
+ err = event_size;
+
+ }
+#ifndef WIN32
+ else {
+ err = sendto(mcon->socket, event, event_size, 0, (struct sockaddr *) &mcon->remote_addr, sizeof(mcon->remote_addr));
+ }
+#endif
+ ftdm_mutex_unlock(mcon->mutex);
+
+ ftdm_assert_return(err == event_size, -1, "Failed to send boost message completely!");
+
+ if (boost_full_event(event->event_id)) {
+ sangomabc_print_event_call(mcon, event, 1, 1, file, func, line);
+ } else {
+ sangomabc_print_event_short(mcon, (sangomabc_short_event_t*)event, 1, 1, file, func, line);
+ }
+
+ return err;
+}
+
+
+void sangomabc_call_init(sangomabc_event_t *event, const char *calling, const char *called, int setup_id)
+{
+ memset(event, 0, sizeof(sangomabc_event_t));
+ event->event_id = SIGBOOST_EVENT_CALL_START;
+
+ if (calling) {
+ strncpy((char*)event->calling_number_digits, calling, sizeof(event->calling_number_digits)-1);
+ event->calling_number_digits_count = (uint8_t)strlen(calling);
+ }
+
+ if (called) {
+ strncpy((char*)event->called_number_digits, called, sizeof(event->called_number_digits)-1);
+ event->called_number_digits_count = (uint8_t)strlen(called);
+ }
+
+ event->call_setup_id = (uint16_t)setup_id;
+
+}
+
+void sangomabc_event_init(sangomabc_short_event_t *event, sangomabc_event_id_t event_id, int chan, int span)
+{
+ memset(event, 0, sizeof(sangomabc_short_event_t));
+ event->event_id = event_id;
+ event->chan = (uint8_t)chan;
+ event->span = (uint8_t)span;
+}
+
+const char *sangomabc_event_id_name(uint32_t event_id)
+{
+ unsigned int x;
+ const char *ret = NULL;
+
+ for (x = 0 ; x < sizeof(sangomabc_table)/sizeof(struct sangomabc_map); x++) {
+ if (sangomabc_table[x].event_id == event_id) {
+ ret = sangomabc_table[x].name;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ * 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.
+ */
+
+#ifndef _SANGOMABC_H
+#define _SANGOMABC_H
+
+#include "sangoma_boost_interface.h"
+
+#include <ctype.h>
+#include <string.h>
+#ifndef WIN32
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifdef HAVE_NETINET_SCTP_H
+#include <netinet/sctp.h>
+#endif
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/time.h>
+#endif
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include "sigboost.h"
+
+#define sangomabc_test_flag(p,flag) ((p)->flags & (flag))
+
+#define sangomabc_set_flag(p,flag) do { \
+ ((p)->flags |= (flag)); \
+ } while (0)
+
+#define sangomabc_clear_flag(p,flag) do { \
+ ((p)->flags &= ~(flag)); \
+ } while (0)
+
+#define sangomabc_copy_flags(dest,src,flagz) do { \
+ (dest)->flags &= ~(flagz); \
+ (dest)->flags |= ((src)->flags & (flagz)); \
+ } while (0)
+
+typedef t_sigboost_callstart sangomabc_event_t;
+typedef t_sigboost_short sangomabc_short_event_t;
+typedef uint32_t sangomabc_event_id_t;
+
+typedef struct sangomabc_ip_cfg
+{
+ char local_ip[25];
+ int local_port;
+ char remote_ip[25];
+ int remote_port;
+}sangomabc_ip_cfg_t;
+
+typedef enum {
+ MSU_FLAG_EVENT = (1 << 0),
+ MSU_FLAG_DOWN = (1 << 1)
+} sangomabc_flag_t;
+
+
+struct sangomabc_connection {
+ ftdm_socket_t socket;
+ struct sockaddr_in local_addr;
+ struct sockaddr_in remote_addr;
+ sangomabc_event_t event;
+ struct hostent remote_hp;
+ struct hostent local_hp;
+ unsigned int flags;
+ ftdm_mutex_t *mutex;
+ FILE *log;
+ unsigned int txseq;
+ unsigned int rxseq;
+ unsigned int txwindow;
+ unsigned int rxseq_reset;
+ sangomabc_ip_cfg_t cfg;
+ /* boost signaling mod interface pointer (if not working in TCP mode) */
+ boost_sigmod_interface_t *sigmod;
+ ftdm_queue_t *boost_queue;
+ ftdm_interrupt_t *sock_interrupt;
+ ftdm_span_t *span;
+};
+
+typedef struct sangomabc_connection sangomabc_connection_t;
+
+typedef struct sangomabc_queue_element {
+ unsigned char boostmsg[sizeof(sangomabc_event_t)];
+ ftdm_size_t size;
+} sangomabc_queue_element_t;
+
+/* disable nagle's algorythm */
+static __inline__ void sctp_no_nagle(int socket)
+{
+#ifdef HAVE_NETINET_SCTP_H
+ int flag = 1;
+ setsockopt(socket, IPPROTO_SCTP, SCTP_NODELAY, (char *) &flag, sizeof(int));
+#endif
+}
+
+int sangomabc_connection_close(sangomabc_connection_t *mcon);
+int sangomabc_connection_open(sangomabc_connection_t *mcon, char *local_ip, int local_port, char *ip, int port);
+sangomabc_event_t *__sangomabc_connection_read(sangomabc_connection_t *mcon, int iteration, const char *file, const char *func, int line);
+sangomabc_event_t *__sangomabc_connection_readp(sangomabc_connection_t *mcon, int iteration, const char *file, const char *func, int line);
+int __sangomabc_connection_write(sangomabc_connection_t *mcon, sangomabc_event_t *event, const char *file, const char *func, int line);
+int __sangomabc_connection_writep(sangomabc_connection_t *mcon, sangomabc_event_t *event, const char *file, const char *func, int line);
+#define sangomabc_connection_write(_m,_e) __sangomabc_connection_write(_m, _e, __FILE__, __FUNCTION__, __LINE__)
+#define sangomabc_connection_writep(_m,_e) __sangomabc_connection_writep(_m, _e, __FILE__, __FUNCTION__, __LINE__)
+#define sangomabc_connection_read(_m,_e) __sangomabc_connection_read(_m, _e, __FILE__, __FUNCTION__, __LINE__)
+#define sangomabc_connection_readp(_m,_e) __sangomabc_connection_readp(_m, _e, __FILE__, __FUNCTION__, __LINE__)
+void sangomabc_event_init(sangomabc_short_event_t *event, sangomabc_event_id_t event_id, int chan, int span);
+void sangomabc_call_init(sangomabc_event_t *event, const char *calling, const char *called, int setup_id);
+const char *sangomabc_event_id_name(uint32_t event_id);
+int sangomabc_exec_command(sangomabc_connection_t *mcon, int span, int chan, int id, int cmd, int cause, int flags);
+int sangomabc_exec_commandp(sangomabc_connection_t *pcon, int span, int chan, int id, int cmd, int cause);
+
+#endif
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_interface.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_interface.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_interface.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2009, Sangoma Technologies
+ * Moises Silva <moy@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.
+ */
+
+#ifndef SANGOMA_BOOST_INTERFACE_H
+#define SANGOMA_BOOST_INTERFACE_H
+
+#include "freetdm.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*!
+ \brief Callback used to notify signaling status changes on a channel
+ \param ftdmchan The freetdm channel where the signaling status just changed
+ \param status The new signaling status
+ */
+#define BOOST_SIG_STATUS_CB_ARGS (ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status)
+typedef void (*boost_sig_status_cb_func_t) BOOST_SIG_STATUS_CB_ARGS;
+#define BOOST_SIG_STATUS_CB_FUNCTION(name) void name BOOST_SIG_STATUS_CB_ARGS
+
+/*!
+ \brief Write a boost msg to a boost endpoint
+ \param span The freetdm span where this msg was generated
+ \param msg The generic message pointer, owned by the caller
+ \param msglen The length of the provided structure pointed by msg
+ \return FTDM_SUCCESS or FTDM_FAIL
+
+ The msg buffer is owned by the caller and it should
+ be either t_sigboost_callstart or t_sigboost_short
+ the endpoint receiving the msg will first cast to
+ t_sigboost_short, check the event type, and if needed.
+ */
+#define BOOST_WRITE_MSG_ARGS (ftdm_span_t *span, void *msg, ftdm_size_t msglen)
+typedef ftdm_status_t (*boost_write_msg_func_t) BOOST_WRITE_MSG_ARGS;
+#define BOOST_WRITE_MSG_FUNCTION(name) ftdm_status_t name BOOST_WRITE_MSG_ARGS
+
+/*!
+ \brief Set the callback to be used by a signaling module to write boost messages
+ \param callback The callback to be used by the signaling module
+
+ The provided callback will be used for the signaling boost module to notify the
+ user with boost messages.
+ */
+#define BOOST_SET_WRITE_MSG_CB_ARGS (boost_write_msg_func_t callback)
+typedef void (*boost_set_write_msg_cb_func_t) BOOST_SET_WRITE_MSG_CB_ARGS;
+#define BOOST_SET_WRITE_MSG_CB_FUNCTION(name) void name BOOST_SET_WRITE_MSG_CB_ARGS
+
+/*!
+ \brief Notify hardware status change
+ \param ftdmchan The freetdm channel
+ \param status The hw status
+ \return FTDM_SUCCESS or FTDM_FAIL
+ */
+#define BOOST_ON_HW_LINK_STATUS_CHANGE_ARGS (ftdm_channel_t *ftdmchan, ftdm_channel_hw_link_status_t status)
+typedef void (*boost_on_hw_link_status_change_func_t) BOOST_ON_HW_LINK_STATUS_CHANGE_ARGS;
+#define BOOST_ON_HW_LINK_STATUS_CHANGE_FUNCTION(name) void name BOOST_ON_HW_LINK_STATUS_CHANGE_ARGS
+
+/*!
+ \brief Set signaling status callback used by the signaling module to report signaling status changes
+ \param callback The callback to be used by the signaling module
+
+ The provided callback will be used for the signaling boost module to notify the
+ user with signaling link status changes.
+ */
+#define BOOST_SET_SIG_STATUS_CB_ARGS (boost_sig_status_cb_func_t callback)
+typedef void (*boost_set_sig_status_cb_func_t) BOOST_SET_SIG_STATUS_CB_ARGS;
+#define BOOST_SET_SIG_STATUS_CB_FUNCTION(name) void name BOOST_SET_SIG_STATUS_CB_ARGS
+
+/*!
+ \brief Get the signaling status on the given channel.
+ \param ftdmchan The freetdm channel
+ \param status The status pointer where the current signaling status will be set
+ */
+#define BOOST_GET_CHANNEL_SIG_STATUS_ARGS (ftdm_channel_t *ftdmchan, ftdm_signaling_status_t *status)
+typedef ftdm_status_t (*boost_get_channel_sig_status_func_t) BOOST_GET_CHANNEL_SIG_STATUS_ARGS;
+#define BOOST_GET_CHANNEL_SIG_STATUS_FUNCTION(name) ftdm_status_t name BOOST_GET_CHANNEL_SIG_STATUS_ARGS
+
+/*!
+ \brief Set the signaling status on the given channel.
+ \param ftdmchan The freetdm channel
+ \param status The new status for the channel
+ \return FTDM_SUCCESS or FTDM_FAIL
+ */
+#define BOOST_SET_CHANNEL_SIG_STATUS_ARGS (ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status)
+typedef ftdm_status_t (*boost_set_channel_sig_status_func_t) BOOST_SET_CHANNEL_SIG_STATUS_ARGS;
+#define BOOST_SET_CHANNEL_SIG_STATUS_FUNCTION(name) ftdm_status_t name BOOST_SET_CHANNEL_SIG_STATUS_ARGS
+
+/*!
+ \brief Get the signaling status on the given span.
+ \param span The freetdm span
+ \param status The status pointer where the current signaling status will be set
+ */
+#define BOOST_GET_SPAN_SIG_STATUS_ARGS (ftdm_span_t *span, ftdm_signaling_status_t *status)
+typedef ftdm_status_t (*boost_get_span_sig_status_func_t) BOOST_GET_SPAN_SIG_STATUS_ARGS;
+#define BOOST_GET_SPAN_SIG_STATUS_FUNCTION(name) ftdm_status_t name BOOST_GET_SPAN_SIG_STATUS_ARGS
+
+/*!
+ \brief Set the signaling status on the given span.
+ \param ftdmchan The freetdm span
+ \param status The new status for the span
+ \return FTDM_SUCCESS or FTDM_FAIL
+ */
+#define BOOST_SET_SPAN_SIG_STATUS_ARGS (ftdm_span_t *span, ftdm_signaling_status_t status)
+typedef ftdm_status_t (*boost_set_span_sig_status_func_t) BOOST_SET_SPAN_SIG_STATUS_ARGS;
+#define BOOST_SET_SPAN_SIG_STATUS_FUNCTION(name) ftdm_status_t name BOOST_SET_SPAN_SIG_STATUS_ARGS
+
+/*!
+ \brief Configure the given span signaling
+ \param span The freetdm span
+ \param parameters The array of configuration key,value pairs (must be null terminated)
+ \return FTDM_SUCCESS or FTDM_FAIL
+ */
+#define BOOST_CONFIGURE_SPAN_ARGS (ftdm_span_t *span, ftdm_conf_parameter_t *parameters)
+typedef ftdm_status_t (*boost_configure_span_func_t) BOOST_CONFIGURE_SPAN_ARGS;
+#define BOOST_CONFIGURE_SPAN_FUNCTION(name) ftdm_status_t name BOOST_CONFIGURE_SPAN_ARGS
+
+/*!
+ \brief Start the given span
+ \param span The freetdm span
+ \return FTDM_SUCCESS or FTDM_FAIL
+ */
+#define BOOST_START_SPAN_ARGS (ftdm_span_t *span)
+typedef ftdm_status_t (*boost_start_span_func_t) BOOST_START_SPAN_ARGS;
+#define BOOST_START_SPAN_FUNCTION(name) ftdm_status_t name BOOST_START_SPAN_ARGS
+
+/*!
+ \brief Stop the given span
+ \param span The freetdm span
+ \return FTDM_SUCCESS or FTDM_FAIL
+ */
+#define BOOST_STOP_SPAN_ARGS (ftdm_span_t *span)
+typedef ftdm_status_t (*boost_stop_span_func_t) BOOST_START_SPAN_ARGS;
+#define BOOST_STOP_SPAN_FUNCTION(name) ftdm_status_t name BOOST_STOP_SPAN_ARGS
+
+/*!
+ \brief Called when the module is being loaded BEFORE calling anything else
+ \return FTDM_SUCCESS or FTDM_FAIL
+ */
+#define BOOST_ON_LOAD_ARGS (void)
+typedef ftdm_status_t (*boost_on_load_func_t) BOOST_ON_LOAD_ARGS;
+#define BOOST_ON_LOAD_FUNCTION(name) ftdm_status_t name BOOST_ON_LOAD_ARGS
+
+/*!
+ \brief Called when the module is being unloaded, last chance to stop everything!
+ */
+#define BOOST_ON_UNLOAD_ARGS (void)
+typedef ftdm_status_t (*boost_on_unload_func_t) BOOST_ON_UNLOAD_ARGS;
+#define BOOST_ON_UNLOAD_FUNCTION(name) ftdm_status_t name BOOST_ON_UNLOAD_ARGS
+
+/*!
+ \brief The boost signaling module interface
+ */
+typedef struct boost_sigmod_interface_s {
+ /*! \brief Module name */
+ const char *name;
+ /*! \brief write boost message function */
+ boost_write_msg_func_t write_msg;
+ /*! \brief set the user write boost message function */
+ boost_set_write_msg_cb_func_t set_write_msg_cb;
+ /*! \brief set the user signaling status function */
+ boost_set_sig_status_cb_func_t set_sig_status_cb;
+ /*! \brief get channel signaling status */
+ boost_get_channel_sig_status_func_t get_channel_sig_status;
+ /*! \brief set channel signaling status */
+ boost_set_channel_sig_status_func_t set_channel_sig_status;
+ /*! \brief get span signaling status */
+ boost_get_span_sig_status_func_t get_span_sig_status;
+ /*! \brief set span signaling status */
+ boost_set_span_sig_status_func_t set_span_sig_status;
+ /*! \brief set notify hardware link status change */
+ boost_on_hw_link_status_change_func_t on_hw_link_status_change;
+ /*! \brief configure span signaling */
+ boost_configure_span_func_t configure_span;
+ /*! \brief start freetdm span */
+ boost_start_span_func_t start_span;
+ /*! \brief stop freetdm span */
+ boost_stop_span_func_t stop_span;
+ /*! \brief the module was just loaded */
+ boost_on_load_func_t on_load;
+ /*! \brief the module is about to be unloaded */
+ boost_on_unload_func_t on_unload;
+ /*! \brief private pointer for the interface user */
+ void *pvt;
+} boost_sigmod_interface_t;
+
+#ifdef __cplusplus
+} // extern C
+#endif
+
+#define BOOST_INTERFACE_NAME boost_sigmod_interface
+#define BOOST_INTERFACE_NAME_STR "boost_sigmod_interface"
+/* use this in your sig boost module to declare your interface */
+#ifndef WIN32
+#define BOOST_INTERFACE boost_sigmod_interface_t BOOST_INTERFACE_NAME
+#else
+#define BOOST_INTERFACE __declspec(dllexport) boost_sigmod_interface_t BOOST_INTERFACE_NAME
+#endif
+#endif
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sigboost.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sigboost.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sigboost.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,203 @@
+/****************************************************************************
+ * sigboost.h $Revision: 1.13 $
+ *
+ * Definitions for the sigboost interface.
+ *
+ * WARNING WARNING WARNING
+ *
+ * This file is used by sangoma_mgd and perhaps other programs. Any changes
+ * to this file must be coordinated with other user programs,
+ *
+ * Copyright (C) 2005 Xygnada Technology, Inc.
+ *
+****************************************************************************/
+#ifndef _SIGBOOST_H_
+#define _SIGBOOST_H_
+
+#define SIGBOOST_VERSION 103
+
+// handy to define integer types that actually work on both Lin and Win
+#include <freetdm.h>
+
+enum e_sigboost_event_id_values
+{
+ SIGBOOST_EVENT_CALL_START = 0x80, /*128*/
+ SIGBOOST_EVENT_CALL_START_ACK = 0x81, /*129*/
+ SIGBOOST_EVENT_CALL_START_NACK = 0x82, /*130*/
+ SIGBOOST_EVENT_CALL_START_NACK_ACK = 0x83, /*131*/
+ SIGBOOST_EVENT_CALL_ANSWERED = 0x84, /*132*/
+ SIGBOOST_EVENT_CALL_STOPPED = 0x85, /*133*/
+ SIGBOOST_EVENT_CALL_STOPPED_ACK = 0x86, /*134*/
+ SIGBOOST_EVENT_SYSTEM_RESTART = 0x87, /*135*/
+ SIGBOOST_EVENT_SYSTEM_RESTART_ACK = 0x88, /*136*/
+ /* CALL_RELEASED is aimed to fix a race condition that became obvious
+ * when the boost socket was replaced by direct function calls
+ * and the channel hunting was moved to freetdm, the problem is
+ * we can get CALL_STOPPED msg and reply with CALL_STOPPED_ACK
+ * but the signaling module will still (in PRI) send RELEASE and
+ * wait for RELEASE_COMPLETE from the isdn network before
+ * marking the channel as available, therefore freetdm should
+ * also not mark the channel as available until CALL_RELEASED
+ * is received, for socket mode we can continue working as usual
+ * with CALL_STOPPED being the last step because the hunting is
+ * done in the signaling module.
+ * */
+ SIGBOOST_EVENT_CALL_RELEASED = 0x51, /* 81 */
+ SIGBOOST_EVENT_CALL_PROGRESS = 0x50, /*decimal 80*/
+ /* Following IDs are ss7boost to sangoma_mgd only. */
+ SIGBOOST_EVENT_HEARTBEAT = 0x89, /*137*/
+ SIGBOOST_EVENT_INSERT_CHECK_LOOP = 0x8a, /*138*/
+ SIGBOOST_EVENT_REMOVE_CHECK_LOOP = 0x8b, /*139*/
+ SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE = 0x8c, /*140*/
+ SIGBOOST_EVENT_DIGIT_IN = 0x8d, /*141*/
+};
+enum e_sigboost_release_cause_values
+{
+ SIGBOOST_RELEASE_CAUSE_UNDEFINED = 0,
+ SIGBOOST_RELEASE_CAUSE_NORMAL = 16,
+ /* probable elimination */
+ //SIGBOOST_RELEASE_CAUSE_BUSY = 0x91, /* 145 */
+ //SIGBOOST_RELEASE_CAUSE_CALLED_NOT_EXIST = 0x92, /* 146 */
+ //SIGBOOST_RELEASE_CAUSE_CIRCUIT_RESET = 0x93, /* 147 */
+ //SIGBOOST_RELEASE_CAUSE_NOANSWER = 0x94, /* 148 */
+};
+
+enum e_sigboost_call_setup_ack_nack_cause_values
+{
+ //SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY = 34, /* Q.850 value - don't use */
+ SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY = 117, /* non Q.850 value indicates local all ckt busy
+ causing sangoma_mgd to perform automatic call
+ gapping*/
+ SIGBOOST_CALL_SETUP_NACK_TEST_CKT_BUSY = 17, /* Q.850 value */
+ SIGBOOST_CALL_SETUP_NACK_INVALID_NUMBER = 28, /* Q.850 value */
+ SIGBOOST_CALL_SETUP_CSUPID_DBL_USE = 200, /* unused Q.850 value */
+};
+
+
+enum e_sigboost_huntgroup_values
+{
+ SIGBOOST_HUNTGRP_SEQ_ASC = 0x00, /* sequential with lowest available first */
+ SIGBOOST_HUNTGRP_SEQ_DESC = 0x01, /* sequential with highest available first */
+ SIGBOOST_HUNTGRP_RR_ASC = 0x02, /* round-robin with lowest available first */
+ SIGBOOST_HUNTGRP_RR_DESC = 0x03, /* round-robin with highest available first */
+};
+
+enum e_sigboost_event_info_par_values
+{
+ SIGBOOST_EVI_SPARE = 0x00,
+ SIGBOOST_EVI_ALERTING = 0x01,
+ SIGBOOST_EVI_PROGRESS = 0x02,
+};
+
+enum e_sigboost_progress_flags
+{
+ SIGBOOST_PROGRESS_RING = (1 << 0),
+ SIGBOOST_PROGRESS_MEDIA = (1 << 1)
+};
+
+#define MAX_DIALED_DIGITS 31
+
+/* Next two defines are used to create the range of values for call_setup_id
+ * in the t_sigboost structure.
+ * 0..((CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN) - 1) */
+#define CORE_MAX_SPANS 200
+#define CORE_MAX_CHAN_PER_SPAN 32
+#define MAX_PENDING_CALLS CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN
+/* 0..(MAX_PENDING_CALLS-1) is range of call_setup_id below */
+
+/* Should only be used by server */
+#define MAX_CALL_SETUP_ID 0xFFFF
+
+#define SIZE_CUSTOM 900
+#define SIZE_RDNIS SIZE_CUSTOM
+
+
+#pragma pack(1)
+
+typedef struct
+{
+ uint8_t capability;
+ uint8_t uil1p;
+} t_sigboost_bearer;
+
+typedef struct
+{
+ uint8_t digits_count;
+ char digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
+ uint8_t npi;
+ uint8_t ton;
+ uint8_t screening_ind;
+ uint8_t presentation_ind;
+}t_sigboost_digits;
+
+typedef struct
+{
+ uint16_t version;
+ uint32_t event_id;
+ /* delete sequence numbers - SCTP does not need them */
+ uint32_t fseqno;
+ uint32_t bseqno;
+ uint16_t call_setup_id;
+ uint32_t trunk_group;
+ uint8_t span;
+ uint8_t chan;
+ uint32_t flags;
+ /* struct timeval tv; */
+ t_sigboost_digits called;
+ t_sigboost_digits calling;
+ t_sigboost_digits rdnis;
+ /* ref. Q.931 Table 4-11 and Q.951 Section 3 */
+ char calling_name[MAX_DIALED_DIGITS + 1];
+ t_sigboost_bearer bearer;
+ uint8_t hunt_group;
+ uint16_t custom_data_size;
+ char custom_data[SIZE_CUSTOM]; /* it's a null terminated string */
+
+} t_sigboost_callstart;
+
+#define called_number_digits_count called.digits_count
+#define called_number_digits called.digits
+#define calling_number_digits_count calling.digits_count
+#define calling_number_digits calling.digits
+#define calling_number_screening_ind calling.screening_ind
+#define calling_number_presentation calling.presentation_ind
+
+#define isup_in_rdnis_size custom_data_size
+#define isup_in_rdnis custom_data
+
+
+#define MIN_SIZE_CALLSTART_MSG sizeof(t_sigboost_callstart) - SIZE_CUSTOM
+
+typedef struct
+{
+ uint16_t version;
+ uint32_t event_id;
+ /* delete sequence numbers - SCTP does not need them */
+ uint32_t fseqno;
+ uint32_t bseqno;
+ uint16_t call_setup_id;
+ uint32_t trunk_group;
+ uint8_t span;
+ uint8_t chan;
+ uint32_t flags;
+ /* struct timeval tv; */
+ uint8_t release_cause;
+} t_sigboost_short;
+#pragma pack()
+
+
+static __inline__ int boost_full_event(int event_id)
+{
+ switch (event_id) {
+ case SIGBOOST_EVENT_CALL_START:
+ case SIGBOOST_EVENT_DIGIT_IN:
+ case SIGBOOST_EVENT_CALL_PROGRESS:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+#endif
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_skel/ftmod_skel.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_skel/ftmod_skel.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_skel/ftmod_skel.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+
+#include "freetdm.h"
+//#include "ftdm_skel.h"
+
+static FIO_CONFIGURE_FUNCTION(skel_configure)
+{
+ return FTDM_FAIL;
+}
+
+static FIO_CONFIGURE_SPAN_FUNCTION(skel_configure_span)
+{
+ return FTDM_FAIL;
+}
+
+static FIO_OPEN_FUNCTION(skel_open)
+{
+ return FTDM_FAIL;
+}
+
+static FIO_CLOSE_FUNCTION(skel_close)
+{
+ return FTDM_FAIL;
+}
+
+static FIO_WAIT_FUNCTION(skel_wait)
+{
+ return FTDM_FAIL;
+}
+
+static FIO_READ_FUNCTION(skel_read)
+{
+ return FTDM_FAIL;
+}
+
+static FIO_WRITE_FUNCTION(skel_write)
+{
+ return FTDM_FAIL;
+}
+
+static FIO_COMMAND_FUNCTION(skel_command)
+{
+ return FTDM_FAIL;
+}
+
+static FIO_SPAN_POLL_EVENT_FUNCTION(skel_poll_event)
+{
+ return FTDM_FAIL;
+}
+
+static FIO_SPAN_NEXT_EVENT_FUNCTION(skel_next_event)
+{
+ return FTDM_FAIL;
+}
+
+static FIO_CHANNEL_DESTROY_FUNCTION(skel_channel_destroy)
+{
+ return FTDM_FAIL;
+}
+
+static FIO_SPAN_DESTROY_FUNCTION(skel_span_destroy)
+{
+ return FTDM_FAIL;
+}
+
+static FIO_GET_ALARMS_FUNCTION(skel_get_alarms)
+{
+ return FTDM_FAIL;
+}
+
+static ftdm_io_interface_t skel_interface;
+
+static FIO_IO_LOAD_FUNCTION(skel_init)
+{
+ assert(fio != NULL);
+ memset(&skel_interface, 0, sizeof(skel_interface));
+
+ skel_interface.name = "skel";
+ skel_interface.configure = skel_configure;
+ skel_interface.configure_span = skel_configure_span;
+ skel_interface.open = skel_open;
+ skel_interface.close = skel_close;
+ skel_interface.wait = skel_wait;
+ skel_interface.read = skel_read;
+ skel_interface.write = skel_write;
+ skel_interface.command = skel_command;
+ skel_interface.poll_event = skel_poll_event;
+ skel_interface.next_event = skel_next_event;
+ skel_interface.channel_destroy = skel_channel_destroy;
+ skel_interface.span_destroy = skel_span_destroy;
+ skel_interface.get_alarms = skel_get_alarms;
+ *fio = &skel_interface;
+
+ return FTDM_SUCCESS;
+}
+
+static FIO_IO_UNLOAD_FUNCTION(skel_destroy)
+{
+ return FTDM_SUCCESS;
+}
+
+
+ftdm_module_t ftdm_module = {
+ "skel",
+ skel_init,
+ skel_destroy,
+};
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,355 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="ftmod_wanpipe"
+ ProjectGUID="{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}"
+ RootNamespace="ftmod_wanpipe"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;"C:\Program Files\Sangoma\include""
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="freetdm.lib libsangoma.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=""$(OutDir)";"C:\Program Files\Sangoma\lib""
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="freetdm.lib libsangoma.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=""$(OutDir)";../../../wanpipe/api/lib/x64"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="freetdm.lib libsangoma.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories=""$(OutDir)";../../../wanpipe/api/lib/x86"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="freetdm.lib libsangoma.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories=""$(OutDir)";../../../wanpipe/api/lib/x64"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\ftmod_wanpipe.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1238 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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:
+ *
+ * Moises Silva <moy@sangoma.com>
+ * David Yat Sin <davidy@sangoma.com>
+ * Nenad Corbic <ncorbic@sangoma.com>
+ *
+ */
+
+#ifdef __sun
+#include <unistd.h>
+#include <stropts.h>
+#endif
+#include "freetdm.h"
+#ifndef __WINDOWS__
+#include <poll.h>
+#include <sys/socket.h>
+#endif
+#include "libsangoma.h"
+
+#if defined(__WINDOWS__)
+/*! Backward compatible defines - current code is all using the old names*/
+#define sangoma_open_tdmapi_span_chan sangoma_open_api_span_chan
+#define sangoma_open_tdmapi_span sangoma_open_api_span
+#define sangoma_open_tdmapi_ctrl sangoma_open_api_ctrl
+#define sangoma_tdm_get_fe_status sangoma_get_fe_status
+#define sangoma_socket_close sangoma_close
+#define sangoma_tdm_get_hw_coding sangoma_get_hw_coding
+#define sangoma_tdm_set_fe_status sangoma_set_fe_status
+#define sangoma_tdm_get_link_status sangoma_get_link_status
+#define sangoma_tdm_flush_bufs sangoma_flush_bufs
+#define sangoma_tdm_cmd_exec sangoma_cmd_exec
+#define sangoma_tdm_read_event sangoma_read_event
+#define sangoma_readmsg_tdm sangoma_readmsg
+#define sangoma_readmsg_socket sangoma_readmsg
+#define sangoma_sendmsg_socket sangoma_writemsg
+#define sangoma_writemsg_tdm sangoma_writemsg
+#define sangoma_create_socket_intr sangoma_open_api_span_chan
+#endif
+
+/*! Starting with libsangoma 3 we can use the new libsangoma waitable API, the poor souls of those using a release where LIBSANGOMA version
+ * is defined but the version is not higher or equal to 3.0.0 will be forced to upgrade
+ * */
+#ifdef LIBSANGOMA_VERSION
+#if LIBSANGOMA_VERSION_CODE < LIBSANGOMA_VERSION(3,0,0)
+#undef LIBSANGOMA_VERSION
+#endif
+#endif
+
+/**
+ * \brief Wanpipe flags
+ */
+typedef enum {
+ WP_RINGING = (1 << 0)
+} wp_flag_t;
+
+/**
+ * \brief Wanpipe globals
+ */
+static struct {
+ uint32_t codec_ms;
+ uint32_t wink_ms;
+ uint32_t flash_ms;
+ uint32_t ring_on_ms;
+ uint32_t ring_off_ms;
+} wp_globals;
+
+/* a bunch of this stuff should go into the wanpipe_tdm_api_iface.h */
+
+FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event);
+FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event);
+
+#define WP_INVALID_SOCKET -1
+
+/**
+ * \brief Poll for event on a wanpipe socket
+ * \param fd Wanpipe socket descriptor
+ * \param timeout Time to wait for event
+ * \param flags Sangoma event flags
+ * \return -1 on failure, wanpipe event flags on success
+ *
+ * a cross platform way to poll on an actual pollset (span and/or list of spans) will probably also be needed for analog
+ * so we can have one analong handler thread that will deal with all the idle analog channels for events
+ * the alternative would be for the driver to provide one socket for all of the oob events for all analog channels
+ */
+static __inline__ int tdmv_api_wait_socket(ftdm_channel_t *ftdmchan, int timeout, int *flags)
+{
+
+#ifdef LIBSANGOMA_VERSION
+ int err;
+ uint32_t inflags = *flags;
+ uint32_t outflags = 0;
+ sangoma_wait_obj_t *sangoma_wait_obj = ftdmchan->mod_data;
+
+ err = sangoma_waitfor(sangoma_wait_obj, inflags, &outflags, timeout);
+ *flags = 0;
+ if (err == SANG_STATUS_SUCCESS) {
+ *flags = outflags;
+ err = 1; /* ideally should be the number of file descriptors with something to read */
+ }
+ if (err == SANG_STATUS_APIPOLL_TIMEOUT) {
+ err = 0;
+ }
+ return err;
+#else
+ struct pollfd pfds[1];
+ int res;
+
+ memset(&pfds[0], 0, sizeof(pfds[0]));
+ pfds[0].fd = ftdmchan->sockfd;
+ pfds[0].events = *flags;
+ res = poll(pfds, 1, timeout);
+ *flags = 0;
+
+ if (pfds[0].revents & POLLERR) {
+ res = -1;
+ }
+
+ if (res > 0) {
+ *flags = pfds[0].revents;
+ }
+
+ return res;
+#endif
+
+}
+
+/**
+ * \brief Opens a sangoma channel socket (TDM API)
+ * \param span Span number
+ * \param chan Channel number
+ * \return 0 on success, wanpipe error code on failure
+ */
+static __inline__ sng_fd_t tdmv_api_open_span_chan(int span, int chan)
+{
+ return sangoma_open_tdmapi_span_chan(span, chan);
+}
+
+#ifdef LIBSANGOMA_VERSION
+static __inline__ sng_fd_t __tdmv_api_open_span_chan(int span, int chan)
+{
+ return __sangoma_open_tdmapi_span_chan(span, chan);
+}
+#endif
+
+static ftdm_io_interface_t wanpipe_interface;
+
+/**
+ * \brief Inverts bit string
+ * \param cas_bits CAS bit string
+ * \return Swapped bits
+ */
+static unsigned char wanpipe_swap_bits(unsigned char cas_bits)
+{
+ unsigned char swapped_bits = 0x0;
+ if (cas_bits & 0x8) {
+ swapped_bits |= 0x1;
+ }
+ if (cas_bits & 0x4) {
+ swapped_bits |= 0x2;
+ }
+ if (cas_bits & 0x2) {
+ swapped_bits |= 0x4;
+ }
+ if (cas_bits & 0x1) {
+ swapped_bits |= 0x8;
+ }
+ return swapped_bits;
+}
+
+/**
+ * \brief Initialises a range of wanpipe channels
+ * \param span FreeTDM span
+ * \param spanno Wanpipe span number
+ * \param start Initial wanpipe channel number
+ * \param end Final wanpipe channel number
+ * \param type FreeTDM channel type
+ * \param name FreeTDM span name
+ * \param number FreeTDM span number
+ * \param cas_bits CAS bits
+ * \return number of spans configured
+ */
+static unsigned wp_open_range(ftdm_span_t *span, unsigned spanno, unsigned start, unsigned end, ftdm_chan_type_t type, char *name, char *number, unsigned char cas_bits)
+{
+ unsigned configured = 0, x;
+#ifdef LIBSANGOMA_VERSION
+ sangoma_status_t sangstatus;
+ sangoma_wait_obj_t *sangoma_wait_obj;
+#endif
+
+ if (type == FTDM_CHAN_TYPE_CAS) {
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring Wanpipe CAS channels with abcd == 0x%X\n", cas_bits);
+ }
+ for(x = start; x < end; x++) {
+ ftdm_channel_t *chan;
+ ftdm_socket_t sockfd = WP_INVALID_SOCKET;
+ const char *dtmf = "none";
+ if (!strncasecmp(span->name, "smg_prid_nfas", 8) && span->trunk_type == FTDM_TRUNK_T1 && x == 24) {
+#ifdef LIBSANGOMA_VERSION
+ sockfd = __tdmv_api_open_span_chan(spanno, x);
+#else
+ ftdm_log(FTDM_LOG_ERROR, "span %d channel %d cannot be configured as smg_prid_nfas, you need to compile freetdm with newer libsangoma\n", spanno, x);
+#endif
+ } else {
+ sockfd = tdmv_api_open_span_chan(spanno, x);
+ }
+
+ if (sockfd == WP_INVALID_SOCKET) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to open wanpipe device span %d channel %d\n", spanno, x);
+ continue;
+ }
+
+ if (ftdm_span_add_channel(span, sockfd, type, &chan) == FTDM_SUCCESS) {
+ wanpipe_tdm_api_t tdm_api;
+ memset(&tdm_api, 0, sizeof(tdm_api));
+#ifdef LIBSANGOMA_VERSION
+ /* we need SANGOMA_DEVICE_WAIT_OBJ_SIG and not SANGOMA_DEVICE_WAIT_OBJ alone because we need to call
+ * sangoma_wait_obj_sig to wake up any I/O waiters when closing the channel (typically on ftdm shutdown)
+ * this adds an extra pair of file descriptors to the waitable object
+ * */
+ sangstatus = sangoma_wait_obj_create(&sangoma_wait_obj, sockfd, SANGOMA_DEVICE_WAIT_OBJ_SIG);
+ if (sangstatus != SANG_STATUS_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "failure create waitable object for s%dc%d\n", spanno, x);
+ continue;
+ }
+ chan->mod_data = sangoma_wait_obj;
+#endif
+
+ chan->physical_span_id = spanno;
+ chan->physical_chan_id = x;
+ chan->rate = 8000;
+
+ if (type == FTDM_CHAN_TYPE_FXS || type == FTDM_CHAN_TYPE_FXO || type == FTDM_CHAN_TYPE_B) {
+ int err;
+
+ dtmf = "software";
+
+ /* FIXME: Handle Error Condition Check for return code */
+ err = sangoma_tdm_get_hw_coding(chan->sockfd, &tdm_api);
+
+ if (tdm_api.wp_tdm_cmd.hw_tdm_coding) {
+ chan->native_codec = chan->effective_codec = FTDM_CODEC_ALAW;
+ } else {
+ chan->native_codec = chan->effective_codec = FTDM_CODEC_ULAW;
+ }
+
+ //err = sangoma_tdm_get_hw_dtmf(chan->sockfd, &tdm_api);
+ //if (err > 0) {
+ err = sangoma_tdm_enable_dtmf_events(chan->sockfd, &tdm_api);
+ if (err == 0) {
+ ftdm_channel_set_feature(chan, FTDM_CHANNEL_FEATURE_DTMF_DETECT);
+ dtmf = "hardware";
+ }
+ //}
+ }
+
+#ifdef LIBSANGOMA_VERSION
+ if (type == FTDM_CHAN_TYPE_FXS) {
+ if (sangoma_tdm_disable_ring_trip_detect_events(chan->sockfd, &tdm_api)) {
+ /* we had problems of on-hook/off-hook detection due to how ring trip events were handled
+ * if this fails, I believe we will still work ok as long as we dont handle them incorrectly */
+ ftdm_log(FTDM_LOG_WARNING, "Failed to disable ring trip events in channel s%dc%d\n", spanno, x);
+ }
+ }
+#endif
+#if 0
+ if (type == FTDM_CHAN_TYPE_FXS || type == FTDM_CHAN_TYPE_FXO) {
+ /* Enable FLASH/Wink Events */
+ int err=sangoma_set_rm_rxflashtime(chan->sockfd, &tdm_api, wp_globals.flash_ms);
+ if (err == 0) {
+ ftdm_log(FTDM_LOG_ERROR, "flash enabled s%dc%d\n", spanno, x);
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "flash disabled s%dc%d\n", spanno, x);
+ }
+ }
+#endif
+
+ if (type == FTDM_CHAN_TYPE_CAS || type == FTDM_CHAN_TYPE_EM) {
+#ifdef LIBSANGOMA_VERSION
+ sangoma_tdm_write_rbs(chan->sockfd,&tdm_api,chan->physical_chan_id, wanpipe_swap_bits(cas_bits));
+
+ /* this should probably be done for old libsangoma but I am not sure if the API is available and I'm lazy to check,
+ The poll rate is hard coded to 100 per second (done in the driver, is the max rate of polling allowed by wanpipe)
+ */
+ if (sangoma_tdm_enable_rbs_events(chan->sockfd, &tdm_api, 100)) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to enable RBS/CAS events in device %d:%d fd:%d\n", chan->span_id, chan->chan_id, sockfd);
+ continue;
+ }
+ /* probably done by the driver but lets write defensive code this time */
+ sangoma_flush_bufs(chan->sockfd, &tdm_api);
+#else
+ /*
+ * With wanpipe 3.4.4.2 I get failure even though the events are enabled, /var/log/messages said:
+ * wanpipe4: WARNING: Event type 9 is already pending!
+ * wanpipe4: Failed to add new fe event 09 ch_map=FFFFFFFF!
+ * may be we should not send an error until that is fixed in the driver
+ */
+ if (sangoma_tdm_enable_rbs_events(chan->sockfd, &tdm_api, 100)) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to enable RBS/CAS events in device %d:%d fd:%d\n", chan->span_id, chan->chan_id, sockfd);
+ }
+ /* probably done by the driver but lets write defensive code this time */
+ sangoma_tdm_flush_bufs(chan->sockfd, &tdm_api);
+ sangoma_tdm_write_rbs(chan->sockfd,&tdm_api, wanpipe_swap_bits(cas_bits));
+#endif
+ }
+
+ if (!ftdm_strlen_zero(name)) {
+ ftdm_copy_string(chan->chan_name, name, sizeof(chan->chan_name));
+ }
+
+ if (!ftdm_strlen_zero(number)) {
+ ftdm_copy_string(chan->chan_number, number, sizeof(chan->chan_number));
+ }
+ configured++;
+ ftdm_log(FTDM_LOG_INFO, "configuring device s%dc%d as FreeTDM device %d:%d fd:%d DTMF: %s\n",
+ spanno, x, chan->span_id, chan->chan_id, sockfd, dtmf);
+
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "ftdm_span_add_channel failed for wanpipe span %d channel %d\n", spanno, x);
+ }
+ }
+
+ return configured;
+}
+
+/**
+ * \brief Process configuration variable for a Wanpipe profile
+ * \param category Wanpipe profile name
+ * \param var Variable name
+ * \param val Variable value
+ * \param lineno Line number from configuration file
+ * \return Success
+ */
+static FIO_CONFIGURE_FUNCTION(wanpipe_configure)
+{
+ int num;
+
+ if (!strcasecmp(category, "defaults")) {
+ if (!strcasecmp(var, "codec_ms")) {
+ num = atoi(val);
+ if (num < 10 || num > 60) {
+ ftdm_log(FTDM_LOG_WARNING, "invalid codec ms at line %d\n", lineno);
+ } else {
+ wp_globals.codec_ms = num;
+ }
+ } else if (!strcasecmp(var, "wink_ms")) {
+ num = atoi(val);
+ if (num < 50 || num > 3000) {
+ ftdm_log(FTDM_LOG_WARNING, "invalid wink ms at line %d\n", lineno);
+ } else {
+ wp_globals.wink_ms = num;
+ }
+ } else if (!strcasecmp(var, "flash_ms")) {
+ num = atoi(val);
+ if (num < 50 || num > 3000) {
+ ftdm_log(FTDM_LOG_WARNING, "invalid flash ms at line %d\n", lineno);
+ } else {
+ wp_globals.flash_ms = num;
+ }
+ } else if (!strcasecmp(var, "ring_on_ms")) {
+ num = atoi(val);
+ if (num < 500 || num > 5000) {
+ ftdm_log(FTDM_LOG_WARNING, "invalid ring_on_ms at line %d (valid range 500 to 5000)\n", lineno);
+ } else {
+ wp_globals.ring_on_ms = num;
+ }
+ } else if (!strcasecmp(var, "ring_off_ms")) {
+ num = atoi(val);
+ if (num < 500 || num > 5000) {
+ ftdm_log(FTDM_LOG_WARNING, "invalid ring_off_ms at line %d (valid range 500 to 5000)\n", lineno);
+ } else {
+ wp_globals.ring_off_ms = num;
+ }
+ }
+ }
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Initialises an freetdm Wanpipe span from a configuration string
+ * \param span FreeTDM span
+ * \param str Configuration string
+ * \param type FreeTDM span type
+ * \param name FreeTDM span name
+ * \param number FreeTDM span number
+ * \return Success or failure
+ */
+static FIO_CONFIGURE_SPAN_FUNCTION(wanpipe_configure_span)
+{
+ int items, i;
+ char *mydata, *item_list[10];
+ char *sp, *ch, *mx;
+ unsigned char cas_bits = 0;
+ int channo;
+ int spanno;
+ int top = 0;
+ unsigned configured = 0;
+
+ assert(str != NULL);
+
+
+ mydata = ftdm_strdup(str);
+ assert(mydata != NULL);
+
+
+ items = ftdm_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
+
+ for(i = 0; i < items; i++) {
+ sp = item_list[i];
+ if ((ch = strchr(sp, ':'))) {
+ *ch++ = '\0';
+ }
+
+ if (!(sp && ch)) {
+ ftdm_log(FTDM_LOG_ERROR, "No valid wanpipe span and channel was specified\n");
+ continue;
+ }
+
+ channo = atoi(ch);
+ spanno = atoi(sp);
+
+ if (channo < 0) {
+ ftdm_log(FTDM_LOG_ERROR, "Invalid channel number %d\n", channo);
+ continue;
+ }
+
+ if (spanno < 0) {
+ ftdm_log(FTDM_LOG_ERROR, "Invalid span number %d\n", channo);
+ continue;
+ }
+
+ if ((mx = strchr(ch, '-'))) {
+ mx++;
+ top = atoi(mx) + 1;
+ } else {
+ top = channo + 1;
+ }
+
+
+ if (top < 0) {
+ ftdm_log(FTDM_LOG_ERROR, "Invalid range number %d\n", top);
+ continue;
+ }
+ if (FTDM_CHAN_TYPE_CAS == type && ftdm_config_get_cas_bits(ch, &cas_bits)) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to get CAS bits in CAS channel\n");
+ continue;
+ }
+ configured += wp_open_range(span, spanno, channo, top, type, name, number, cas_bits);
+
+ }
+
+ ftdm_safe_free(mydata);
+
+ return configured;
+}
+
+/**
+ * \brief Opens Wanpipe channel
+ * \param ftdmchan Channel to open
+ * \return Success or failure
+ */
+static FIO_OPEN_FUNCTION(wanpipe_open)
+{
+
+ wanpipe_tdm_api_t tdm_api;
+
+ memset(&tdm_api,0,sizeof(tdm_api));
+ sangoma_tdm_flush_bufs(ftdmchan->sockfd, &tdm_api);
+#ifdef LIBSANGOMA_VERSION
+ sangoma_flush_event_bufs(ftdmchan->sockfd, &tdm_api);
+#endif
+
+ if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921 || ftdmchan->type == FTDM_CHAN_TYPE_DQ931) {
+ ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_NONE;
+ } else {
+ ftdmchan->effective_codec = ftdmchan->native_codec;
+
+ sangoma_tdm_set_usr_period(ftdmchan->sockfd, &tdm_api, wp_globals.codec_ms);
+
+ ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_INTERVAL);
+ ftdmchan->effective_interval = ftdmchan->native_interval = wp_globals.codec_ms;
+ ftdmchan->packet_len = ftdmchan->native_interval * 8;
+ }
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Closes Wanpipe channel
+ * \param ftdmchan Channel to close
+ * \return Success
+ */
+static FIO_CLOSE_FUNCTION(wanpipe_close)
+{
+#ifdef LIBSANGOMA_VERSION
+ sangoma_wait_obj_t *waitobj = ftdmchan->mod_data;
+ /* kick any I/O waiters */
+ sangoma_wait_obj_signal(waitobj);
+#endif
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Executes an FreeTDM command on a Wanpipe channel
+ * \param ftdmchan Channel to execute command on
+ * \param command FreeTDM command to execute
+ * \param obj Object (unused)
+ * \return Success or failure
+ */
+static FIO_COMMAND_FUNCTION(wanpipe_command)
+{
+ wanpipe_tdm_api_t tdm_api;
+ int err = 0;
+
+ memset(&tdm_api, 0, sizeof(tdm_api));
+
+ switch(command) {
+ case FTDM_COMMAND_OFFHOOK:
+ {
+ err=sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api);
+ if (err) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "OFFHOOK Failed");
+ return FTDM_FAIL;
+ }
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
+ }
+ break;
+ case FTDM_COMMAND_ONHOOK:
+ {
+ err=sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
+ if (err) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ONHOOK Failed");
+ return FTDM_FAIL;
+ }
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
+ }
+ break;
+ case FTDM_COMMAND_GENERATE_RING_ON:
+ {
+ err=sangoma_tdm_txsig_start(ftdmchan->sockfd,&tdm_api);
+ if (err) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring Failed");
+ return FTDM_FAIL;
+ }
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
+ ftdm_set_pflag_locked(ftdmchan, WP_RINGING);
+ ftdmchan->ring_time = ftdm_current_time_in_ms() + wp_globals.ring_on_ms;
+ }
+ break;
+ case FTDM_COMMAND_GENERATE_RING_OFF:
+ {
+ err=sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api);
+ if (err) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring-off Failed");
+ return FTDM_FAIL;
+ }
+ ftdm_clear_pflag_locked(ftdmchan, WP_RINGING);
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
+ }
+ break;
+ case FTDM_COMMAND_GET_INTERVAL:
+ {
+ err=sangoma_tdm_get_usr_period(ftdmchan->sockfd, &tdm_api);
+ if (err > 0 ) {
+ FTDM_COMMAND_OBJ_INT = err;
+ err=0;
+ }
+ }
+ break;
+ case FTDM_COMMAND_ENABLE_ECHOCANCEL:
+ {
+ err=sangoma_tdm_enable_hwec(ftdmchan->sockfd, &tdm_api);
+ if (err) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Enable Failed");
+ return FTDM_FAIL;
+ }
+ }
+ break;
+ case FTDM_COMMAND_DISABLE_ECHOCANCEL:
+ {
+ err=sangoma_tdm_disable_hwec(ftdmchan->sockfd, &tdm_api);
+ if (err) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Disable Failed");
+ return FTDM_FAIL;
+ }
+ }
+ break;
+ case FTDM_COMMAND_ENABLE_LOOP:
+ {
+#ifdef WP_API_FEATURE_LOOP
+ err=sangoma_tdm_enable_loop(ftdmchan->sockfd, &tdm_api);
+ if (err) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Loop Enable Failed");
+ return FTDM_FAIL;
+ }
+#endif
+ }
+ case FTDM_COMMAND_DISABLE_LOOP:
+ {
+#ifdef WP_API_FEATURE_LOOP
+ err=sangoma_tdm_disable_loop(ftdmchan->sockfd, &tdm_api);
+ if (err) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Loop Disable Failed");
+ return FTDM_FAIL;
+ }
+#endif
+ }
+ case FTDM_COMMAND_SET_INTERVAL:
+ {
+ err=sangoma_tdm_set_usr_period(ftdmchan->sockfd, &tdm_api, FTDM_COMMAND_OBJ_INT);
+ ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8);
+ }
+ break;
+ case FTDM_COMMAND_SET_CAS_BITS:
+ {
+#ifdef LIBSANGOMA_VERSION
+ err = sangoma_tdm_write_rbs(ftdmchan->sockfd,&tdm_api, ftdmchan->physical_chan_id, wanpipe_swap_bits(FTDM_COMMAND_OBJ_INT));
+#else
+ err = sangoma_tdm_write_rbs(ftdmchan->sockfd, &tdm_api, wanpipe_swap_bits(FTDM_COMMAND_OBJ_INT));
+#endif
+ }
+ break;
+ case FTDM_COMMAND_GET_CAS_BITS:
+ {
+#ifdef LIBSANGOMA_VERSION
+ unsigned char rbsbits;
+ err = sangoma_tdm_read_rbs(ftdmchan->sockfd, &tdm_api, ftdmchan->physical_chan_id, &rbsbits);
+ if (!err) {
+ FTDM_COMMAND_OBJ_INT = wanpipe_swap_bits(rbsbits);
+ }
+#else
+ // does sangoma_tdm_read_rbs is available here?
+ FTDM_COMMAND_OBJ_INT = ftdmchan->rx_cas_bits;
+#endif
+ }
+ break;
+ case FTDM_COMMAND_SET_LINK_STATUS:
+ {
+ ftdm_channel_hw_link_status_t status = FTDM_COMMAND_OBJ_INT;
+ char sangoma_status = status == FTDM_HW_LINK_CONNECTED ? FE_CONNECTED : FE_DISCONNECTED;
+ err = sangoma_tdm_set_fe_status(ftdmchan->sockfd, &tdm_api, sangoma_status);
+ }
+ break;
+ case FTDM_COMMAND_GET_LINK_STATUS:
+ {
+ unsigned char sangoma_status = 0;
+ err = sangoma_tdm_get_fe_status(ftdmchan->sockfd, &tdm_api, &sangoma_status);
+ if (!err) {
+ FTDM_COMMAND_OBJ_INT = sangoma_status == FE_CONNECTED ? FTDM_HW_LINK_CONNECTED : FTDM_HW_LINK_DISCONNECTED;
+ }
+ }
+ break;
+ default:
+ break;
+ };
+
+ if (err) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+ return FTDM_FAIL;
+ }
+
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Reads data from a Wanpipe channel
+ * \param ftdmchan Channel to read from
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success, failure or timeout
+ */
+static FIO_READ_FUNCTION(wanpipe_read)
+{
+ int rx_len = 0;
+ wp_tdm_api_rx_hdr_t hdrframe;
+
+ memset(&hdrframe, 0, sizeof(hdrframe));
+
+ rx_len = sangoma_readmsg_tdm(ftdmchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (int)*datalen,0);
+ *datalen = rx_len;
+
+ if (rx_len == 0 || rx_len == -17) {
+ return FTDM_TIMEOUT;
+ }
+
+ if (rx_len < 0) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+ return FTDM_FAIL;
+ }
+
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Writes data to a Wanpipe channel
+ * \param ftdmchan Channel to write to
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success or failure
+ */
+static FIO_WRITE_FUNCTION(wanpipe_write)
+{
+ int bsent;
+ wp_tdm_api_tx_hdr_t hdrframe;
+
+ /* Do we even need the headerframe here? on windows, we don't even pass it to the driver */
+ memset(&hdrframe, 0, sizeof(hdrframe));
+ if (*datalen == 0) {
+ return FTDM_SUCCESS;
+ }
+ bsent = sangoma_writemsg_tdm(ftdmchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (unsigned short)(*datalen),0);
+
+ /* should we be checking if bsent == *datalen here? */
+ if (bsent > 0) {
+ *datalen = bsent;
+ return FTDM_SUCCESS;
+ }
+
+ return FTDM_FAIL;
+}
+
+/**
+ * \brief Waits for an event on a Wanpipe channel
+ * \param ftdmchan Channel to open
+ * \param flags Type of event to wait for
+ * \param to Time to wait (in ms)
+ * \return Success, failure or timeout
+ */
+
+static FIO_WAIT_FUNCTION(wanpipe_wait)
+{
+ int32_t inflags = 0;
+ int result;
+
+ if (*flags & FTDM_READ) {
+ inflags |= POLLIN;
+ }
+
+ if (*flags & FTDM_WRITE) {
+ inflags |= POLLOUT;
+ }
+
+ if (*flags & FTDM_EVENTS) {
+ inflags |= POLLPRI;
+ }
+
+ result = tdmv_api_wait_socket(ftdmchan, to, &inflags);
+
+ *flags = FTDM_NO_FLAGS;
+
+ if (result < 0){
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Poll failed");
+ return FTDM_FAIL;
+ }
+
+ if (result == 0) {
+ return FTDM_TIMEOUT;
+ }
+
+ if (inflags & POLLIN) {
+ *flags |= FTDM_READ;
+ }
+
+ if (inflags & POLLOUT) {
+ *flags |= FTDM_WRITE;
+ }
+
+ if (inflags & POLLPRI) {
+ *flags |= FTDM_EVENTS;
+ }
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Checks for events on a Wanpipe span
+ * \param span Span to check for events
+ * \param ms Time to wait for event
+ * \return Success if event is waiting or failure if not
+ */
+FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event)
+{
+#ifdef LIBSANGOMA_VERSION
+ sangoma_status_t sangstatus;
+ sangoma_wait_obj_t *pfds[FTDM_MAX_CHANNELS_SPAN] = { 0 };
+ uint32_t inflags[FTDM_MAX_CHANNELS_SPAN];
+ uint32_t outflags[FTDM_MAX_CHANNELS_SPAN];
+#else
+ struct pollfd pfds[FTDM_MAX_CHANNELS_SPAN];
+#endif
+ uint32_t i, j = 0, k = 0, l = 0;
+ int r;
+
+ for(i = 1; i <= span->chan_count; i++) {
+ ftdm_channel_t *ftdmchan = span->channels[i];
+#ifdef LIBSANGOMA_VERSION
+ if (!ftdmchan->mod_data) {
+ continue; /* should never happen but happens when shutting down */
+ }
+ pfds[j] = ftdmchan->mod_data;
+ inflags[j] = POLLPRI;
+#else
+ memset(&pfds[j], 0, sizeof(pfds[j]));
+ pfds[j].fd = span->channels[i]->sockfd;
+ pfds[j].events = POLLPRI;
+#endif
+
+ /* The driver probably should be able to do this wink/flash/ringing by itself this is sort of a hack to make it work! */
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_FLASH)) {
+ l = 5;
+ }
+
+ j++;
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RINGING)) {
+ l = 5;
+ }
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RINGING) && ftdm_current_time_in_ms() >= ftdmchan->ring_time) {
+ wanpipe_tdm_api_t tdm_api;
+ int err;
+ memset(&tdm_api, 0, sizeof(tdm_api));
+ if (ftdm_test_pflag(ftdmchan, WP_RINGING)) {
+ err = sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api);
+ if (err) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring-off Failed");
+ ftdm_log(FTDM_LOG_ERROR, "sangoma_tdm_txsig_offhook failed\n");
+ return FTDM_FAIL;
+ }
+ ftdm_clear_pflag_locked(ftdmchan, WP_RINGING);
+ ftdmchan->ring_time = ftdm_current_time_in_ms() + wp_globals.ring_off_ms;
+ } else {
+ err=sangoma_tdm_txsig_start(ftdmchan->sockfd,&tdm_api);
+ if (err) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring Failed");
+ ftdm_log(FTDM_LOG_ERROR, "sangoma_tdm_txsig_start failed\n");
+ return FTDM_FAIL;
+ }
+ ftdm_set_pflag_locked(ftdmchan, WP_RINGING);
+ ftdmchan->ring_time = ftdm_current_time_in_ms() + wp_globals.ring_on_ms;
+ }
+ }
+ }
+
+ if (l) {
+ ms = l;
+ }
+#ifdef LIBSANGOMA_VERSION
+ sangstatus = sangoma_waitfor_many(pfds, inflags, outflags, j, ms);
+ if (SANG_STATUS_APIPOLL_TIMEOUT == sangstatus) {
+ r = 0;
+ } else if (SANG_STATUS_SUCCESS == sangstatus) {
+ r = 1; /* hopefully we never need how many changed -_- */
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "sangoma_waitfor_many failed: %d, %s\n", sangstatus, strerror(errno));
+ r = -1;
+ }
+#else
+ r = poll(pfds, j, ms);
+#endif
+
+ if (r == 0) {
+ return l ? FTDM_SUCCESS : FTDM_TIMEOUT;
+ } else if (r < 0) {
+ snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+ return FTDM_FAIL;
+ }
+
+ for(i = 1; i <= span->chan_count; i++) {
+ ftdm_channel_t *ftdmchan = span->channels[i];
+
+#ifdef LIBSANGOMA_VERSION
+ if (outflags[i-1] & POLLPRI) {
+#else
+ if (pfds[i-1].revents & POLLPRI) {
+#endif
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_EVENT);
+ ftdmchan->last_event_time = ftdm_current_time_in_ms();
+ k++;
+ }
+ }
+ /* when k is 0 it might be that an async wanpipe device signal was delivered */
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Gets alarms from a Wanpipe Channel
+ * \param ftdmchan Channel to get alarms from
+ * \return Success or failure
+ */
+static FIO_GET_ALARMS_FUNCTION(wanpipe_get_alarms)
+{
+ wanpipe_tdm_api_t tdm_api;
+ unsigned int alarms = 0;
+ int err;
+
+ memset(&tdm_api,0,sizeof(tdm_api));
+
+#ifdef LIBSANGOMA_VERSION
+ if ((err = sangoma_tdm_get_fe_alarms(ftdmchan->sockfd, &tdm_api, &alarms))) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ioctl failed (%s)", strerror(errno));
+ snprintf(ftdmchan->span->last_error, sizeof(ftdmchan->span->last_error), "ioctl failed (%s)", strerror(errno));
+ return FTDM_FAIL;
+ }
+#else
+ if ((err = sangoma_tdm_get_fe_alarms(ftdmchan->sockfd, &tdm_api)) < 0){
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ioctl failed (%s)", strerror(errno));
+ snprintf(ftdmchan->span->last_error, sizeof(ftdmchan->span->last_error), "ioctl failed (%s)", strerror(errno));
+ return FTDM_FAIL;
+ }
+ alarms = tdm_api.wp_tdm_cmd.fe_alarms;
+#endif
+ ftdmchan->alarm_flags = FTDM_ALARM_NONE;
+
+ if (alarms & WAN_TE_BIT_ALARM_RED) {
+ ftdmchan->alarm_flags |= FTDM_ALARM_RED;
+ alarms &= ~WAN_TE_BIT_ALARM_RED;
+ }
+
+ if (alarms & WAN_TE_BIT_ALARM_AIS) {
+ ftdmchan->alarm_flags |= FTDM_ALARM_AIS;
+ ftdmchan->alarm_flags |= FTDM_ALARM_BLUE;
+ alarms &= ~WAN_TE_BIT_ALARM_AIS;
+ }
+
+ if (alarms & WAN_TE_BIT_ALARM_RAI) {
+ ftdmchan->alarm_flags |= FTDM_ALARM_RAI;
+ ftdmchan->alarm_flags |= FTDM_ALARM_YELLOW;
+ alarms &= ~WAN_TE_BIT_ALARM_RAI;
+ }
+
+ /* still missing to map:
+ * FTDM_ALARM_RECOVER
+ * FTDM_ALARM_LOOPBACK
+ * FTDM_ALARM_NOTOPEN
+ * */
+
+ /* if we still have alarms that we did not map, set the general alarm */
+ if (alarms) {
+ ftdm_log(FTDM_LOG_DEBUG, "Unmapped wanpipe alarms: %d\n", alarms);
+ ftdmchan->alarm_flags |= FTDM_ALARM_GENERAL;
+ }
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Retrieves an event from a wanpipe span
+ * \param span Span to retrieve event from
+ * \param event FreeTDM event to return
+ * \return Success or failure
+ */
+FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event)
+{
+ uint32_t i,err;
+ ftdm_oob_event_t event_id;
+ for(i = 1; i <= span->chan_count; i++) {
+ if (span->channels[i]->last_event_time && !ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
+ uint32_t diff = (uint32_t)(ftdm_current_time_in_ms() - span->channels[i]->last_event_time);
+ /* XX printf("%u %u %u\n", diff, (unsigned)ftdm_current_time_in_ms(), (unsigned)span->channels[i]->last_event_time); */
+ if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_WINK)) {
+ if (diff > wp_globals.wink_ms) {
+ ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
+ ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
+ ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
+ event_id = FTDM_OOB_OFFHOOK;
+ goto event;
+ }
+ }
+
+ if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_FLASH)) {
+ if (diff > wp_globals.flash_ms) {
+ ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
+ ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
+ ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
+ event_id = FTDM_OOB_ONHOOK;
+
+ if (span->channels[i]->type == FTDM_CHAN_TYPE_FXO) {
+ ftdm_channel_t *ftdmchan = span->channels[i];
+ wanpipe_tdm_api_t tdm_api;
+ memset(&tdm_api, 0, sizeof(tdm_api));
+
+ sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
+ }
+ goto event;
+ }
+ }
+ }
+ if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
+ wanpipe_tdm_api_t tdm_api;
+ ftdm_channel_t *ftdmchan = span->channels[i];
+ memset(&tdm_api, 0, sizeof(tdm_api));
+ ftdm_clear_flag(span->channels[i], FTDM_CHANNEL_EVENT);
+
+ err = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api);
+ if (err != FTDM_SUCCESS) {
+ snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+ return FTDM_FAIL;
+ }
+
+ ftdm_log(FTDM_LOG_DEBUG, "read wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
+ switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) {
+
+ case WP_TDMAPI_EVENT_LINK_STATUS:
+ {
+ switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
+ case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
+ event_id = FTDM_OOB_ALARM_CLEAR;
+ break;
+ default:
+ event_id = FTDM_OOB_ALARM_TRAP;
+ break;
+ };
+ }
+ break;
+
+ case WP_TDMAPI_EVENT_RXHOOK:
+ {
+ if (span->channels[i]->type == FTDM_CHAN_TYPE_FXS) {
+ event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK;
+ if (event_id == FTDM_OOB_OFFHOOK) {
+ if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_FLASH)) {
+ ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
+ ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
+ event_id = FTDM_OOB_FLASH;
+ goto event;
+ } else {
+ ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
+ }
+ } else {
+ if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_WINK)) {
+ ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
+ ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
+ event_id = FTDM_OOB_WINK;
+ goto event;
+ } else {
+ ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
+ }
+ }
+ continue;
+ } else {
+ int err;
+ ftdm_channel_t *ftdmchan = span->channels[i];
+ err=sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
+ if (err) {
+ snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "ONHOOK Failed");
+ return FTDM_FAIL;
+ }
+ event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP;
+ }
+ }
+ break;
+ case WP_TDMAPI_EVENT_RING_DETECT:
+ {
+ event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP;
+ }
+ break;
+ /*
+ disabled this ones when configuring, we don't need them, do we?
+ case WP_TDMAPI_EVENT_RING_TRIP_DETECT:
+ {
+ event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK;
+ }
+ break;
+ */
+ case WP_TDMAPI_EVENT_RBS:
+ {
+ event_id = FTDM_OOB_CAS_BITS_CHANGE;
+ span->channels[i]->rx_cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
+ }
+ break;
+ case WP_TDMAPI_EVENT_DTMF:
+ {
+ char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 };
+ event_id = FTDM_OOB_NOOP;
+
+ if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) {
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
+ }
+
+ if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
+ ftdm_log(FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
+ ftdm_channel_queue_dtmf(ftdmchan, tmp_dtmf);
+ }
+ }
+ }
+ break;
+ case WP_TDMAPI_EVENT_ALARM:
+ {
+ ftdm_log(FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api.wp_tdm_cmd.event.wp_api_event_alarm);
+ event_id = FTDM_OOB_ALARM_TRAP;
+ }
+ break;
+ default:
+ {
+ ftdm_log(FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
+ event_id = FTDM_OOB_INVALID;
+ }
+ break;
+ }
+
+ event:
+
+ span->channels[i]->last_event_time = 0;
+ span->event_header.e_type = FTDM_EVENT_OOB;
+ span->event_header.enum_id = event_id;
+ span->event_header.channel = span->channels[i];
+ *event = &span->event_header;
+ return FTDM_SUCCESS;
+ }
+ }
+
+ return FTDM_FAIL;
+
+}
+
+/**
+ * \brief Destroys a Wanpipe Channel
+ * \param ftdmchan Channel to destroy
+ * \return Success
+ */
+static FIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy)
+{
+#ifdef LIBSANGOMA_VERSION
+ if (ftdmchan->mod_data) {
+ sangoma_wait_obj_t *sangoma_wait_obj;
+ sangoma_wait_obj = ftdmchan->mod_data;
+ ftdmchan->mod_data = NULL;
+ sangoma_wait_obj_delete(&sangoma_wait_obj);
+ }
+#endif
+
+ if (ftdmchan->sockfd > -1) {
+ close(ftdmchan->sockfd);
+ ftdmchan->sockfd = WP_INVALID_SOCKET;
+ }
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Loads wanpipe IO module
+ * \param fio FreeTDM IO interface
+ * \return Success
+ */
+static FIO_IO_LOAD_FUNCTION(wanpipe_init)
+{
+ assert(fio != NULL);
+ memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
+
+ wp_globals.codec_ms = 20;
+ wp_globals.wink_ms = 150;
+ wp_globals.flash_ms = 750;
+ wp_globals.ring_on_ms = 2000;
+ wp_globals.ring_off_ms = 4000;
+ wanpipe_interface.name = "wanpipe";
+ wanpipe_interface.configure_span = wanpipe_configure_span;
+ wanpipe_interface.configure = wanpipe_configure;
+ wanpipe_interface.open = wanpipe_open;
+ wanpipe_interface.close = wanpipe_close;
+ wanpipe_interface.command = wanpipe_command;
+ wanpipe_interface.wait = wanpipe_wait;
+ wanpipe_interface.read = wanpipe_read;
+ wanpipe_interface.write = wanpipe_write;
+ wanpipe_interface.poll_event = wanpipe_poll_event;
+ wanpipe_interface.next_event = wanpipe_next_event;
+ wanpipe_interface.channel_destroy = wanpipe_channel_destroy;
+ wanpipe_interface.get_alarms = wanpipe_get_alarms;
+ *fio = &wanpipe_interface;
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Unloads wanpipe IO module
+ * \return Success
+ */
+static FIO_IO_UNLOAD_FUNCTION(wanpipe_destroy)
+{
+ memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief FreeTDM wanpipe IO module definition
+ */
+EX_DECLARE_DATA ftdm_module_t ftdm_module = {
+ "wanpipe",
+ wanpipe_init,
+ wanpipe_destroy,
+};
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4
+ */
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ozmod_wanpipe.2005.vcproj (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ozmod_wanpipe.2005.vcproj (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ozmod_wanpipe.2005.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,196 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ftmod_wanpipe"
+ ProjectGUID="{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}"
+ RootNamespace="ftmod_wanpipe"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="freetdm.lib libsangoma.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=""$(OutDir)";../../../wanpipe/api/lib/x86"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="freetdm.lib libsangoma.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories=""$(OutDir)";../../../wanpipe/api/lib/x86"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\ftmod_wanpipe.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/wanpipe_tdm_api_iface.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/wanpipe_tdm_api_iface.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/wanpipe_tdm_api_iface.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,351 @@
+/*****************************************************************************
+* wanpipe_tdm_api_iface.h
+*
+* WANPIPE(tm) AFT TE1 Hardware Support
+*
+* Authors: Nenad Corbic <ncorbic@sangoma.com>
+*
+* Copyright (c) 2007 - 08, Sangoma Technologies
+* 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 <organization> 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 <copyright holder> ``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 <copyright holder> 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.
+
+* ============================================================================
+* Oct 04, 2005 Nenad Corbic Initial version.
+*
+* Jul 25, 2006 David Rokhvarg <davidr@sangoma.com> Ported to Windows.
+*****************************************************************************/
+
+#ifndef __WANPIPE_TDM_API_IFACE_H_
+#define __WANPIPE_TDM_API_IFACE_H_
+
+
+#if defined(__WINDOWS__)
+typedef HANDLE sng_fd_t;
+#else
+typedef int sng_fd_t;
+#endif
+
+/* Indicate to library that new features exist */
+#define WP_TDM_FEATURE_DTMF_EVENTS 1
+#define WP_TDM_FEATURE_FE_ALARM 1
+#define WP_TDM_FEATURE_EVENTS 1
+#define WP_TDM_FEATURE_LINK_STATUS 1
+
+enum wanpipe_tdm_api_cmds {
+
+ SIOC_WP_TDM_GET_USR_MTU_MRU, /* 0x00 */
+
+ SIOC_WP_TDM_SET_USR_PERIOD, /* 0x01 */
+ SIOC_WP_TDM_GET_USR_PERIOD, /* 0x02 */
+
+ SIOC_WP_TDM_SET_HW_MTU_MRU, /* 0x03 */
+ SIOC_WP_TDM_GET_HW_MTU_MRU, /* 0x04 */
+
+ SIOC_WP_TDM_SET_CODEC, /* 0x05 */
+ SIOC_WP_TDM_GET_CODEC, /* 0x06 */
+
+ SIOC_WP_TDM_SET_POWER_LEVEL, /* 0x07 */
+ SIOC_WP_TDM_GET_POWER_LEVEL, /* 0x08 */
+
+ SIOC_WP_TDM_TOGGLE_RX, /* 0x09 */
+ SIOC_WP_TDM_TOGGLE_TX, /* 0x0A */
+
+ SIOC_WP_TDM_GET_HW_CODING, /* 0x0B */
+ SIOC_WP_TDM_SET_HW_CODING, /* 0x0C */
+
+ SIOC_WP_TDM_GET_FULL_CFG, /* 0x0D */
+
+ SIOC_WP_TDM_SET_EC_TAP, /* 0x0E */
+ SIOC_WP_TDM_GET_EC_TAP, /* 0x0F */
+
+ SIOC_WP_TDM_ENABLE_RBS_EVENTS, /* 0x10 */
+ SIOC_WP_TDM_DISABLE_RBS_EVENTS, /* 0x11 */
+ SIOC_WP_TDM_WRITE_RBS_BITS, /* 0x12 */
+
+ SIOC_WP_TDM_GET_STATS, /* 0x13 */
+ SIOC_WP_TDM_FLUSH_BUFFERS, /* 0x14 */
+
+ SIOC_WP_TDM_READ_EVENT, /* 0x15 */
+
+ SIOC_WP_TDM_SET_EVENT, /* 0x16 */
+
+ SIOC_WP_TDM_SET_RX_GAINS, /* 0x17 */
+ SIOC_WP_TDM_SET_TX_GAINS, /* 0x18 */
+ SIOC_WP_TDM_CLEAR_RX_GAINS, /* 0x19 */
+ SIOC_WP_TDM_CLEAR_TX_GAINS, /* 0x1A */
+
+ SIOC_WP_TDM_GET_FE_ALARMS, /* 0x1B */
+
+ SIOC_WP_TDM_ENABLE_HWEC, /* 0x1C */
+ SIOC_WP_TDM_DISABLE_HWEC, /* 0x1D */
+
+ SIOC_WP_TDM_SET_FE_STATUS, /* 0x1E */
+ SIOC_WP_TDM_GET_FE_STATUS, /* 0x1F */
+
+ SIOC_WP_TDM_GET_HW_DTMF, /* 0x20 */
+
+ SIOC_WP_TDM_NOTSUPP /* */
+
+};
+
+#define SIOC_WP_TDM_GET_LINK_STATUS SIOC_WP_TDM_GET_FE_STATUS
+
+enum wanpipe_tdm_api_events {
+ WP_TDMAPI_EVENT_NONE,
+ WP_TDMAPI_EVENT_RBS,
+ WP_TDMAPI_EVENT_ALARM,
+ WP_TDMAPI_EVENT_DTMF,
+ WP_TDMAPI_EVENT_RM_DTMF,
+ WP_TDMAPI_EVENT_RXHOOK,
+ WP_TDMAPI_EVENT_RING,
+ WP_TDMAPI_EVENT_RING_DETECT,
+ WP_TDMAPI_EVENT_RING_TRIP_DETECT,
+ WP_TDMAPI_EVENT_TONE,
+ WP_TDMAPI_EVENT_TXSIG_KEWL,
+ WP_TDMAPI_EVENT_TXSIG_START,
+ WP_TDMAPI_EVENT_TXSIG_OFFHOOK,
+ WP_TDMAPI_EVENT_TXSIG_ONHOOK,
+ WP_TDMAPI_EVENT_ONHOOKTRANSFER,
+ WP_TDMAPI_EVENT_SETPOLARITY,
+ WP_TDMAPI_EVENT_BRI_CHAN_LOOPBACK,
+ WP_TDMAPI_EVENT_LINK_STATUS
+};
+
+#define WP_TDMAPI_EVENT_FE_ALARM WP_TDMAPI_EVENT_ALARM
+
+
+#define WP_TDMAPI_EVENT_ENABLE 0x01
+#define WP_TDMAPI_EVENT_DISABLE 0x02
+#define WP_TDMAPI_EVENT_MODE_DECODE(mode) \
+ ((mode) == WP_TDMAPI_EVENT_ENABLE) ? "Enable" : \
+ ((mode) == WP_TDMAPI_EVENT_DISABLE) ? "Disable" : \
+ "(Unknown mode)"
+
+#define WPTDM_A_BIT WAN_RBS_SIG_A
+#define WPTDM_B_BIT WAN_RBS_SIG_B
+#define WPTDM_C_BIT WAN_RBS_SIG_C
+#define WPTDM_D_BIT WAN_RBS_SIG_D
+
+#define WP_TDMAPI_EVENT_RXHOOK_OFF 0x01
+#define WP_TDMAPI_EVENT_RXHOOK_ON 0x02
+#define WP_TDMAPI_EVENT_RXHOOK_DECODE(state) \
+ ((state) == WP_TDMAPI_EVENT_RXHOOK_OFF) ? "Off-hook" : \
+ ((state) == WP_TDMAPI_EVENT_RXHOOK_ON) ? "On-hook" : \
+ "(Unknown state)"
+
+#define WP_TDMAPI_EVENT_RING_PRESENT 0x01
+#define WP_TDMAPI_EVENT_RING_STOP 0x02
+#define WP_TDMAPI_EVENT_RING_DECODE(state) \
+ ((state) == WP_TDMAPI_EVENT_RING_PRESENT) ? "Ring Present" : \
+ ((state) == WP_TDMAPI_EVENT_RING_STOP) ? "Ring Stop" : \
+ "(Unknown state)"
+
+#define WP_TDMAPI_EVENT_RING_TRIP_PRESENT 0x01
+#define WP_TDMAPI_EVENT_RING_TRIP_STOP 0x02
+#define WP_TDMAPI_EVENT_RING_TRIP_DECODE(state) \
+ ((state) == WP_TDMAPI_EVENT_RING_TRIP_PRESENT) ? "Ring Present" : \
+ ((state) == WP_TDMAPI_EVENT_RING_TRIP_STOP) ? "Ring Stop" : \
+ "(Unknown state)"
+/*Link Status */
+#define WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED 0x01
+#define WP_TDMAPI_EVENT_LINK_STATUS_DISCONNECTED 0x02
+#define WP_TDMAPI_EVENT_LINK_STATUS_DECODE(status) \
+ ((status) == WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED) ? "Connected" : \
+ ((status) == WP_TDMAPI_EVENT_LINK_STATUS_DISCONNECTED) ? "Disconnected" : \
+ "Unknown"
+#define WP_TDMAPI_EVENT_TONE_DIAL 0x01
+#define WP_TDMAPI_EVENT_TONE_BUSY 0x02
+#define WP_TDMAPI_EVENT_TONE_RING 0x03
+#define WP_TDMAPI_EVENT_TONE_CONGESTION 0x04
+
+/* BRI channels list */
+#define WAN_BRI_BCHAN1 0x01
+#define WAN_BRI_BCHAN2 0x02
+#define WAN_BRI_DCHAN 0x03
+
+
+typedef struct {
+
+ u_int8_t type;
+ u_int8_t mode;
+ u_int32_t time_stamp;
+ u_int8_t channel;
+ u_int32_t chan_map;
+ u_int8_t span;
+ union {
+ struct {
+ u_int8_t alarm;
+ } te1_alarm;
+ struct {
+ u_int8_t rbs_bits;
+ } te1_rbs;
+ struct {
+ u_int8_t state;
+ u_int8_t sig;
+ } rm_hook;
+ struct {
+ u_int8_t state;
+ } rm_ring;
+ struct {
+ u_int8_t type;
+ } rm_tone;
+ struct {
+ u_int8_t digit; /* DTMF: digit */
+ u_int8_t port; /* DTMF: SOUT/ROUT */
+ u_int8_t type; /* DTMF: PRESET/STOP */
+ } dtmf;
+ struct {
+ u_int16_t polarity;
+ u_int16_t ohttimer;
+ } rm_common;
+ struct{
+ u_int16_t status;
+ } linkstatus;
+ } wp_tdm_api_event_u;
+#define wp_tdm_api_event_type type
+#define wp_tdm_api_event_mode mode
+#define wp_tdm_api_event_alarm wp_tdm_api_event_u.te1_alarm.alarm
+#define wp_tdm_api_event_alarm wp_tdm_api_event_u.te1_alarm.alarm
+#define wp_tdm_api_event_rbs_bits wp_tdm_api_event_u.te1_rbs.rbs_bits
+#define wp_tdm_api_event_hook_state wp_tdm_api_event_u.rm_hook.state
+#define wp_tdm_api_event_hook_sig wp_tdm_api_event_u.rm_hook.sig
+#define wp_tdm_api_event_ring_state wp_tdm_api_event_u.rm_ring.state
+#define wp_tdm_api_event_tone_type wp_tdm_api_event_u.rm_tone.type
+#define wp_tdm_api_event_dtmf_digit wp_tdm_api_event_u.dtmf.digit
+#define wp_tdm_api_event_dtmf_type wp_tdm_api_event_u.dtmf.type
+#define wp_tdm_api_event_dtmf_port wp_tdm_api_event_u.dtmf.port
+#define wp_tdm_api_event_ohttimer wp_tdm_api_event_u.rm_common.ohttimer
+#define wp_tdm_api_event_polarity wp_tdm_api_event_u.rm_common.polarity
+#define wp_tdm_api_event_link_status wp_tdm_api_event_u.linkstatus.status
+} wp_tdm_api_event_t;
+
+typedef struct {
+ union {
+ unsigned char reserved[16];
+ }wp_rx_hdr_u;
+} wp_tdm_api_rx_hdr_t;
+
+typedef struct {
+ wp_tdm_api_rx_hdr_t hdr;
+ unsigned char data[1];
+} wp_tdm_api_rx_element_t;
+
+typedef struct {
+ union {
+ struct {
+ unsigned char _rbs_rx_bits;
+ unsigned int _time_stamp;
+ }wp_tx;
+ unsigned char reserved[16];
+ }wp_tx_hdr_u;
+#define wp_api_time_stamp wp_tx_hdr_u.wp_tx._time_stamp
+} wp_tdm_api_tx_hdr_t;
+
+typedef struct {
+ wp_tdm_api_tx_hdr_t hdr;
+ unsigned char data[1];
+} wp_tdm_api_tx_element_t;
+
+
+
+typedef struct wp_tdm_chan_stats
+{
+ unsigned int rx_packets; /* total packets received */
+ unsigned int tx_packets; /* total packets transmitted */
+ unsigned int rx_bytes; /* total bytes received */
+ unsigned int tx_bytes; /* total bytes transmitted */
+ unsigned int rx_errors; /* bad packets received */
+ unsigned int tx_errors; /* packet transmit problems */
+ unsigned int rx_dropped; /* no space in linux buffers */
+ unsigned int tx_dropped; /* no space available in linux */
+ unsigned int multicast; /* multicast packets received */
+#if !defined(__WINDOWS__)
+ unsigned int collisions;
+#endif
+ /* detailed rx_errors: */
+ unsigned int rx_length_errors;
+ unsigned int rx_over_errors; /* receiver ring buff overflow */
+ unsigned int rx_crc_errors; /* recved pkt with crc error */
+ unsigned int rx_frame_errors; /* recv'd frame alignment error */
+#if !defined(__WINDOWS__)
+ unsigned int rx_fifo_errors; /* recv'r fifo overrun */
+#endif
+ unsigned int rx_missed_errors; /* receiver missed packet */
+
+ /* detailed tx_errors */
+#if !defined(__WINDOWS__)
+ unsigned int tx_aborted_errors;
+ unsigned int tx_carrier_errors;
+#endif
+ unsigned int tx_fifo_errors;
+ unsigned int tx_heartbeat_errors;
+ unsigned int tx_window_errors;
+
+}wp_tdm_chan_stats_t;
+
+
+
+typedef struct wanpipe_tdm_api_cmd{
+ unsigned int cmd;
+ unsigned int hw_tdm_coding; /* Set/Get HW TDM coding: uLaw muLaw */
+ unsigned int hw_mtu_mru; /* Set/Get HW TDM MTU/MRU */
+ unsigned int usr_period; /* Set/Get User Period in ms */
+ unsigned int tdm_codec; /* Set/Get TDM Codec: SLinear */
+ unsigned int power_level; /* Set/Get Power level treshold */
+ unsigned int rx_disable; /* Enable/Disable Rx */
+ unsigned int tx_disable; /* Enable/Disable Tx */
+ unsigned int usr_mtu_mru; /* Set/Get User TDM MTU/MRU */
+ unsigned int ec_tap; /* Echo Cancellation Tap */
+ unsigned int rbs_poll; /* Enable/Disable RBS Polling */
+ unsigned int rbs_rx_bits; /* Rx RBS Bits */
+ unsigned int rbs_tx_bits; /* Tx RBS Bits */
+ unsigned int hdlc; /* HDLC based device */
+ unsigned int idle_flag; /* IDLE flag to Tx */
+ unsigned int fe_alarms; /* FE Alarms detected */
+ wp_tdm_chan_stats_t stats; /* TDM Statistics */
+ /* Do NOT add anything above this! Important for binary backward compatibility. */
+ wp_tdm_api_event_t event; /* TDM Event */
+ unsigned int data_len;
+ void *data;
+ unsigned char fe_status; /* FE status - Connected or Disconnected */
+ unsigned int hw_dtmf; /* HW DTMF enabled */
+}wanpipe_tdm_api_cmd_t;
+
+typedef struct wanpipe_tdm_api_event{
+ int (*wp_rbs_event)(sng_fd_t fd, unsigned char rbs_bits);
+ int (*wp_dtmf_event)(sng_fd_t fd, unsigned char dtmf, unsigned char type, unsigned char port);
+ int (*wp_rxhook_event)(sng_fd_t fd, unsigned char hook_state);
+ int (*wp_ring_detect_event)(sng_fd_t fd, unsigned char ring_state);
+ int (*wp_ring_trip_detect_event)(sng_fd_t fd, unsigned char ring_state);
+ int (*wp_fe_alarm_event)(sng_fd_t fd, unsigned char fe_alarm_event);
+ int (*wp_link_status_event)(sng_fd_t fd, unsigned char link_status_event);
+}wanpipe_tdm_api_event_t;
+
+typedef struct wanpipe_tdm_api{
+ wanpipe_tdm_api_cmd_t wp_tdm_cmd;
+ wanpipe_tdm_api_event_t wp_tdm_event;
+}wanpipe_tdm_api_t;
+
+
+#endif
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1232 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+
+#include "freetdm.h"
+#include "ftmod_zt.h"
+
+/**
+ * \brief Zaptel globals
+ */
+static struct {
+ uint32_t codec_ms;
+ uint32_t wink_ms;
+ uint32_t flash_ms;
+ uint32_t eclevel;
+ uint32_t etlevel;
+ float rxgain;
+ float txgain;
+} zt_globals;
+
+/**
+ * \brief General IOCTL codes
+ */
+struct ioctl_codes {
+ int GET_BLOCKSIZE;
+ int SET_BLOCKSIZE;
+ int FLUSH;
+ int SYNC;
+ int GET_PARAMS;
+ int SET_PARAMS;
+ int HOOK;
+ int GETEVENT;
+ int IOMUX;
+ int SPANSTAT;
+ int MAINT;
+ int GETCONF;
+ int SETCONF;
+ int CONFLINK;
+ int CONFDIAG;
+ int GETGAINS;
+ int SETGAINS;
+ int SPANCONFIG;
+ int CHANCONFIG;
+ int SET_BUFINFO;
+ int GET_BUFINFO;
+ int AUDIOMODE;
+ int ECHOCANCEL;
+ int HDLCRAWMODE;
+ int HDLCFCSMODE;
+ int SPECIFY;
+ int SETLAW;
+ int SETLINEAR;
+ int GETCONFMUTE;
+ int ECHOTRAIN;
+ int SETTXBITS;
+ int GETRXBITS;
+};
+
+/**
+ * \brief Zaptel IOCTL codes
+ */
+static struct ioctl_codes zt_ioctl_codes = {
+ .GET_BLOCKSIZE = ZT_GET_BLOCKSIZE,
+ .SET_BLOCKSIZE = ZT_SET_BLOCKSIZE,
+ .FLUSH = ZT_FLUSH,
+ .SYNC = ZT_SYNC,
+ .GET_PARAMS = ZT_GET_PARAMS,
+ .SET_PARAMS = ZT_SET_PARAMS,
+ .HOOK = ZT_HOOK,
+ .GETEVENT = ZT_GETEVENT,
+ .IOMUX = ZT_IOMUX,
+ .SPANSTAT = ZT_SPANSTAT,
+ .MAINT = ZT_MAINT,
+ .GETCONF = ZT_GETCONF,
+ .SETCONF = ZT_SETCONF,
+ .CONFLINK = ZT_CONFLINK,
+ .CONFDIAG = ZT_CONFDIAG,
+ .GETGAINS = ZT_GETGAINS,
+ .SETGAINS = ZT_SETGAINS,
+ .SPANCONFIG = ZT_SPANCONFIG,
+ .CHANCONFIG = ZT_CHANCONFIG,
+ .SET_BUFINFO = ZT_SET_BUFINFO,
+ .GET_BUFINFO = ZT_GET_BUFINFO,
+ .AUDIOMODE = ZT_AUDIOMODE,
+ .ECHOCANCEL = ZT_ECHOCANCEL,
+ .HDLCRAWMODE = ZT_HDLCRAWMODE,
+ .HDLCFCSMODE = ZT_HDLCFCSMODE,
+ .SPECIFY = ZT_SPECIFY,
+ .SETLAW = ZT_SETLAW,
+ .SETLINEAR = ZT_SETLINEAR,
+ .GETCONFMUTE = ZT_GETCONFMUTE,
+ .ECHOTRAIN = ZT_ECHOTRAIN,
+ .SETTXBITS = ZT_SETTXBITS,
+ .GETRXBITS = ZT_GETRXBITS
+};
+
+/**
+ * \brief Dahdi IOCTL codes
+ */
+static struct ioctl_codes dahdi_ioctl_codes = {
+ .GET_BLOCKSIZE = DAHDI_GET_BLOCKSIZE,
+ .SET_BLOCKSIZE = DAHDI_SET_BLOCKSIZE,
+ .FLUSH = DAHDI_FLUSH,
+ .SYNC = DAHDI_SYNC,
+ .GET_PARAMS = DAHDI_GET_PARAMS,
+ .SET_PARAMS = DAHDI_SET_PARAMS,
+ .HOOK = DAHDI_HOOK,
+ .GETEVENT = DAHDI_GETEVENT,
+ .IOMUX = DAHDI_IOMUX,
+ .SPANSTAT = DAHDI_SPANSTAT,
+ .MAINT = DAHDI_MAINT,
+ .GETCONF = DAHDI_GETCONF,
+ .SETCONF = DAHDI_SETCONF,
+ .CONFLINK = DAHDI_CONFLINK,
+ .CONFDIAG = DAHDI_CONFDIAG,
+ .GETGAINS = DAHDI_GETGAINS,
+ .SETGAINS = DAHDI_SETGAINS,
+ .SPANCONFIG = DAHDI_SPANCONFIG,
+ .CHANCONFIG = DAHDI_CHANCONFIG,
+ .SET_BUFINFO = DAHDI_SET_BUFINFO,
+ .GET_BUFINFO = DAHDI_GET_BUFINFO,
+ .AUDIOMODE = DAHDI_AUDIOMODE,
+ .ECHOCANCEL = DAHDI_ECHOCANCEL,
+ .HDLCRAWMODE = DAHDI_HDLCRAWMODE,
+ .HDLCFCSMODE = DAHDI_HDLCFCSMODE,
+ .SPECIFY = DAHDI_SPECIFY,
+ .SETLAW = DAHDI_SETLAW,
+ .SETLINEAR = DAHDI_SETLINEAR,
+ .GETCONFMUTE = DAHDI_GETCONFMUTE,
+ .ECHOTRAIN = DAHDI_ECHOTRAIN,
+ .SETTXBITS = DAHDI_SETTXBITS,
+ .GETRXBITS = DAHDI_GETRXBITS
+};
+
+#define ZT_INVALID_SOCKET -1
+static struct ioctl_codes codes;
+static const char *ctlpath = NULL;
+static const char *chanpath = NULL;
+
+static const char dahdi_ctlpath[] = "/dev/dahdi/ctl";
+static const char dahdi_chanpath[] = "/dev/dahdi/channel";
+
+static const char zt_ctlpath[] = "/dev/ftdm/ctl";
+static const char zt_chanpath[] = "/dev/ftdm/channel";
+
+static ftdm_socket_t CONTROL_FD = ZT_INVALID_SOCKET;
+
+FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event);
+FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event);
+
+/**
+ * \brief Initialises codec, and rx/tx gains
+ * \param g Structure for gains to be initialised
+ * \param rxgain RX gain value
+ * \param txgain TX gain value
+ * \param codec Codec
+ */
+static void zt_build_gains(struct zt_gains *g, float rxgain, float txgain, int codec)
+{
+ int j;
+ int k;
+ float linear_rxgain = pow(10.0, rxgain / 20.0);
+ float linear_txgain = pow(10.0, txgain / 20.0);
+
+ switch (codec) {
+ case FTDM_CODEC_ALAW:
+ for (j = 0; j < (sizeof(g->receive_gain) / sizeof(g->receive_gain[0])); j++) {
+ if (rxgain) {
+ k = (int) (((float) alaw_to_linear(j)) * linear_rxgain);
+ if (k > 32767) k = 32767;
+ if (k < -32767) k = -32767;
+ g->receive_gain[j] = linear_to_alaw(k);
+ } else {
+ g->receive_gain[j] = j;
+ }
+ if (txgain) {
+ k = (int) (((float) alaw_to_linear(j)) * linear_txgain);
+ if (k > 32767) k = 32767;
+ if (k < -32767) k = -32767;
+ g->transmit_gain[j] = linear_to_alaw(k);
+ } else {
+ g->transmit_gain[j] = j;
+ }
+ }
+ break;
+ case FTDM_CODEC_ULAW:
+ for (j = 0; j < (sizeof(g->receive_gain) / sizeof(g->receive_gain[0])); j++) {
+ if (rxgain) {
+ k = (int) (((float) ulaw_to_linear(j)) * linear_rxgain);
+ if (k > 32767) k = 32767;
+ if (k < -32767) k = -32767;
+ g->receive_gain[j] = linear_to_ulaw(k);
+ } else {
+ g->receive_gain[j] = j;
+ }
+ if (txgain) {
+ k = (int) (((float) ulaw_to_linear(j)) * linear_txgain);
+ if (k > 32767) k = 32767;
+ if (k < -32767) k = -32767;
+ g->transmit_gain[j] = linear_to_ulaw(k);
+ } else {
+ g->transmit_gain[j] = j;
+ }
+ }
+ break;
+ }
+}
+
+/**
+ * \brief Initialises a range of ftdmtel channels
+ * \param span FreeTDM span
+ * \param start Initial wanpipe channel number
+ * \param end Final wanpipe channel number
+ * \param type FreeTDM channel type
+ * \param name FreeTDM span name
+ * \param number FreeTDM span number
+ * \param cas_bits CAS bits
+ * \return number of spans configured
+ */
+static unsigned zt_open_range(ftdm_span_t *span, unsigned start, unsigned end, ftdm_chan_type_t type, char *name, char *number, unsigned char cas_bits)
+{
+ unsigned configured = 0, x;
+ zt_params_t ztp;
+
+ memset(&ztp, 0, sizeof(ztp));
+
+ if (type == FTDM_CHAN_TYPE_CAS) {
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring CAS channels with abcd == 0x%X\n", cas_bits);
+ }
+ for(x = start; x < end; x++) {
+ ftdm_channel_t *ftdmchan;
+ ftdm_socket_t sockfd = ZT_INVALID_SOCKET;
+ int len;
+
+ sockfd = open(chanpath, O_RDWR);
+ if (sockfd != ZT_INVALID_SOCKET && ftdm_span_add_channel(span, sockfd, type, &ftdmchan) == FTDM_SUCCESS) {
+
+ if (ioctl(sockfd, codes.SPECIFY, &x)) {
+ ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s chan %d fd %d (%s)\n", chanpath, x, sockfd, strerror(errno));
+ close(sockfd);
+ continue;
+ }
+
+ if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
+ struct zt_bufferinfo binfo;
+ memset(&binfo, 0, sizeof(binfo));
+ binfo.txbufpolicy = 0;
+ binfo.rxbufpolicy = 0;
+ binfo.numbufs = 32;
+ binfo.bufsize = 1024;
+ if (ioctl(sockfd, codes.SET_BUFINFO, &binfo)) {
+ ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d\n", chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd);
+ close(sockfd);
+ continue;
+ }
+ }
+
+ if (type == FTDM_CHAN_TYPE_FXS || type == FTDM_CHAN_TYPE_FXO) {
+ struct zt_chanconfig cc;
+ memset(&cc, 0, sizeof(cc));
+ cc.chan = cc.master = x;
+
+ switch(type) {
+ case FTDM_CHAN_TYPE_FXS:
+ {
+ switch(span->start_type) {
+ case FTDM_ANALOG_START_KEWL:
+ cc.sigtype = ZT_SIG_FXOKS;
+ break;
+ case FTDM_ANALOG_START_LOOP:
+ cc.sigtype = ZT_SIG_FXOLS;
+ break;
+ case FTDM_ANALOG_START_GROUND:
+ cc.sigtype = ZT_SIG_FXOGS;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case FTDM_CHAN_TYPE_FXO:
+ {
+ switch(span->start_type) {
+ case FTDM_ANALOG_START_KEWL:
+ cc.sigtype = ZT_SIG_FXSKS;
+ break;
+ case FTDM_ANALOG_START_LOOP:
+ cc.sigtype = ZT_SIG_FXSLS;
+ break;
+ case FTDM_ANALOG_START_GROUND:
+ cc.sigtype = ZT_SIG_FXSGS;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (ioctl(CONTROL_FD, codes.CHANCONFIG, &cc)) {
+ ftdm_log(FTDM_LOG_WARNING, "this ioctl fails on older ftdmtel but is harmless if you used ztcfg\n[device %s chan %d fd %d (%s)]\n", chanpath, x, CONTROL_FD, strerror(errno));
+ }
+ }
+
+ if (type == FTDM_CHAN_TYPE_CAS) {
+ struct zt_chanconfig cc;
+ memset(&cc, 0, sizeof(cc));
+ cc.chan = cc.master = x;
+ cc.sigtype = ZT_SIG_CAS;
+ cc.idlebits = cas_bits;
+ if (ioctl(CONTROL_FD, codes.CHANCONFIG, &cc)) {
+ ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d err:%s", chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd, strerror(errno));
+ close(sockfd);
+ continue;
+ }
+ }
+
+ if (ftdmchan->type != FTDM_CHAN_TYPE_DQ921 && ftdmchan->type != FTDM_CHAN_TYPE_DQ931) {
+ len = zt_globals.codec_ms * 8;
+ if (ioctl(ftdmchan->sockfd, codes.SET_BLOCKSIZE, &len)) {
+ ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d err:%s\n",
+ chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd, strerror(errno));
+ close(sockfd);
+ continue;
+ }
+
+ ftdmchan->packet_len = len;
+ ftdmchan->effective_interval = ftdmchan->native_interval = ftdmchan->packet_len / 8;
+
+ if (ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+ ftdmchan->packet_len *= 2;
+ }
+ }
+
+ if (ioctl(sockfd, codes.GET_PARAMS, &ztp) < 0) {
+ ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d\n", chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd);
+ close(sockfd);
+ continue;
+ }
+
+ if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
+ if (
+ (ztp.sig_type != ZT_SIG_HDLCRAW) &&
+ (ztp.sig_type != ZT_SIG_HDLCFCS) &&
+ (ztp.sig_type != ZT_SIG_HARDHDLC)
+ ) {
+ ftdm_log(FTDM_LOG_ERROR, "Failure configuring device %s as FreeTDM device %d:%d fd:%d, hardware signaling is not HDLC, fix your Zap/DAHDI configuration!\n", chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd);
+ close(sockfd);
+ continue;
+ }
+ }
+
+ ftdm_log(FTDM_LOG_INFO, "configuring device %s channel %d as FreeTDM device %d:%d fd:%d\n", chanpath, x, ftdmchan->span_id, ftdmchan->chan_id, sockfd);
+
+ ftdmchan->rate = 8000;
+ ftdmchan->physical_span_id = ztp.span_no;
+ ftdmchan->physical_chan_id = ztp.chan_no;
+
+ if (type == FTDM_CHAN_TYPE_FXS || type == FTDM_CHAN_TYPE_FXO || type == FTDM_CHAN_TYPE_EM || type == FTDM_CHAN_TYPE_B) {
+ if (ztp.g711_type == ZT_G711_ALAW) {
+ ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_ALAW;
+ } else if (ztp.g711_type == ZT_G711_MULAW) {
+ ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_ULAW;
+ } else {
+ int type;
+
+ if (ftdmchan->span->trunk_type == FTDM_TRUNK_E1) {
+ type = FTDM_CODEC_ALAW;
+ } else {
+ type = FTDM_CODEC_ULAW;
+ }
+
+ ftdmchan->native_codec = ftdmchan->effective_codec = type;
+
+ }
+ }
+
+ ztp.wink_time = zt_globals.wink_ms;
+ ztp.flash_time = zt_globals.flash_ms;
+
+ if (ioctl(sockfd, codes.SET_PARAMS, &ztp) < 0) {
+ ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d\n", chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd);
+ close(sockfd);
+ continue;
+ }
+
+ if (!ftdm_strlen_zero(name)) {
+ ftdm_copy_string(ftdmchan->chan_name, name, sizeof(ftdmchan->chan_name));
+ }
+ if (!ftdm_strlen_zero(number)) {
+ ftdm_copy_string(ftdmchan->chan_number, number, sizeof(ftdmchan->chan_number));
+ }
+ configured++;
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s\n", chanpath);
+ }
+ }
+
+
+
+ return configured;
+}
+
+/**
+ * \brief Initialises an freetdm ftdmtel span from a configuration string
+ * \param span FreeTDM span
+ * \param str Configuration string
+ * \param type FreeTDM span type
+ * \param name FreeTDM span name
+ * \param number FreeTDM span number
+ * \return Success or failure
+ */
+static FIO_CONFIGURE_SPAN_FUNCTION(zt_configure_span)
+{
+
+ int items, i;
+ char *mydata, *item_list[10];
+ char *ch, *mx;
+ unsigned char cas_bits = 0;
+ int channo;
+ int top = 0;
+ unsigned configured = 0;
+
+ assert(str != NULL);
+
+
+ mydata = ftdm_strdup(str);
+ assert(mydata != NULL);
+
+
+ items = ftdm_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
+
+ for(i = 0; i < items; i++) {
+ ch = item_list[i];
+
+ if (!(ch)) {
+ ftdm_log(FTDM_LOG_ERROR, "Invalid input\n");
+ continue;
+ }
+
+ channo = atoi(ch);
+
+ if (channo < 0) {
+ ftdm_log(FTDM_LOG_ERROR, "Invalid channel number %d\n", channo);
+ continue;
+ }
+
+ if ((mx = strchr(ch, '-'))) {
+ mx++;
+ top = atoi(mx) + 1;
+ } else {
+ top = channo + 1;
+ }
+
+
+ if (top < 0) {
+ ftdm_log(FTDM_LOG_ERROR, "Invalid range number %d\n", top);
+ continue;
+ }
+ if (FTDM_CHAN_TYPE_CAS == type && ftdm_config_get_cas_bits(ch, &cas_bits)) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to get CAS bits in CAS channel\n");
+ continue;
+ }
+ configured += zt_open_range(span, channo, top, type, name, number, cas_bits);
+
+ }
+
+ ftdm_safe_free(mydata);
+
+ return configured;
+
+}
+
+/**
+ * \brief Process configuration variable for a ftdmtel profile
+ * \param category Wanpipe profile name
+ * \param var Variable name
+ * \param val Variable value
+ * \param lineno Line number from configuration file
+ * \return Success
+ */
+static FIO_CONFIGURE_FUNCTION(zt_configure)
+{
+
+ int num;
+ float fnum;
+
+ if (!strcasecmp(category, "defaults")) {
+ if (!strcasecmp(var, "codec_ms")) {
+ num = atoi(val);
+ if (num < 10 || num > 60) {
+ ftdm_log(FTDM_LOG_WARNING, "invalid codec ms at line %d\n", lineno);
+ } else {
+ zt_globals.codec_ms = num;
+ }
+ } else if (!strcasecmp(var, "wink_ms")) {
+ num = atoi(val);
+ if (num < 50 || num > 3000) {
+ ftdm_log(FTDM_LOG_WARNING, "invalid wink ms at line %d\n", lineno);
+ } else {
+ zt_globals.wink_ms = num;
+ }
+ } else if (!strcasecmp(var, "flash_ms")) {
+ num = atoi(val);
+ if (num < 50 || num > 3000) {
+ ftdm_log(FTDM_LOG_WARNING, "invalid flash ms at line %d\n", lineno);
+ } else {
+ zt_globals.flash_ms = num;
+ }
+ } else if (!strcasecmp(var, "echo_cancel_level")) {
+ num = atoi(val);
+ if (num < 0 || num > 256) {
+ ftdm_log(FTDM_LOG_WARNING, "invalid echo can val at line %d\n", lineno);
+ } else {
+ zt_globals.eclevel = num;
+ }
+
+ } else if (!strcasecmp(var, "rxgain")) {
+ fnum = (float)atof(val);
+ if (fnum < -100.0 || fnum > 100.0) {
+ ftdm_log(FTDM_LOG_WARNING, "invalid rxgain val at line %d\n", lineno);
+ } else {
+ zt_globals.rxgain = fnum;
+ ftdm_log(FTDM_LOG_INFO, "Setting rxgain val to %f\n", fnum);
+ }
+
+ } else if (!strcasecmp(var, "txgain")) {
+ fnum = (float)atof(val);
+ if (fnum < -100.0 || fnum > 100.0) {
+ ftdm_log(FTDM_LOG_WARNING, "invalid txgain val at line %d\n", lineno);
+ } else {
+ zt_globals.txgain = fnum;
+ ftdm_log(FTDM_LOG_INFO, "Setting txgain val to %f\n", fnum);
+ }
+
+ }
+ }
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Opens a ftdmtel channel
+ * \param ftdmchan Channel to open
+ * \return Success or failure
+ */
+static FIO_OPEN_FUNCTION(zt_open)
+{
+ ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_INTERVAL);
+
+ if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921 || ftdmchan->type == FTDM_CHAN_TYPE_DQ931) {
+ ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_NONE;
+ } else {
+ int blocksize = zt_globals.codec_ms * (ftdmchan->rate / 1000);
+ int err;
+ if ((err = ioctl(ftdmchan->sockfd, codes.SET_BLOCKSIZE, &blocksize))) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+ return FTDM_FAIL;
+ } else {
+ ftdmchan->effective_interval = ftdmchan->native_interval;
+ ftdmchan->packet_len = blocksize;
+ ftdmchan->native_codec = ftdmchan->effective_codec;
+ }
+
+ if (ftdmchan->type == FTDM_CHAN_TYPE_B) {
+ int one = 1;
+ if (ioctl(ftdmchan->sockfd, codes.AUDIOMODE, &one)) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+ ftdm_log(FTDM_LOG_ERROR, "%s\n", ftdmchan->last_error);
+ return FTDM_FAIL;
+ }
+ } else if (ftdmchan->type == FTDM_CHAN_TYPE_FXS || ftdmchan->type == FTDM_CHAN_TYPE_FXO || ftdmchan->type == FTDM_CHAN_TYPE_EM) {
+ int len = zt_globals.eclevel;
+ if (ioctl(ftdmchan->sockfd, codes.ECHOCANCEL, &len)) {
+ ftdm_log(FTDM_LOG_WARNING, "Echo cancel not available for %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id);
+ //snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+ //ftdm_log(FTDM_LOG_ERROR, "%s\n", ftdmchan->last_error);
+ //return FTDM_FAIL;
+ } else {
+ len = zt_globals.etlevel;
+ if (ioctl(ftdmchan->sockfd, codes.ECHOTRAIN, &len)) {
+ ftdm_log(FTDM_LOG_WARNING, "Echo training not available for %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id);
+ //snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+ //ftdm_log(FTDM_LOG_ERROR, "%s\n", ftdmchan->last_error);
+ //return FTDM_FAIL;
+ }
+ }
+ }
+ if(zt_globals.rxgain || zt_globals.txgain) {
+ struct zt_gains gains;
+ memset(&gains, 0, sizeof(gains));
+
+ gains.chan_no = ftdmchan->physical_chan_id;
+ zt_build_gains(&gains, zt_globals.rxgain, zt_globals.txgain, ftdmchan->native_codec);
+
+ if(zt_globals.rxgain)
+ ftdm_log(FTDM_LOG_INFO, "Setting rxgain to %f on channel %d\n", zt_globals.rxgain, gains.chan_no);
+
+ if(zt_globals.txgain)
+ ftdm_log(FTDM_LOG_INFO, "Setting txgain to %f on channel %d\n", zt_globals.txgain, gains.chan_no);
+
+ if (ioctl(ftdmchan->sockfd, codes.SETGAINS, &gains) < 0) {
+ ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d\n", chanpath, ftdmchan->span_id, ftdmchan->chan_id, ftdmchan->sockfd);
+ }
+ }
+
+ int len = zt_globals.eclevel;
+ ftdm_log(FTDM_LOG_INFO, "Setting echo cancel to %d taps for %d:%d\n", len, ftdmchan->span_id, ftdmchan->chan_id);
+ if (ioctl(ftdmchan->sockfd, codes.ECHOCANCEL, &len)) {
+ ftdm_log(FTDM_LOG_WARNING, "Echo cancel not available for %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id);
+ } else {
+ len = zt_globals.etlevel;
+ if (ioctl(ftdmchan->sockfd, codes.ECHOTRAIN, &len)) {
+ ftdm_log(FTDM_LOG_WARNING, "Echo training not available for %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id);
+ }
+ }
+
+ }
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Closes ftdmtel channel
+ * \param ftdmchan Channel to close
+ * \return Success
+ */
+static FIO_CLOSE_FUNCTION(zt_close)
+{
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Executes an FreeTDM command on a ftdmtel channel
+ * \param ftdmchan Channel to execute command on
+ * \param command FreeTDM command to execute
+ * \param obj Object (unused)
+ * \return Success or failure
+ */
+static FIO_COMMAND_FUNCTION(zt_command)
+{
+ zt_params_t ztp;
+ int err = 0;
+
+ memset(&ztp, 0, sizeof(ztp));
+
+ switch(command) {
+ case FTDM_COMMAND_ENABLE_ECHOCANCEL:
+ {
+ int level = FTDM_COMMAND_OBJ_INT;
+ err = ioctl(ftdmchan->sockfd, codes.ECHOCANCEL, &level);
+ FTDM_COMMAND_OBJ_INT = level;
+ }
+ case FTDM_COMMAND_DISABLE_ECHOCANCEL:
+ {
+ int level = 0;
+ err = ioctl(ftdmchan->sockfd, codes.ECHOCANCEL, &level);
+ FTDM_COMMAND_OBJ_INT = level;
+ }
+ break;
+ case FTDM_COMMAND_ENABLE_ECHOTRAIN:
+ {
+ int level = FTDM_COMMAND_OBJ_INT;
+ err = ioctl(ftdmchan->sockfd, codes.ECHOTRAIN, &level);
+ FTDM_COMMAND_OBJ_INT = level;
+ }
+ case FTDM_COMMAND_DISABLE_ECHOTRAIN:
+ {
+ int level = 0;
+ err = ioctl(ftdmchan->sockfd, codes.ECHOTRAIN, &level);
+ FTDM_COMMAND_OBJ_INT = level;
+ }
+ break;
+ case FTDM_COMMAND_OFFHOOK:
+ {
+ int command = ZT_OFFHOOK;
+ if (ioctl(ftdmchan->sockfd, codes.HOOK, &command)) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "OFFHOOK Failed");
+ return FTDM_FAIL;
+ }
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
+ }
+ break;
+ case FTDM_COMMAND_ONHOOK:
+ {
+ int command = ZT_ONHOOK;
+ if (ioctl(ftdmchan->sockfd, codes.HOOK, &command)) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ONHOOK Failed");
+ return FTDM_FAIL;
+ }
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
+ }
+ break;
+ case FTDM_COMMAND_FLASH:
+ {
+ int command = ZT_FLASH;
+ if (ioctl(ftdmchan->sockfd, codes.HOOK, &command)) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "FLASH Failed");
+ return FTDM_FAIL;
+ }
+ }
+ break;
+ case FTDM_COMMAND_WINK:
+ {
+ int command = ZT_WINK;
+ if (ioctl(ftdmchan->sockfd, codes.HOOK, &command)) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "WINK Failed");
+ return FTDM_FAIL;
+ }
+ }
+ break;
+ case FTDM_COMMAND_GENERATE_RING_ON:
+ {
+ int command = ZT_RING;
+ if (ioctl(ftdmchan->sockfd, codes.HOOK, &command)) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring Failed");
+ return FTDM_FAIL;
+ }
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
+ }
+ break;
+ case FTDM_COMMAND_GENERATE_RING_OFF:
+ {
+ int command = ZT_RINGOFF;
+ if (ioctl(ftdmchan->sockfd, codes.HOOK, &command)) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring-off failed");
+ return FTDM_FAIL;
+ }
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
+ }
+ break;
+ case FTDM_COMMAND_GET_INTERVAL:
+ {
+
+ if (!(err = ioctl(ftdmchan->sockfd, codes.GET_BLOCKSIZE, &ftdmchan->packet_len))) {
+ ftdmchan->native_interval = ftdmchan->packet_len / 8;
+ if (ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+ ftdmchan->packet_len *= 2;
+ }
+ FTDM_COMMAND_OBJ_INT = ftdmchan->native_interval;
+ }
+ }
+ break;
+ case FTDM_COMMAND_SET_INTERVAL:
+ {
+ int interval = FTDM_COMMAND_OBJ_INT;
+ int len = interval * 8;
+
+ if (!(err = ioctl(ftdmchan->sockfd, codes.SET_BLOCKSIZE, &len))) {
+ ftdmchan->packet_len = len;
+ ftdmchan->effective_interval = ftdmchan->native_interval = ftdmchan->packet_len / 8;
+
+ if (ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+ ftdmchan->packet_len *= 2;
+ }
+ }
+ }
+ break;
+ case FTDM_COMMAND_SET_CAS_BITS:
+ {
+ int bits = FTDM_COMMAND_OBJ_INT;
+ err = ioctl(ftdmchan->sockfd, codes.SETTXBITS, &bits);
+ }
+ break;
+ case FTDM_COMMAND_GET_CAS_BITS:
+ {
+ err = ioctl(ftdmchan->sockfd, codes.GETRXBITS, &ftdmchan->rx_cas_bits);
+ if (!err) {
+ FTDM_COMMAND_OBJ_INT = ftdmchan->rx_cas_bits;
+ }
+ }
+ break;
+ case FTDM_COMMAND_FLUSH_TX_BUFFERS:
+ {
+ int flushmode = ZT_FLUSH_WRITE;
+ err = ioctl(ftdmchan->sockfd, codes.FLUSH, &flushmode);
+ }
+ break;
+ case FTDM_COMMAND_FLUSH_RX_BUFFERS:
+ {
+ int flushmode = ZT_FLUSH_READ;
+ err = ioctl(ftdmchan->sockfd, codes.FLUSH, &flushmode);
+ }
+ break;
+ case FTDM_COMMAND_FLUSH_BUFFERS:
+ {
+ int flushmode = ZT_FLUSH_BOTH;
+ err = ioctl(ftdmchan->sockfd, codes.FLUSH, &flushmode);
+ }
+ break;
+ default:
+ err = FTDM_NOTIMPL;
+ break;
+ };
+
+ if (err && err != FTDM_NOTIMPL) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+ return FTDM_FAIL;
+ }
+
+
+ return err == 0 ? FTDM_SUCCESS : err;
+}
+
+/**
+ * \brief Gets alarms from a ftdmtel Channel
+ * \param ftdmchan Channel to get alarms from
+ * \return Success or failure
+ */
+static FIO_GET_ALARMS_FUNCTION(zt_get_alarms)
+{
+ struct zt_spaninfo info;
+
+ memset(&info, 0, sizeof(info));
+ info.span_no = ftdmchan->physical_span_id;
+
+ if (ioctl(CONTROL_FD, codes.SPANSTAT, &info)) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ioctl failed (%s)", strerror(errno));
+ snprintf(ftdmchan->span->last_error, sizeof(ftdmchan->span->last_error), "ioctl failed (%s)", strerror(errno));
+ return FTDM_FAIL;
+ }
+
+ ftdmchan->alarm_flags = info.alarms;
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Waits for an event on a ftdmtel channel
+ * \param ftdmchan Channel to open
+ * \param flags Type of event to wait for
+ * \param to Time to wait (in ms)
+ * \return Success, failure or timeout
+ */
+static FIO_WAIT_FUNCTION(zt_wait)
+{
+ int32_t inflags = 0;
+ int result;
+ struct pollfd pfds[1];
+
+ if (*flags & FTDM_READ) {
+ inflags |= POLLIN;
+ }
+
+ if (*flags & FTDM_WRITE) {
+ inflags |= POLLOUT;
+ }
+
+ if (*flags & FTDM_EVENTS) {
+ inflags |= POLLPRI;
+ }
+
+
+ memset(&pfds[0], 0, sizeof(pfds[0]));
+ pfds[0].fd = ftdmchan->sockfd;
+ pfds[0].events = inflags;
+ result = poll(pfds, 1, to);
+ *flags = 0;
+
+ if (pfds[0].revents & POLLERR) {
+ result = -1;
+ }
+
+ if (result > 0) {
+ inflags = pfds[0].revents;
+ }
+
+ *flags = FTDM_NO_FLAGS;
+
+ if (result < 0){
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Poll failed");
+ return FTDM_FAIL;
+ }
+
+ if (result == 0) {
+ return FTDM_TIMEOUT;
+ }
+
+ if (inflags & POLLIN) {
+ *flags |= FTDM_READ;
+ }
+
+ if (inflags & POLLOUT) {
+ *flags |= FTDM_WRITE;
+ }
+
+ if (inflags & POLLPRI) {
+ *flags |= FTDM_EVENTS;
+ }
+
+ return FTDM_SUCCESS;
+
+}
+
+/**
+ * \brief Checks for events on a ftdmtel span
+ * \param span Span to check for events
+ * \param ms Time to wait for event
+ * \return Success if event is waiting or failure if not
+ */
+FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event)
+{
+ struct pollfd pfds[FTDM_MAX_CHANNELS_SPAN];
+ uint32_t i, j = 0, k = 0;
+ int r;
+
+ for(i = 1; i <= span->chan_count; i++) {
+ memset(&pfds[j], 0, sizeof(pfds[j]));
+ pfds[j].fd = span->channels[i]->sockfd;
+ pfds[j].events = POLLPRI;
+ j++;
+ }
+
+ r = poll(pfds, j, ms);
+
+ if (r == 0) {
+ return FTDM_TIMEOUT;
+ } else if (r < 0 || (pfds[i-1].revents & POLLERR)) {
+ snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+ return FTDM_FAIL;
+ }
+
+ for(i = 1; i <= span->chan_count; i++) {
+ if (pfds[i-1].revents & POLLPRI) {
+ ftdm_set_flag(span->channels[i], FTDM_CHANNEL_EVENT);
+ span->channels[i]->last_event_time = ftdm_current_time_in_ms();
+ k++;
+ }
+ }
+
+ if (!k) {
+ snprintf(span->last_error, sizeof(span->last_error), "no matching descriptor");
+ }
+
+ return k ? FTDM_SUCCESS : FTDM_FAIL;
+}
+
+/**
+ * \brief Retrieves an event from a ftdmtel span
+ * \param span Span to retrieve event from
+ * \param event FreeTDM event to return
+ * \return Success or failure
+ */
+FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
+{
+ uint32_t i, event_id = 0;
+ ftdm_oob_event_t zt_event_id = 0;
+
+ for(i = 1; i <= span->chan_count; i++) {
+ if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
+ ftdm_clear_flag(span->channels[i], FTDM_CHANNEL_EVENT);
+ if (ioctl(span->channels[i]->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
+ snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+ return FTDM_FAIL;
+ }
+
+ switch(zt_event_id) {
+ case ZT_EVENT_RINGEROFF:
+ {
+ return FTDM_FAIL;
+ }
+ break;
+ case ZT_EVENT_RINGERON:
+ {
+ return FTDM_FAIL;
+ }
+ break;
+ case ZT_EVENT_RINGBEGIN:
+ {
+ event_id = FTDM_OOB_RING_START;
+ }
+ break;
+ case ZT_EVENT_ONHOOK:
+ {
+ event_id = FTDM_OOB_ONHOOK;
+ }
+ break;
+ case ZT_EVENT_WINKFLASH:
+ {
+ if (span->channels[i]->state == FTDM_CHANNEL_STATE_DOWN || span->channels[i]->state == FTDM_CHANNEL_STATE_DIALING) {
+ event_id = FTDM_OOB_WINK;
+ } else {
+ event_id = FTDM_OOB_FLASH;
+ }
+ }
+ break;
+ case ZT_EVENT_RINGOFFHOOK:
+ {
+ if (span->channels[i]->type == FTDM_CHAN_TYPE_FXS || (span->channels[i]->type == FTDM_CHAN_TYPE_EM && span->channels[i]->state != FTDM_CHANNEL_STATE_UP)) {
+ ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
+ event_id = FTDM_OOB_OFFHOOK;
+ } else if (span->channels[i]->type == FTDM_CHAN_TYPE_FXO) {
+ event_id = FTDM_OOB_RING_START;
+ }
+ }
+ break;
+ case ZT_EVENT_ALARM:
+ {
+ event_id = FTDM_OOB_ALARM_TRAP;
+ }
+ break;
+ case ZT_EVENT_NOALARM:
+ {
+ event_id = FTDM_OOB_ALARM_CLEAR;
+ }
+ break;
+ case ZT_EVENT_BITSCHANGED:
+ {
+ event_id = FTDM_OOB_CAS_BITS_CHANGE;
+ int bits = 0;
+ int err = ioctl(span->channels[i]->sockfd, codes.GETRXBITS, &bits);
+ if (err) {
+ return FTDM_FAIL;
+ }
+ span->channels[i]->rx_cas_bits = bits;
+ }
+ break;
+ default:
+ {
+ ftdm_log(FTDM_LOG_WARNING, "Unhandled event %d for %d:%d\n", zt_event_id, span->span_id, i);
+ event_id = FTDM_OOB_INVALID;
+ }
+ break;
+ }
+
+ span->channels[i]->last_event_time = 0;
+ span->event_header.e_type = FTDM_EVENT_OOB;
+ span->event_header.enum_id = event_id;
+ span->event_header.channel = span->channels[i];
+ *event = &span->event_header;
+ return FTDM_SUCCESS;
+ }
+ }
+
+ return FTDM_FAIL;
+
+}
+
+/**
+ * \brief Reads data from a ftdmtel channel
+ * \param ftdmchan Channel to read from
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success, failure or timeout
+ */
+static FIO_READ_FUNCTION(zt_read)
+{
+ ftdm_ssize_t r = 0;
+ int errs = 0;
+
+ while (errs++ < 30) {
+ if ((r = read(ftdmchan->sockfd, data, *datalen)) > 0) {
+ break;
+ }
+ ftdm_sleep(10);
+ if (r == 0) {
+ errs--;
+ }
+ }
+
+ if (r > 0) {
+ *datalen = r;
+ if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
+ *datalen -= 2;
+ }
+ return FTDM_SUCCESS;
+ }
+
+ return r == 0 ? FTDM_TIMEOUT : FTDM_FAIL;
+}
+
+/**
+ * \brief Writes data to a ftdmtel channel
+ * \param ftdmchan Channel to write to
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success or failure
+ */
+static FIO_WRITE_FUNCTION(zt_write)
+{
+ ftdm_ssize_t w = 0;
+ ftdm_size_t bytes = *datalen;
+
+ if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
+ memset(data+bytes, 0, 2);
+ bytes += 2;
+ }
+
+ w = write(ftdmchan->sockfd, data, bytes);
+
+ if (w >= 0) {
+ *datalen = w;
+ return FTDM_SUCCESS;
+ }
+
+ return FTDM_FAIL;
+}
+
+/**
+ * \brief Destroys a ftdmtel Channel
+ * \param ftdmchan Channel to destroy
+ * \return Success
+ */
+static FIO_CHANNEL_DESTROY_FUNCTION(zt_channel_destroy)
+{
+ close(ftdmchan->sockfd);
+ ftdmchan->sockfd = ZT_INVALID_SOCKET;
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Global FreeTDM IO interface for ftdmtel
+ */
+static ftdm_io_interface_t zt_interface;
+
+/**
+ * \brief Loads ftdmtel IO module
+ * \param fio FreeTDM IO interface
+ * \return Success or failure
+ */
+static FIO_IO_LOAD_FUNCTION(zt_init)
+{
+ assert(fio != NULL);
+ struct stat statbuf;
+ memset(&zt_interface, 0, sizeof(zt_interface));
+ memset(&zt_globals, 0, sizeof(zt_globals));
+
+ if (!stat(zt_ctlpath, &statbuf)) {
+ ftdm_log(FTDM_LOG_NOTICE, "Using Zaptel control device\n");
+ ctlpath = zt_ctlpath;
+ chanpath = zt_chanpath;
+ memcpy(&codes, &zt_ioctl_codes, sizeof(codes));
+ } else if (!stat(dahdi_ctlpath, &statbuf)) {
+ ftdm_log(FTDM_LOG_NOTICE, "Using DAHDI control device\n");
+ ctlpath = dahdi_ctlpath;
+ chanpath = dahdi_chanpath;
+ memcpy(&codes, &dahdi_ioctl_codes, sizeof(codes));
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "No DAHDI or Zap control device found in /dev/\n");
+ return FTDM_FAIL;
+ }
+ if ((CONTROL_FD = open(ctlpath, O_RDWR)) < 0) {
+ ftdm_log(FTDM_LOG_ERROR, "Cannot open control device %s: %s\n", ctlpath, strerror(errno));
+ return FTDM_FAIL;
+ }
+
+ zt_globals.codec_ms = 20;
+ zt_globals.wink_ms = 150;
+ zt_globals.flash_ms = 750;
+ zt_globals.eclevel = 64;
+ zt_globals.etlevel = 0;
+
+ zt_interface.name = "zt";
+ zt_interface.configure = zt_configure;
+ zt_interface.configure_span = zt_configure_span;
+ zt_interface.open = zt_open;
+ zt_interface.close = zt_close;
+ zt_interface.command = zt_command;
+ zt_interface.wait = zt_wait;
+ zt_interface.read = zt_read;
+ zt_interface.write = zt_write;
+ zt_interface.poll_event = zt_poll_event;
+ zt_interface.next_event = zt_next_event;
+ zt_interface.channel_destroy = zt_channel_destroy;
+ zt_interface.get_alarms = zt_get_alarms;
+ *fio = &zt_interface;
+
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Unloads ftdmtel IO module
+ * \return Success
+ */
+static FIO_IO_UNLOAD_FUNCTION(zt_destroy)
+{
+ close(CONTROL_FD);
+ memset(&zt_interface, 0, sizeof(zt_interface));
+ return FTDM_SUCCESS;
+}
+
+/**
+ * \brief FreeTDM ftdmtel IO module definition
+ */
+ftdm_module_t ftdm_module = {
+ "zt",
+ zt_init,
+ zt_destroy,
+};
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#ifndef FTDM_ZT_H
+#define FTDM_ZT_H
+#include "freetdm.h"
+#include <sys/ioctl.h>
+#include <poll.h>
+
+#ifdef __sun
+#include <unistd.h>
+#include <sys/ioccom.h>
+#include <stropts.h>
+#endif
+
+/* Hardware interface structures and defines */
+/* Based on documentation of the structures required for the hardware interface */
+/* from http://wiki.freeswitch.org/wiki/Zapata_ftdmtel_interface */
+
+/* Structures */
+
+/* Used with ioctl: ZT_GET_PARAMS and ZT_SET_PARAMS */
+struct zt_params {
+ int chan_no; /* Channel Number */
+ int span_no; /* Span Number */
+ int chan_position; /* Channel Position */
+ int sig_type; /* Signal Type (read-only) */
+ int sig_cap; /* Signal Cap (read-only) */
+ int receive_offhook; /* Receive is offhook (read-only) */
+ int receive_bits; /* Number of bits in receive (read-only) */
+ int transmit_bits; /* Number of bits in transmit (read-only) */
+ int transmit_hook_sig; /* Transmit Hook Signal (read-only) */
+ int receive_hook_sig; /* Receive Hook Signal (read-only) */
+ int g711_type; /* Member of zt_g711_t (read-only) */
+ int idlebits; /* bits for the idle state (read-only) */
+ char chan_name[40]; /* Channel Name */
+ int prewink_time;
+ int preflash_time;
+ int wink_time;
+ int flash_time;
+ int start_time;
+ int receive_wink_time;
+ int receive_flash_time;
+ int debounce_time;
+ int pulse_break_time;
+ int pulse_make_time;
+ int pulse_after_time;
+ /* latest version of this struct include chan_alarms field */
+ uint32_t chan_alarms;
+};
+
+typedef struct zt_params zt_params_t;
+
+/* Used with ioctl: ZT_CONFLINK, ZT_GETCONF and ZT_SETCONF */
+struct zt_confinfo {
+ int chan_no; /* Channel Number, 0 for current */
+ int conference_number;
+ int conference_mode;
+};
+
+/* Used with ioctl: ZT_GETGAINS and ZT_SETGAINS */
+struct zt_gains {
+ int chan_no; /* Channel Number, 0 for current */
+ unsigned char receive_gain[256]; /* Receive gain table */
+ unsigned char transmit_gain[256]; /* Transmit gain table */
+};
+
+/* Used with ioctl: ZT_SPANSTAT */
+struct zt_spaninfo {
+ int span_no; /* span number (-1 to use name) */
+ char name[20]; /* Name of span */
+ char description[40]; /* Description of span */
+ int alarms; /* alarms status */
+ int transmit_level; /* Transmit level */
+ int receive_level; /* Receive level */
+ int bpv_count; /* Current BPV count */
+ int crc4_count; /* Current CRC4 error count */
+ int ebit_count; /* Current E-bit error count */
+ int fas_count; /* Current FAS error count */
+ int irq_misses; /* Current IRQ misses */
+ int sync_src; /* Span # of sync source (0 = free run) */
+ int configured_chan_count; /* Count of channels configured on the span */
+ int channel_count; /* Total count of channels on the span */
+ int span_count; /* Total count of ftdmtel spans on the system*/
+ /* end v1 of the struct */
+ /* as long as we don't use the fields below we should be ok regardless of the ftdmtel/dahdi version */
+ int lbo; /* Line Build Out */
+ int lineconfig; /* framing/coding */
+ /* end of v2 of the struct */
+ char lboname[40]; /* Line Build Out in text form */
+ char location[40]; /* span's device location in system */
+ char manufacturer[40]; /* manufacturer of span's device */
+ char devicetype[40]; /* span's device type */
+ int irq; /* span's device IRQ */
+ int linecompat; /* signaling modes possible on this span */
+ char spantype[6]; /* type of span in text form */
+};
+
+struct zt_maintinfo {
+ int span_no; /* span number */
+ int command; /* Maintenance mode to set (from zt_maintenance_mode_t) */
+};
+
+struct zt_lineconfig {
+/* Used in ZT_SPANCONFIG */
+ int span; /* Which span number (0 to use name) */
+ char name[20]; /* Name of span to use */
+ int lbo; /* line build-outs */
+ int lineconfig; /* line config parameters (framing, coding) */
+ int sync; /* what level of sync source we are */
+};
+
+struct zt_chanconfig {
+/* Used in ZT_CHANCONFIG */
+ int chan; /* Channel we're applying this to (0 to use name) */
+ char name[40]; /* Name of channel to use */
+ int sigtype; /* Signal type */
+ int deflaw; /* Default law (ZT_LAW_DEFAULT, ZT_LAW_MULAW, or ZT_LAW_ALAW */
+ int master; /* Master channel if sigtype is ZT_SLAVE */
+ int idlebits; /* Idle bits (if this is a CAS channel) or channel to monitor (if this is DACS channel) */
+ char netdev_name[16]; /* name for the hdlc network device */
+};
+
+struct zt_bufferinfo {
+/* used in ZT_SET_BUFINFO and ZT_GET_BUFINFO */
+ int txbufpolicy; /* Policy for handling receive buffers */
+ int rxbufpolicy; /* Policy for handling receive buffers */
+ int numbufs; /* How many buffers to use */
+ int bufsize; /* How big each buffer is */
+ int readbufs; /* How many read buffers are full (read-only) */
+ int writebufs; /* How many write buffers are full (read-only) */
+};
+
+/* Enumerations */
+
+/* Values in zt_params structure for member g711_type */
+typedef enum {
+ ZT_G711_DEFAULT = 0, /* Default mulaw/alaw from the span */
+ ZT_G711_MULAW = 1,
+ ZT_G711_ALAW = 2
+} zt_g711_t;
+
+typedef enum {
+ ZT_EVENT_NONE = 0,
+ ZT_EVENT_ONHOOK = 1,
+ ZT_EVENT_RINGOFFHOOK = 2,
+ ZT_EVENT_WINKFLASH = 3,
+ ZT_EVENT_ALARM = 4,
+ ZT_EVENT_NOALARM = 5,
+ ZT_EVENT_ABORT = 6,
+ ZT_EVENT_OVERRUN = 7,
+ ZT_EVENT_BADFCS = 8,
+ ZT_EVENT_DIALCOMPLETE = 9,
+ ZT_EVENT_RINGERON = 10,
+ ZT_EVENT_RINGEROFF = 11,
+ ZT_EVENT_HOOKCOMPLETE = 12,
+ ZT_EVENT_BITSCHANGED = 13,
+ ZT_EVENT_PULSE_START = 14,
+ ZT_EVENT_TIMER_EXPIRED = 15,
+ ZT_EVENT_TIMER_PING = 16,
+ ZT_EVENT_POLARITY = 17,
+ ZT_EVENT_RINGBEGIN = 18
+} zt_event_t;
+
+typedef enum {
+ ZT_FLUSH_READ = 1,
+ ZT_FLUSH_WRITE = 2,
+ ZT_FLUSH_BOTH = (ZT_FLUSH_READ | ZT_FLUSH_WRITE),
+ ZT_FLUSH_EVENT = 4,
+ ZT_FLUSH_ALL = (ZT_FLUSH_READ | ZT_FLUSH_WRITE | ZT_FLUSH_EVENT)
+} zt_flush_t;
+
+typedef enum {
+ ZT_IOMUX_READ = 1,
+ ZT_IOMUX_WRITE = 2,
+ ZT_IOMUX_WRITEEMPTY = 4,
+ ZT_IOMUX_SIGEVENT = 8,
+ ZT_IOMUX_NOWAIT = 256
+} zt_iomux_t;
+
+typedef enum {
+ ZT_ONHOOK = 0,
+ ZT_OFFHOOK = 1,
+ ZT_WINK = 2,
+ ZT_FLASH = 3,
+ ZT_START = 4,
+ ZT_RING = 5,
+ ZT_RINGOFF = 6
+} zt_hookstate_t;
+
+typedef enum {
+ ZT_MAINT_NONE = 0, /* Normal Mode */
+ ZT_MAINT_LOCALLOOP = 1, /* Local Loopback */
+ ZT_MAINT_REMOTELOOP = 2, /* Remote Loopback */
+ ZT_MAINT_LOOPUP = 3, /* Send Loopup Code */
+ ZT_MAINT_LOOPDOWN = 4, /* Send Loopdown Code */
+ ZT_MAINT_LOOPSTOP = 5 /* Stop Sending Loop Codes */
+} zt_maintenance_mode_t;
+
+typedef enum {
+/* Signalling type */
+ZT_SIG_NONE = 0, /* chan not configured. */
+
+ZT_SIG_FXSLS = ((1 << 0) | (1 << 13)), /* FXS, Loopstart */
+ZT_SIG_FXSGS = ((1 << 1) | (1 << 13)), /* FXS, Groundstart */
+ZT_SIG_FXSKS = ((1 << 2) | (1 << 13)), /* FXS, Kewlstart */
+ZT_SIG_FXOLS = ((1 << 3) | (1 << 12)), /* FXO, Loopstart */
+ZT_SIG_FXOGS = ((1 << 4) | (1 << 12)), /* FXO, Groupstart */
+ZT_SIG_FXOKS = ((1 << 5) | (1 << 12)), /* FXO, Kewlstart */
+ZT_SIG_EM = (1 << 6), /* E&M */
+ZT_SIG_CLEAR = (1 << 7),
+ZT_SIG_HDLCRAW = ((1 << 8) | ZT_SIG_CLEAR),
+ZT_SIG_HDLCFCS = ((1 << 9) | ZT_SIG_HDLCRAW),
+ZT_SIG_CAS = (1 << 15),
+ZT_SIG_HARDHDLC = ((1 << 19) | ZT_SIG_CLEAR),
+} zt_sigtype_t;
+
+typedef enum {
+ZT_DBIT = 1,
+ZT_CBIT = 2,
+ZT_BBIT = 4,
+ZT_ABIT = 8
+} zt_cas_bit_t;
+
+/* Defines */
+
+#define ZT_MAX_BLOCKSIZE 8192
+#define ZT_DEFAULT_MTU_MRU 2048
+
+/* ioctl defines */
+
+#define ZT_CODE 'J'
+#define DAHDI_CODE 0xDA
+
+
+#define ZT_GET_BLOCKSIZE _IOR (ZT_CODE, 1, int) /* Get Transfer Block Size. */
+#define ZT_SET_BLOCKSIZE _IOW (ZT_CODE, 2, int) /* Set Transfer Block Size. */
+#define ZT_FLUSH _IOW (ZT_CODE, 3, int) /* Flush Buffer(s) and stop I/O */
+#define ZT_SYNC _IOW (ZT_CODE, 4, int) /* Wait for Write to Finish */
+#define ZT_GET_PARAMS _IOR (ZT_CODE, 5, struct zt_params) /* Get channel parameters */
+#define ZT_SET_PARAMS _IOW (ZT_CODE, 6, struct zt_params) /* Set channel parameters */
+#define ZT_HOOK _IOW (ZT_CODE, 7, int) /* Set Hookswitch Status */
+#define ZT_GETEVENT _IOR (ZT_CODE, 8, int) /* Get Signalling Event */
+#define ZT_IOMUX _IOWR (ZT_CODE, 9, int) /* Wait for something to happen (IO Mux) */
+#define ZT_SPANSTAT _IOWR (ZT_CODE, 10, struct zt_spaninfo) /* Get Span Status */
+#define ZT_MAINT _IOW (ZT_CODE, 11, struct zt_maintinfo)/* Set Maintenance Mode for a span */
+#define ZT_GETCONF _IOWR (ZT_CODE, 12, struct zt_confinfo) /* Get Conference Mode */
+#define ZT_SETCONF _IOWR (ZT_CODE, 13, struct zt_confinfo) /* Set Conference Mode */
+#define ZT_CONFLINK _IOW (ZT_CODE, 14, struct zt_confinfo) /* Setup or Remove Conference Link */
+#define ZT_CONFDIAG _IOR (ZT_CODE, 15, int) /* Display Conference Diagnostic Information on Console */
+
+#define ZT_GETGAINS _IOWR (ZT_CODE, 16, struct zt_gains) /* Get Channel audio gains */
+#define ZT_SETGAINS _IOWR (ZT_CODE, 17, struct zt_gains) /* Set Channel audio gains */
+#define ZT_SPANCONFIG _IOW (ZT_CODE, 18, struct zt_lineconfig)/* Set Line (T1) Configurations and start system */
+#define ZT_CHANCONFIG _IOW (ZT_CODE, 19, struct zt_chanconfig)/* Set Channel Configuration */
+#define ZT_SET_BUFINFO _IOW (ZT_CODE, 27, struct zt_bufferinfo)/* Set buffer policy */
+#define ZT_GET_BUFINFO _IOR (ZT_CODE, 28, struct zt_bufferinfo)/* Get current buffer info */
+#define ZT_AUDIOMODE _IOW (ZT_CODE, 32, int) /* Set a clear channel into audio mode */
+#define ZT_ECHOCANCEL _IOW (ZT_CODE, 33, int) /* Control Echo Canceller */
+#define ZT_HDLCRAWMODE _IOW (ZT_CODE, 36, int) /* Set a clear channel into HDLC w/out FCS checking/calculation mode */
+#define ZT_HDLCFCSMODE _IOW (ZT_CODE, 37, int) /* Set a clear channel into HDLC w/ FCS mode */
+
+/* Specify a channel on /dev/ftdm/chan -- must be done before any other ioctl's and is only valid on /dev/ftdm/chan */
+#define ZT_SPECIFY _IOW (ZT_CODE, 38, int)
+
+/* Temporarily set the law on a channel to ZT_LAW_DEFAULT, ZT_LAW_ALAW, or ZT_LAW_MULAW. Is reset on close. */
+#define ZT_SETLAW _IOW (ZT_CODE, 39, int)
+
+/* Temporarily set the channel to operate in linear mode when non-zero or default law if 0 */
+#define ZT_SETLINEAR _IOW (ZT_CODE, 40, int)
+
+#define ZT_GETCONFMUTE _IOR (ZT_CODE, 49, int) /* Get Conference to mute mode */
+#define ZT_ECHOTRAIN _IOW (ZT_CODE, 50, int) /* Control Echo Trainer */
+
+/* Set/Get CAS bits */
+#define ZT_SETTXBITS _IOW (ZT_CODE, 43, int)
+#define ZT_GETRXBITS _IOR (ZT_CODE, 45, int)
+
+#define DAHDI_GET_BLOCKSIZE _IOR (DAHDI_CODE, 1, int) /* Get Transfer Block Size. */
+#define DAHDI_SET_BLOCKSIZE _IOW (DAHDI_CODE, 1, int) /* Set Transfer Block Size. */
+#define DAHDI_FLUSH _IOW (DAHDI_CODE, 3, int) /* Flush Buffer(s) and stop I/O */
+#define DAHDI_SYNC _IO (DAHDI_CODE, 4) /* Wait for Write to Finish */
+#define DAHDI_GET_PARAMS _IOR (DAHDI_CODE, 5, struct zt_params) /* Get channel parameters */
+#define DAHDI_SET_PARAMS _IOW (DAHDI_CODE, 5, struct zt_params) /* Set channel parameters */
+#define DAHDI_HOOK _IOW (DAHDI_CODE, 7, int) /* Set Hookswitch Status */
+#define DAHDI_GETEVENT _IOR (DAHDI_CODE, 8, int) /* Get Signalling Event */
+#define DAHDI_IOMUX _IOWR (DAHDI_CODE, 9, int) /* Wait for something to happen (IO Mux) */
+#define DAHDI_SPANSTAT _IOWR (DAHDI_CODE, 10, struct zt_spaninfo) /* Get Span Status */
+#define DAHDI_MAINT _IOW (DAHDI_CODE, 11, struct zt_maintinfo) /* Set Maintenance Mode for a span */
+#define DAHDI_GETCONF _IOR (DAHDI_CODE, 12, struct zt_confinfo) /* Get Conference Mode */
+#define DAHDI_SETCONF _IOW (DAHDI_CODE, 12, struct zt_confinfo) /* Set Conference Mode */
+#define DAHDI_CONFLINK _IOW (DAHDI_CODE, 14, struct zt_confinfo) /* Setup or Remove Conference Link */
+#define DAHDI_CONFDIAG _IOR (DAHDI_CODE, 15, int) /* Display Conference Diagnostic Information on Console */
+
+#define DAHDI_GETGAINS _IOR (DAHDI_CODE, 16, struct zt_gains) /* Get Channel audio gains */
+#define DAHDI_SETGAINS _IOW (DAHDI_CODE, 16, struct zt_gains) /* Set Channel audio gains */
+#define DAHDI_SPANCONFIG _IOW (DAHDI_CODE, 18, struct zt_lineconfig)/* Set Line (T1) Configurations and start system */
+#define DAHDI_CHANCONFIG _IOW (DAHDI_CODE, 19, struct zt_chanconfig)/* Set Channel Configuration */
+#define DAHDI_SET_BUFINFO _IOW (DAHDI_CODE, 27, struct zt_bufferinfo)/* Set buffer policy */
+#define DAHDI_GET_BUFINFO _IOR (DAHDI_CODE, 27, struct zt_bufferinfo)/* Get current buffer info */
+#define DAHDI_AUDIOMODE _IOW (DAHDI_CODE, 32, int) /* Set a clear channel into audio mode */
+#define DAHDI_ECHOCANCEL _IOW (DAHDI_CODE, 33, int) /* Control Echo Canceller */
+#define DAHDI_HDLCRAWMODE _IOW (DAHDI_CODE, 36, int) /* Set a clear channel into HDLC w/out FCS checking/calculation mode */
+#define DAHDI_HDLCFCSMODE _IOW (DAHDI_CODE, 37, int) /* Set a clear channel into HDLC w/ FCS mode */
+
+/* Specify a channel on /dev/dahdi/chan -- must be done before any other ioctl's and is only valid on /dev/dahdi/chan */
+#define DAHDI_SPECIFY _IOW (DAHDI_CODE, 38, int)
+
+/* Temporarily set the law on a channel to DAHDI_LAW_DEFAULT, DAHDI_LAW_ALAW, or DAHDI_LAW_MULAW. Is reset on close. */
+#define DAHDI_SETLAW _IOW (DAHDI_CODE, 39, int)
+
+/* Temporarily set the channel to operate in linear mode when non-zero or default law if 0 */
+#define DAHDI_SETLINEAR _IOW (DAHDI_CODE, 40, int)
+
+#define DAHDI_GETCONFMUTE _IOR (DAHDI_CODE, 49, int) /* Get Conference to mute mode */
+#define DAHDI_ECHOTRAIN _IOW (DAHDI_CODE, 50, int) /* Control Echo Trainer */
+
+/* Set/Get CAS bits */
+#define DAHDI_SETTXBITS _IOW (DAHDI_CODE, 43, int)
+#define DAHDI_GETRXBITS _IOR (DAHDI_CODE, 43, int)
+
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/g711.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/g711.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/g711.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,104 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * g711.c - A-law and u-law transcoding routines
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2006 Steve Underwood
+ *
+ * Despite my general liking of the GPL, I place this code in the
+ * public domain for the benefit of all mankind - even the slimy
+ * ones who might try to proprietize my work and use it to my
+ * detriment.
+ *
+ * $Id: g711.c,v 1.1 2006/06/07 15:46:39 steveu Exp $
+ */
+
+/*! \file */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#ifndef _MSC_VER
+#include <inttypes.h>
+#ifdef HAVE_TGMATH_H
+#include <tgmath.h>
+#endif
+#endif
+
+#include "g711.h"
+
+/* Copied from the CCITT G.711 specification */
+static const uint8_t ulaw_to_alaw_table[256] =
+ {
+ 42, 43, 40, 41, 46, 47, 44, 45, 34, 35, 32, 33, 38, 39, 36, 37,
+ 58, 59, 56, 57, 62, 63, 60, 61, 50, 51, 48, 49, 54, 55, 52, 53,
+ 10, 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, 1, 6, 7, 4, 26,
+ 27, 24, 25, 30, 31, 28, 29, 18, 19, 16, 17, 22, 23, 20, 21, 106,
+ 104, 105, 110, 111, 108, 109, 98, 99, 96, 97, 102, 103, 100, 101, 122, 120,
+ 126, 127, 124, 125, 114, 115, 112, 113, 118, 119, 116, 117, 75, 73, 79, 77,
+ 66, 67, 64, 65, 70, 71, 68, 69, 90, 91, 88, 89, 94, 95, 92, 93,
+ 82, 82, 83, 83, 80, 80, 81, 81, 86, 86, 87, 87, 84, 84, 85, 85,
+ 170, 171, 168, 169, 174, 175, 172, 173, 162, 163, 160, 161, 166, 167, 164, 165,
+ 186, 187, 184, 185, 190, 191, 188, 189, 178, 179, 176, 177, 182, 183, 180, 181,
+ 138, 139, 136, 137, 142, 143, 140, 141, 130, 131, 128, 129, 134, 135, 132, 154,
+ 155, 152, 153, 158, 159, 156, 157, 146, 147, 144, 145, 150, 151, 148, 149, 234,
+ 232, 233, 238, 239, 236, 237, 226, 227, 224, 225, 230, 231, 228, 229, 250, 248,
+ 254, 255, 252, 253, 242, 243, 240, 241, 246, 247, 244, 245, 203, 201, 207, 205,
+ 194, 195, 192, 193, 198, 199, 196, 197, 218, 219, 216, 217, 222, 223, 220, 221,
+ 210, 210, 211, 211, 208, 208, 209, 209, 214, 214, 215, 215, 212, 212, 213, 213
+ };
+
+/* These transcoding tables are copied from the CCITT G.711 specification. To achieve
+ optimal results, do not change them. */
+
+static const uint8_t alaw_to_ulaw_table[256] =
+ {
+ 42, 43, 40, 41, 46, 47, 44, 45, 34, 35, 32, 33, 38, 39, 36, 37,
+ 57, 58, 55, 56, 61, 62, 59, 60, 49, 50, 47, 48, 53, 54, 51, 52,
+ 10, 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, 1, 6, 7, 4, 5,
+ 26, 27, 24, 25, 30, 31, 28, 29, 18, 19, 16, 17, 22, 23, 20, 21,
+ 98, 99, 96, 97, 102, 103, 100, 101, 93, 93, 92, 92, 95, 95, 94, 94,
+ 116, 118, 112, 114, 124, 126, 120, 122, 106, 107, 104, 105, 110, 111, 108, 109,
+ 72, 73, 70, 71, 76, 77, 74, 75, 64, 65, 63, 63, 68, 69, 66, 67,
+ 86, 87, 84, 85, 90, 91, 88, 89, 79, 79, 78, 78, 82, 83, 80, 81,
+ 170, 171, 168, 169, 174, 175, 172, 173, 162, 163, 160, 161, 166, 167, 164, 165,
+ 185, 186, 183, 184, 189, 190, 187, 188, 177, 178, 175, 176, 181, 182, 179, 180,
+ 138, 139, 136, 137, 142, 143, 140, 141, 130, 131, 128, 129, 134, 135, 132, 133,
+ 154, 155, 152, 153, 158, 159, 156, 157, 146, 147, 144, 145, 150, 151, 148, 149,
+ 226, 227, 224, 225, 230, 231, 228, 229, 221, 221, 220, 220, 223, 223, 222, 222,
+ 244, 246, 240, 242, 252, 254, 248, 250, 234, 235, 232, 233, 238, 239, 236, 237,
+ 200, 201, 198, 199, 204, 205, 202, 203, 192, 193, 191, 191, 196, 197, 194, 195,
+ 214, 215, 212, 213, 218, 219, 216, 217, 207, 207, 206, 206, 210, 211, 208, 209
+ };
+
+uint8_t alaw_to_ulaw(uint8_t alaw)
+{
+ return alaw_to_ulaw_table[alaw];
+}
+/*- End of function --------------------------------------------------------*/
+
+uint8_t ulaw_to_alaw(uint8_t ulaw)
+{
+ return ulaw_to_alaw_table[ulaw];
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/freetdm/src/hashtable.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/hashtable.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/hashtable.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * 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.
+ */
+
+#include "freetdm.h"
+#include "hashtable.h"
+#include "hashtable_private.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+/*
+ Credit for primes table: Aaron Krowne
+ http://br.endernet.org/~akrowne/
+ http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
+*/
+static const unsigned int primes[] = {
+ 53, 97, 193, 389,
+ 769, 1543, 3079, 6151,
+ 12289, 24593, 49157, 98317,
+ 196613, 393241, 786433, 1572869,
+ 3145739, 6291469, 12582917, 25165843,
+ 50331653, 100663319, 201326611, 402653189,
+ 805306457, 1610612741
+};
+const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]);
+const float max_load_factor = 0.65f;
+
+/*****************************************************************************/
+FT_DECLARE(struct hashtable *)
+create_hashtable(unsigned int minsize,
+ unsigned int (*hashf) (void*),
+ int (*eqf) (void*,void*))
+{
+ struct hashtable *h;
+ unsigned int pindex, size = primes[0];
+ /* Check requested hashtable isn't too large */
+ if (minsize > (1u << 30)) return NULL;
+ /* Enforce size as prime */
+ for (pindex=0; pindex < prime_table_length; pindex++) {
+ if (primes[pindex] > minsize) { size = primes[pindex]; break; }
+ }
+ h = (struct hashtable *)ftdm_malloc(sizeof(struct hashtable));
+ if (NULL == h) return NULL; /*oom*/
+ h->table = (struct entry **)ftdm_malloc(sizeof(struct entry*) * size);
+ if (NULL == h->table) { ftdm_safe_free(h); return NULL; } /*oom*/
+ memset(h->table, 0, size * sizeof(struct entry *));
+ h->tablelength = size;
+ h->primeindex = pindex;
+ h->entrycount = 0;
+ h->hashfn = hashf;
+ h->eqfn = eqf;
+ h->loadlimit = (unsigned int) ceil(size * max_load_factor);
+ return h;
+}
+
+/*****************************************************************************/
+unsigned int
+hash(struct hashtable *h, void *k)
+{
+ /* Aim to protect against poor hash functions by adding logic here
+ * - logic taken from java 1.4 hashtable source */
+ unsigned int i = h->hashfn(k);
+ i += ~(i << 9);
+ i ^= ((i >> 14) | (i << 18)); /* >>> */
+ i += (i << 4);
+ i ^= ((i >> 10) | (i << 22)); /* >>> */
+ return i;
+}
+
+/*****************************************************************************/
+static int
+hashtable_expand(struct hashtable *h)
+{
+ /* Double the size of the table to accomodate more entries */
+ struct entry **newtable;
+ struct entry *e;
+ struct entry **pE;
+ unsigned int newsize, i, index;
+ /* Check we're not hitting max capacity */
+ if (h->primeindex == (prime_table_length - 1)) return 0;
+ newsize = primes[++(h->primeindex)];
+
+ newtable = (struct entry **)ftdm_malloc(sizeof(struct entry*) * newsize);
+ if (NULL != newtable)
+ {
+ memset(newtable, 0, newsize * sizeof(struct entry *));
+ /* This algorithm is not 'stable'. ie. it reverses the list
+ * when it transfers entries between the tables */
+ for (i = 0; i < h->tablelength; i++) {
+ while (NULL != (e = h->table[i])) {
+ h->table[i] = e->next;
+ index = indexFor(newsize,e->h);
+ e->next = newtable[index];
+ newtable[index] = e;
+ }
+ }
+ ftdm_safe_free(h->table);
+ h->table = newtable;
+ }
+ /* Plan B: realloc instead */
+ else
+ {
+ newtable = (struct entry **)
+ realloc(h->table, newsize * sizeof(struct entry *));
+ if (NULL == newtable) { (h->primeindex)--; return 0; }
+ h->table = newtable;
+ memset(newtable[h->tablelength], 0, newsize - h->tablelength);
+ for (i = 0; i < h->tablelength; i++) {
+ for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) {
+ index = indexFor(newsize,e->h);
+ if (index == i)
+ {
+ pE = &(e->next);
+ }
+ else
+ {
+ *pE = e->next;
+ e->next = newtable[index];
+ newtable[index] = e;
+ }
+ }
+ }
+ }
+ h->tablelength = newsize;
+ h->loadlimit = (unsigned int) ceil(newsize * max_load_factor);
+ return -1;
+}
+
+/*****************************************************************************/
+FT_DECLARE(unsigned int)
+hashtable_count(struct hashtable *h)
+{
+ return h->entrycount;
+}
+
+/*****************************************************************************/
+FT_DECLARE(int)
+hashtable_insert(struct hashtable *h, void *k, void *v, hashtable_flag_t flags)
+{
+ /* This method allows duplicate keys - but they shouldn't be used */
+ unsigned int index;
+ struct entry *e;
+ if (++(h->entrycount) > h->loadlimit)
+ {
+ /* Ignore the return value. If expand fails, we should
+ * still try cramming just this value into the existing table
+ * -- we may not have memory for a larger table, but one more
+ * element may be ok. Next time we insert, we'll try expanding again.*/
+ hashtable_expand(h);
+ }
+ e = (struct entry *)ftdm_malloc(sizeof(struct entry));
+ if (NULL == e) { --(h->entrycount); return 0; } /*oom*/
+ e->h = hash(h,k);
+ index = indexFor(h->tablelength,e->h);
+ e->k = k;
+ e->v = v;
+ e->flags = flags;
+ e->next = h->table[index];
+ h->table[index] = e;
+ return -1;
+}
+
+/*****************************************************************************/
+FT_DECLARE(void *) /* returns value associated with key */
+hashtable_search(struct hashtable *h, void *k)
+{
+ struct entry *e;
+ unsigned int hashvalue, index;
+ hashvalue = hash(h,k);
+ index = indexFor(h->tablelength,hashvalue);
+ e = h->table[index];
+ while (NULL != e)
+ {
+ /* Check hash value to short circuit heavier comparison */
+ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v;
+ e = e->next;
+ }
+ return NULL;
+}
+
+/*****************************************************************************/
+FT_DECLARE(void *) /* returns value associated with key */
+hashtable_remove(struct hashtable *h, void *k)
+{
+ /* TODO: consider compacting the table when the load factor drops enough,
+ * or provide a 'compact' method. */
+
+ struct entry *e;
+ struct entry **pE;
+ void *v;
+ unsigned int hashvalue, index;
+
+ hashvalue = hash(h,k);
+ index = indexFor(h->tablelength,hash(h,k));
+ pE = &(h->table[index]);
+ e = *pE;
+ while (NULL != e)
+ {
+ /* Check hash value to short circuit heavier comparison */
+ if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
+ {
+ *pE = e->next;
+ h->entrycount--;
+ v = e->v;
+ if (e->flags & HASHTABLE_FLAG_FREE_KEY) {
+ freekey(e->k);
+ }
+ ftdm_safe_free(e);
+ return v;
+ }
+ pE = &(e->next);
+ e = e->next;
+ }
+ return NULL;
+}
+
+/*****************************************************************************/
+/* destroy */
+FT_DECLARE(void)
+hashtable_destroy(struct hashtable *h)
+{
+ unsigned int i;
+ struct entry *e, *f;
+ struct entry **table = h->table;
+
+ for (i = 0; i < h->tablelength; i++)
+ {
+ e = table[i];
+ while (NULL != e)
+ { f = e; e = e->next; if (f->flags & HASHTABLE_FLAG_FREE_KEY) freekey(f->k); if (f->flags & HASHTABLE_FLAG_FREE_VALUE) ftdm_safe_free(f->v); ftdm_safe_free(f); }
+ }
+
+ ftdm_safe_free(h->table);
+ ftdm_safe_free(h);
+}
+
+FT_DECLARE(struct hashtable_iterator *) hashtable_next(struct hashtable_iterator *i)
+{
+
+ if (i->e) {
+ if ((i->e = i->e->next) != 0) {
+ return i;
+ } else {
+ i->pos++;
+ }
+ }
+
+ while(i->pos < i->h->tablelength && !i->h->table[i->pos]) {
+ i->pos++;
+ }
+
+ if (i->pos >= i->h->tablelength) {
+ return NULL;
+ }
+
+ if ((i->e = i->h->table[i->pos]) != 0) {
+ return i;
+ }
+
+ return NULL;
+}
+
+FT_DECLARE(struct hashtable_iterator *) hashtable_first(struct hashtable *h)
+{
+ h->iterator.pos = 0;
+ h->iterator.e = NULL;
+ h->iterator.h = h;
+ return hashtable_next(&h->iterator);
+}
+
+
+
+FT_DECLARE(void) hashtable_this(struct hashtable_iterator *i, const void **key, int *klen, void **val)
+{
+ if (i->e) {
+ if (key) {
+ *key = i->e->k;
+ }
+ if (klen) {
+ *klen = (int)strlen(i->e->k);
+ }
+ if (val) {
+ *val = i->e->v;
+ }
+ } else {
+ if (key) {
+ *key = NULL;
+ }
+ if (klen) {
+ *klen = 0;
+ }
+ if (val) {
+ *val = NULL;
+ }
+ }
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/freetdm/src/hashtable_itr.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/hashtable_itr.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/hashtable_itr.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2002, 2004, Christopher Clark
+ * 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.
+ */
+
+#include "freetdm.h"
+#include "hashtable.h"
+#include "hashtable_private.h"
+#include "hashtable_itr.h"
+#include <stdlib.h> /* defines NULL */
+
+/*****************************************************************************/
+/* hashtable_iterator - iterator constructor */
+
+struct hashtable_itr *
+hashtable_iterator(struct hashtable *h)
+{
+ unsigned int i, tablelength;
+ struct hashtable_itr *itr = ftdm_malloc(sizeof(struct hashtable_itr));
+ if (NULL == itr) return NULL;
+ itr->h = h;
+ itr->e = NULL;
+ itr->parent = NULL;
+ tablelength = h->tablelength;
+ itr->index = tablelength;
+ if (0 == h->entrycount) return itr;
+
+ for (i = 0; i < tablelength; i++)
+ {
+ if (NULL != h->table[i])
+ {
+ itr->e = h->table[i];
+ itr->index = i;
+ break;
+ }
+ }
+ return itr;
+}
+
+/*****************************************************************************/
+/* advance - advance the iterator to the next element
+ * returns zero if advanced to end of table */
+
+int
+hashtable_iterator_advance(struct hashtable_itr *itr)
+{
+ unsigned int j,tablelength;
+ struct entry **table;
+ struct entry *next;
+ if (NULL == itr->e) return 0; /* stupidity check */
+
+ next = itr->e->next;
+ if (NULL != next)
+ {
+ itr->parent = itr->e;
+ itr->e = next;
+ return -1;
+ }
+ tablelength = itr->h->tablelength;
+ itr->parent = NULL;
+ if (tablelength <= (j = ++(itr->index)))
+ {
+ itr->e = NULL;
+ return 0;
+ }
+ table = itr->h->table;
+ while (NULL == (next = table[j]))
+ {
+ if (++j >= tablelength)
+ {
+ itr->index = tablelength;
+ itr->e = NULL;
+ return 0;
+ }
+ }
+ itr->index = j;
+ itr->e = next;
+ return -1;
+}
+
+/*****************************************************************************/
+/* remove - remove the entry at the current iterator position
+ * and advance the iterator, if there is a successive
+ * element.
+ * If you want the value, read it before you remove:
+ * beware memory leaks if you don't.
+ * Returns zero if end of iteration. */
+
+int
+hashtable_iterator_remove(struct hashtable_itr *itr)
+{
+ struct entry *remember_e, *remember_parent;
+ int ret;
+
+ /* Do the removal */
+ if (NULL == (itr->parent))
+ {
+ /* element is head of a chain */
+ itr->h->table[itr->index] = itr->e->next;
+ } else {
+ /* element is mid-chain */
+ itr->parent->next = itr->e->next;
+ }
+ /* itr->e is now outside the hashtable */
+ remember_e = itr->e;
+ itr->h->entrycount--;
+ freekey(remember_e->k);
+
+ /* Advance the iterator, correcting the parent */
+ remember_parent = itr->parent;
+ ret = hashtable_iterator_advance(itr);
+ if (itr->parent == remember_e) { itr->parent = remember_parent; }
+ ftdm_safe_free(remember_e);
+ return ret;
+}
+
+/*****************************************************************************/
+int /* returns zero if not found */
+hashtable_iterator_search(struct hashtable_itr *itr,
+ struct hashtable *h, void *k)
+{
+ struct entry *e, *parent;
+ unsigned int hashvalue, index;
+
+ hashvalue = hash(h,k);
+ index = indexFor(h->tablelength,hashvalue);
+
+ e = h->table[index];
+ parent = NULL;
+ while (NULL != e)
+ {
+ /* Check hash value to short circuit heavier comparison */
+ if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
+ {
+ itr->index = index;
+ itr->e = e;
+ itr->parent = parent;
+ itr->h = h;
+ return -1;
+ }
+ parent = e;
+ e = e->next;
+ }
+ return 0;
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/freetdm/src/include/freetdm.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/include/freetdm.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/freetdm.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,968 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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:
+ *
+ * Moises Silva <moy@sangoma.com>
+ *
+ */
+
+#ifndef FREETDM_H
+#define FREETDM_H
+
+
+#if !defined(_XOPEN_SOURCE) && !defined(__FreeBSD__)
+#define _XOPEN_SOURCE 600
+#endif
+
+#ifndef HAVE_STRINGS_H
+#define HAVE_STRINGS_H 1
+#endif
+#ifndef HAVE_SYS_SOCKET_H
+#define HAVE_SYS_SOCKET_H 1
+#endif
+
+#ifndef __WINDOWS__
+#if defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32) || defined(_WIN64)
+#define __WINDOWS__
+#endif
+#endif
+
+#ifdef _MSC_VER
+#if defined(FT_DECLARE_STATIC)
+#define FT_DECLARE(type) type __stdcall
+#define FT_DECLARE_NONSTD(type) type __cdecl
+#define FT_DECLARE_DATA
+#elif defined(FREETDM_EXPORTS)
+#define FT_DECLARE(type) __declspec(dllexport) type __stdcall
+#define FT_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl
+#define FT_DECLARE_DATA __declspec(dllexport)
+#else
+#define FT_DECLARE(type) __declspec(dllimport) type __stdcall
+#define FT_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl
+#define FT_DECLARE_DATA __declspec(dllimport)
+#endif
+#define EX_DECLARE_DATA __declspec(dllexport)
+#else
+#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(HAVE_VISIBILITY)
+#define FT_DECLARE(type) __attribute__((visibility("default"))) type
+#define FT_DECLARE_NONSTD(type) __attribute__((visibility("default"))) type
+#define FT_DECLARE_DATA __attribute__((visibility("default")))
+#else
+#define FT_DECLARE(type) type
+#define FT_DECLARE_NONSTD(type) type
+#define FT_DECLARE_DATA
+#endif
+#define EX_DECLARE_DATA
+#endif
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+#if (_MSC_VER >= 1400) /* VC8+ */
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+#ifndef _CRT_NONSTDC_NO_DEPRECATE
+#define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+#endif
+#ifndef strcasecmp
+#define strcasecmp(s1, s2) _stricmp(s1, s2)
+#endif
+#ifndef strncasecmp
+#define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n)
+#endif
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#ifndef S_IRUSR
+#define S_IRUSR _S_IREAD
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR _S_IWRITE
+#endif
+#undef HAVE_STRINGS_H
+#undef HAVE_SYS_SOCKET_H
+/* disable warning for zero length array in a struct */
+/* this will cause errors on c99 and ansi compliant compilers and will need to be fixed in the wanpipe header files */
+#pragma warning(disable:4706)
+#pragma comment(lib, "Winmm")
+#endif
+
+#define FTDM_THREAD_STACKSIZE 240 * 1024
+#define FTDM_ENUM_NAMES(_NAME, _STRINGS) static const char * _NAME [] = { _STRINGS , NULL };
+#define FTDM_STR2ENUM_P(_FUNC1, _FUNC2, _TYPE) FT_DECLARE(_TYPE) _FUNC1 (const char *name); FT_DECLARE(const char *) _FUNC2 (_TYPE type);
+#define FTDM_STR2ENUM(_FUNC1, _FUNC2, _TYPE, _STRINGS, _MAX) \
+ FT_DECLARE(_TYPE) _FUNC1 (const char *name) \
+ { \
+ int i; \
+ _TYPE t = _MAX ; \
+ \
+ for (i = 0; i < _MAX ; i++) { \
+ if (!strcasecmp(name, _STRINGS[i])) { \
+ t = (_TYPE) i; \
+ break; \
+ } \
+ } \
+ \
+ return t; \
+ } \
+ FT_DECLARE(const char *) _FUNC2 (_TYPE type) \
+ { \
+ if (type > _MAX) { \
+ type = _MAX; \
+ } \
+ return _STRINGS[(int)type]; \
+ } \
+
+#define ftdm_true(expr) \
+ (expr && ( !strcasecmp(expr, "yes") || \
+ !strcasecmp(expr, "on") || \
+ !strcasecmp(expr, "true") || \
+ !strcasecmp(expr, "enabled") || \
+ !strcasecmp(expr, "active") || \
+ atoi(expr))) ? 1 : 0
+
+
+#include <time.h>
+#ifndef __WINDOWS__
+#include <sys/time.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include <assert.h>
+#include "ftdm_types.h"
+#include "hashtable.h"
+#include "ftdm_config.h"
+#include "g711.h"
+#include "libteletone.h"
+#include "ftdm_buffer.h"
+#include "ftdm_threadmutex.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __WINDOWS__
+#define ftdm_sleep(x) Sleep(x)
+#else
+#define ftdm_sleep(x) usleep(x * 1000)
+#endif
+
+#ifdef NDEBUG
+#undef assert
+#define assert(_Expression) ((void)(_Expression))
+#endif
+
+#define FTDM_MAX_CHANNELS_PHYSICAL_SPAN 32
+#define FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN 32
+#define FTDM_MAX_CHANNELS_SPAN FTDM_MAX_CHANNELS_PHYSICAL_SPAN * FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN
+#define FTDM_MAX_SPANS_INTERFACE 128
+
+#define FTDM_MAX_CHANNELS_GROUP 1024
+#define FTDM_MAX_GROUPS_INTERFACE FTDM_MAX_SPANS_INTERFACE
+
+#define GOTO_STATUS(label,st) status = st; goto label ;
+
+#define ftdm_copy_string(x,y,z) strncpy(x, y, z - 1)
+#define ftdm_set_string(x,y) strncpy(x, y, sizeof(x)-1)
+#define ftdm_strlen_zero(s) (!s || *s == '\0')
+#define ftdm_strlen_zero_buf(s) (*s == '\0')
+
+
+#define ftdm_channel_test_feature(obj, flag) ((obj)->features & flag)
+#define ftdm_channel_set_feature(obj, flag) (obj)->features |= (flag)
+#define ftdm_channel_clear_feature(obj, flag) (obj)->features &= ~(flag)
+#define ftdm_channel_set_member_locked(obj, _m, _v) ftdm_mutex_lock(obj->mutex); obj->_m = _v; ftdm_mutex_unlock(obj->mutex)
+
+/*!
+ \brief Test for the existance of a flag on an arbitary object
+ \command obj the object to test
+ \command flag the or'd list of flags to test
+ \return true value if the object has the flags defined
+*/
+#define ftdm_test_flag(obj, flag) ((obj)->flags & flag)
+#define ftdm_test_pflag(obj, flag) ((obj)->pflags & flag)
+#define ftdm_test_sflag(obj, flag) ((obj)->sflags & flag)
+
+
+#define ftdm_set_alarm_flag(obj, flag) (obj)->alarm_flags |= (flag)
+#define ftdm_clear_alarm_flag(obj, flag) (obj)->alarm_flags &= ~(flag)
+#define ftdm_test_alarm_flag(obj, flag) ((obj)->alarm_flags & flag)
+
+/*!
+ \brief Set a flag on an arbitrary object
+ \command obj the object to set the flags on
+ \command flag the or'd list of flags to set
+*/
+#define ftdm_set_flag(obj, flag) (obj)->flags |= (flag)
+#define ftdm_set_flag_locked(obj, flag) assert(obj->mutex != NULL); \
+ ftdm_mutex_lock(obj->mutex); \
+ (obj)->flags |= (flag); \
+ ftdm_mutex_unlock(obj->mutex);
+
+#define ftdm_set_pflag(obj, flag) (obj)->pflags |= (flag)
+#define ftdm_set_pflag_locked(obj, flag) assert(obj->mutex != NULL); \
+ ftdm_mutex_lock(obj->mutex); \
+ (obj)->pflags |= (flag); \
+ ftdm_mutex_unlock(obj->mutex);
+
+#define ftdm_set_sflag(obj, flag) (obj)->sflags |= (flag)
+#define ftdm_set_sflag_locked(obj, flag) assert(obj->mutex != NULL); \
+ ftdm_mutex_lock(obj->mutex); \
+ (obj)->sflags |= (flag); \
+ ftdm_mutex_unlock(obj->mutex);
+
+/*!
+ \brief Clear a flag on an arbitrary object while locked
+ \command obj the object to test
+ \command flag the or'd list of flags to clear
+*/
+#define ftdm_clear_flag(obj, flag) (obj)->flags &= ~(flag)
+
+#define ftdm_clear_flag_locked(obj, flag) assert(obj->mutex != NULL); ftdm_mutex_lock(obj->mutex); (obj)->flags &= ~(flag); ftdm_mutex_unlock(obj->mutex);
+
+#define ftdm_clear_pflag(obj, flag) (obj)->pflags &= ~(flag)
+
+#define ftdm_clear_pflag_locked(obj, flag) assert(obj->mutex != NULL); ftdm_mutex_lock(obj->mutex); (obj)->pflags &= ~(flag); ftdm_mutex_unlock(obj->mutex);
+
+#define ftdm_clear_sflag(obj, flag) (obj)->sflags &= ~(flag)
+
+#define ftdm_clear_sflag_locked(obj, flag) assert(obj->mutex != NULL); ftdm_mutex_lock(obj->mutex); (obj)->sflags &= ~(flag); ftdm_mutex_unlock(obj->mutex);
+
+
+#define ftdm_set_state_locked(obj, s) if ( obj->state == s ) { \
+ ftdm_log(FTDM_LOG_WARNING, "Why bother changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(obj->state), ftdm_channel_state2str(s)); \
+ } else if (ftdm_test_flag(obj, FTDM_CHANNEL_READY)) { \
+ ftdm_channel_state_t st = obj->state; \
+ ftdm_channel_set_state(obj, s, 1); \
+ if (obj->state == s) ftdm_log(FTDM_LOG_DEBUG, "Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s)); \
+ else ftdm_log(FTDM_LOG_WARNING, "VETO Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s)); \
+ }
+
+#define ftdm_set_state(obj, s) if ( obj->state == s ) { \
+ ftdm_log(FTDM_LOG_WARNING, "Why bother changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(obj->state), ftdm_channel_state2str(s)); \
+ } else if (ftdm_test_flag(obj, FTDM_CHANNEL_READY)) { \
+ ftdm_channel_state_t st = obj->state; \
+ ftdm_channel_set_state(obj, s, 0); \
+ if (obj->state == s) ftdm_log(FTDM_LOG_DEBUG, "Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s)); \
+ else ftdm_log(FTDM_LOG_WARNING, "VETO Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s)); \
+ }
+
+#ifdef _MSC_VER
+/* The while(0) below throws a conditional expression is constant warning */
+#pragma warning(disable:4127)
+#endif
+
+#define ftdm_set_state_locked_wait(obj, s) \
+ do { \
+ int __safety = 100; \
+ ftdm_set_state_locked(obj, s); \
+ while(__safety-- && ftdm_test_flag(obj, FTDM_CHANNEL_STATE_CHANGE)) { \
+ ftdm_sleep(10); \
+ } \
+ if(!__safety) { \
+ ftdm_log(FTDM_LOG_CRIT, "State change not completed\n"); \
+ } \
+ } while(0);
+
+#define ftdm_wait_for_flag_cleared(obj, flag, time) \
+ do { \
+ int __safety = time; \
+ while(__safety-- && ftdm_test_flag(obj, flag)) { \
+ ftdm_mutex_unlock(obj->mutex); \
+ ftdm_sleep(10); \
+ ftdm_mutex_lock(obj->mutex); \
+ } \
+ if(!__safety) { \
+ ftdm_log(FTDM_LOG_CRIT, "flag %d was never cleared\n", flag); \
+ } \
+ } while(0);
+
+#define ftdm_set_state_wait(obj, s) \
+ do { \
+ ftdm_channel_set_state(obj, s, 0); \
+ ftdm_wait_for_flag_cleared(obj, FTDM_CHANNEL_STATE_CHANGE, 100); \
+ } while(0);
+
+
+typedef enum {
+ FTDM_STATE_CHANGE_FAIL,
+ FTDM_STATE_CHANGE_SUCCESS,
+ FTDM_STATE_CHANGE_SAME,
+} ftdm_state_change_result_t;
+
+#define ftdm_set_state_r(obj, s, l, r) if ( obj->state == s ) { \
+ if (s != FTDM_CHANNEL_STATE_HANGUP) ftdm_log(FTDM_LOG_WARNING, "Why bother changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(obj->state), ftdm_channel_state2str(s)); r = FTDM_STATE_CHANGE_SAME; \
+ } else if (ftdm_test_flag(obj, FTDM_CHANNEL_READY)) { \
+ int st = obj->state; \
+ r = (ftdm_channel_set_state(obj, s, l) == FTDM_SUCCESS) ? FTDM_STATE_CHANGE_SUCCESS : FTDM_STATE_CHANGE_FAIL; \
+ if (obj->state == s) {ftdm_log(FTDM_LOG_DEBUG, "Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s));} \
+ else ftdm_log(FTDM_LOG_WARNING, "VETO Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s)); \
+ }
+
+
+#define ftdm_is_dtmf(key) ((key > 47 && key < 58) || (key > 64 && key < 69) || (key > 96 && key < 101) || key == 35 || key == 42 || key == 87 || key == 119)
+
+/*!
+ \brief Copy flags from one arbitrary object to another
+ \command dest the object to copy the flags to
+ \command src the object to copy the flags from
+ \command flags the flags to copy
+*/
+#define ftdm_copy_flags(dest, src, flags) (dest)->flags &= ~(flags); (dest)->flags |= ((src)->flags & (flags))
+
+struct ftdm_stream_handle {
+ ftdm_stream_handle_write_function_t write_function;
+ ftdm_stream_handle_raw_write_function_t raw_write_function;
+ void *data;
+ void *end;
+ ftdm_size_t data_size;
+ ftdm_size_t data_len;
+ ftdm_size_t alloc_len;
+ ftdm_size_t alloc_chunk;
+};
+
+
+FT_DECLARE_NONSTD(ftdm_status_t) ftdm_console_stream_raw_write(ftdm_stream_handle_t *handle, uint8_t *data, ftdm_size_t datalen);
+FT_DECLARE_NONSTD(ftdm_status_t) ftdm_console_stream_write(ftdm_stream_handle_t *handle, const char *fmt, ...);
+
+#define FTDM_CMD_CHUNK_LEN 1024
+#define FTDM_STANDARD_STREAM(s) memset(&s, 0, sizeof(s)); s.data = malloc(FTDM_CMD_CHUNK_LEN); \
+ assert(s.data); \
+ memset(s.data, 0, FTDM_CMD_CHUNK_LEN); \
+ s.end = s.data; \
+ s.data_size = FTDM_CMD_CHUNK_LEN; \
+ s.write_function = ftdm_console_stream_write; \
+ s.raw_write_function = ftdm_console_stream_raw_write; \
+ s.alloc_len = FTDM_CMD_CHUNK_LEN; \
+ s.alloc_chunk = FTDM_CMD_CHUNK_LEN
+
+struct ftdm_event {
+ ftdm_event_type_t e_type;
+ uint32_t enum_id;
+ ftdm_channel_t *channel;
+ void *data;
+};
+
+typedef struct ftdm_queue ftdm_queue_t;
+typedef ftdm_status_t (*ftdm_queue_create_func_t)(ftdm_queue_t **queue, ftdm_size_t capacity);
+typedef ftdm_status_t (*ftdm_queue_enqueue_func_t)(ftdm_queue_t *queue, void *obj);
+typedef void *(*ftdm_queue_dequeue_func_t)(ftdm_queue_t *queue);
+typedef ftdm_status_t (*ftdm_queue_wait_func_t)(ftdm_queue_t *queue, int ms);
+typedef ftdm_status_t (*ftdm_queue_get_interrupt_func_t)(ftdm_queue_t *queue, ftdm_interrupt_t **interrupt);
+typedef ftdm_status_t (*ftdm_queue_destroy_func_t)(ftdm_queue_t **queue);
+typedef struct ftdm_queue_handler {
+ ftdm_queue_create_func_t create;
+ ftdm_queue_enqueue_func_t enqueue;
+ ftdm_queue_dequeue_func_t dequeue;
+ ftdm_queue_wait_func_t wait;
+ ftdm_queue_get_interrupt_func_t get_interrupt;
+ ftdm_queue_destroy_func_t destroy;
+} ftdm_queue_handler_t;
+FT_DECLARE_DATA extern ftdm_queue_handler_t g_ftdm_queue_handler;
+
+/*! brief create a new queue */
+#define ftdm_queue_create(queue, capacity) g_ftdm_queue_handler.create(queue, capacity)
+
+/*! Enqueue an object */
+#define ftdm_queue_enqueue(queue, obj) g_ftdm_queue_handler.enqueue(queue, obj)
+
+/*! dequeue an object from the queue */
+#define ftdm_queue_dequeue(queue) g_ftdm_queue_handler.dequeue(queue)
+
+/*! wait ms milliseconds for a queue to have available objects, -1 to wait forever */
+#define ftdm_queue_wait(queue, ms) g_ftdm_queue_handler.wait(queue, ms)
+
+/*! get the internal interrupt object (to wait for elements to be added from the outside bypassing ftdm_queue_wait) */
+#define ftdm_queue_get_interrupt(queue, ms) g_ftdm_queue_handler.get_interrupt(queue, ms)
+
+/*! destroy the queue */
+#define ftdm_queue_destroy(queue) g_ftdm_queue_handler.destroy(queue)
+
+
+#define FTDM_TOKEN_STRLEN 128
+#define FTDM_MAX_TOKENS 10
+
+static __inline__ char *ftdm_clean_string(char *s)
+{
+ char *p;
+
+ for (p = s; p && *p; p++) {
+ uint8_t x = (uint8_t) *p;
+ if (x < 32 || x > 127) {
+ *p = ' ';
+ }
+ }
+
+ return s;
+}
+
+struct ftdm_bitstream {
+ uint8_t *data;
+ uint32_t datalen;
+ uint32_t byte_index;
+ uint8_t bit_index;
+ int8_t endian;
+ uint8_t top;
+ uint8_t bot;
+ uint8_t ss;
+ uint8_t ssv;
+};
+
+struct ftdm_fsk_data_state {
+ dsp_fsk_handle_t *fsk1200_handle;
+ uint8_t init;
+ uint8_t *buf;
+ size_t bufsize;
+ ftdm_size_t blen;
+ ftdm_size_t bpos;
+ ftdm_size_t dlen;
+ ftdm_size_t ppos;
+ int checksum;
+};
+
+struct ftdm_fsk_modulator {
+ teletone_dds_state_t dds;
+ ftdm_bitstream_t bs;
+ uint32_t carrier_bits_start;
+ uint32_t carrier_bits_stop;
+ uint32_t chan_sieze_bits;
+ uint32_t bit_factor;
+ uint32_t bit_accum;
+ uint32_t sample_counter;
+ int32_t samples_per_bit;
+ int32_t est_bytes;
+ fsk_modem_types_t modem_type;
+ ftdm_fsk_data_state_t *fsk_data;
+ ftdm_fsk_write_sample_t write_sample_callback;
+ void *user_data;
+ int16_t sample_buffer[64];
+};
+
+/**
+ * Type Of Number (TON)
+ */
+typedef enum {
+ FTDM_TON_UNKNOWN = 0,
+ FTDM_TON_INTERNATIONAL,
+ FTDM_TON_NATIONAL,
+ FTDM_TON_NETWORK_SPECIFIC,
+ FTDM_TON_SUBSCRIBER_NUMBER,
+ FTDM_TON_ABBREVIATED_NUMBER,
+ FTDM_TON_RESERVED,
+ FTDM_TON_INVALID = 255
+} ftdm_ton_t;
+
+/**
+ * Numbering Plan Identification (NPI)
+ */
+typedef enum {
+ FTDM_NPI_UNKNOWN = 0,
+ FTDM_NPI_ISDN = 1,
+ FTDM_NPI_DATA = 3,
+ FTDM_NPI_TELEX = 4,
+ FTDM_NPI_NATIONAL = 8,
+ FTDM_NPI_PRIVATE = 9,
+ FTDM_NPI_RESERVED = 10,
+ FTDM_NPI_INVALID = 255
+} ftdm_npi_t;
+
+typedef struct {
+ char digits[25];
+ uint8_t type;
+ uint8_t plan;
+} ftdm_number_t;
+
+typedef enum {
+ FTDM_CALLER_STATE_DIALING,
+ FTDM_CALLER_STATE_SUCCESS,
+ FTDM_CALLER_STATE_FAIL
+} ftdm_caller_state_t;
+
+struct ftdm_caller_data {
+ char cid_date[8];
+ char cid_name[80];
+ ftdm_number_t cid_num;
+ ftdm_number_t ani;
+ ftdm_number_t dnis;
+ ftdm_number_t rdnis;
+ char aniII[25];
+ uint8_t screen;
+ uint8_t pres;
+ char collected[25];
+ int CRV;
+ int hangup_cause;
+ uint8_t raw_data[1024];
+ uint32_t raw_data_len;
+ uint32_t flags;
+ ftdm_caller_state_t call_state;
+ uint32_t chan_id;
+};
+
+typedef enum {
+ FTDM_TYPE_NONE,
+ FTDM_TYPE_SPAN = 0xFF,
+ FTDM_TYPE_CHANNEL
+} ftdm_data_type_t;
+
+/* 2^8 table size, one for each byte value */
+#define FTDM_GAINS_TABLE_SIZE 256
+struct ftdm_channel {
+ ftdm_data_type_t data_type;
+ uint32_t span_id;
+ uint32_t chan_id;
+ uint32_t physical_span_id;
+ uint32_t physical_chan_id;
+ uint32_t rate;
+ uint32_t extra_id;
+ ftdm_chan_type_t type;
+ ftdm_socket_t sockfd;
+ uint32_t flags;
+ uint32_t pflags;
+ uint32_t sflags;
+ ftdm_alarm_flag_t alarm_flags;
+ ftdm_channel_feature_t features;
+ ftdm_codec_t effective_codec;
+ ftdm_codec_t native_codec;
+ uint32_t effective_interval;
+ uint32_t native_interval;
+ uint32_t packet_len;
+ ftdm_channel_state_t state;
+ ftdm_channel_state_t last_state;
+ ftdm_channel_state_t init_state;
+ ftdm_mutex_t *mutex;
+ teletone_dtmf_detect_state_t dtmf_detect;
+ uint32_t buffer_delay;
+ ftdm_event_t event_header;
+ char last_error[256];
+ fio_event_cb_t event_callback;
+ uint32_t skip_read_frames;
+ ftdm_buffer_t *dtmf_buffer;
+ ftdm_buffer_t *gen_dtmf_buffer;
+ ftdm_buffer_t *pre_buffer;
+ ftdm_buffer_t *digit_buffer;
+ ftdm_buffer_t *fsk_buffer;
+ ftdm_mutex_t *pre_buffer_mutex;
+ uint32_t dtmf_on;
+ uint32_t dtmf_off;
+ char *dtmf_hangup_buf;
+ teletone_generation_session_t tone_session;
+ ftdm_time_t last_event_time;
+ ftdm_time_t ring_time;
+ char tokens[FTDM_MAX_TOKENS+1][FTDM_TOKEN_STRLEN];
+ uint8_t needed_tones[FTDM_TONEMAP_INVALID];
+ uint8_t detected_tones[FTDM_TONEMAP_INVALID];
+ ftdm_tonemap_t last_detected_tone;
+ uint32_t token_count;
+ char chan_name[128];
+ char chan_number[32];
+ ftdm_filehandle_t fds[2];
+ ftdm_fsk_data_state_t fsk;
+ uint8_t fsk_buf[80];
+ uint32_t ring_count;
+ void *mod_data;
+ void *call_data;
+ struct ftdm_caller_data caller_data;
+ struct ftdm_span *span;
+ struct ftdm_io_interface *fio;
+ ftdm_hash_t *variable_hash;
+ unsigned char rx_cas_bits;
+ uint32_t pre_buffer_size;
+ unsigned char rxgain_table[FTDM_GAINS_TABLE_SIZE];
+ unsigned char txgain_table[FTDM_GAINS_TABLE_SIZE];
+ float rxgain;
+ float txgain;
+};
+
+
+struct ftdm_sigmsg {
+ ftdm_signal_event_t event_id;
+ uint32_t chan_id;
+ uint32_t span_id;
+ ftdm_channel_t *channel;
+ void *raw_data;
+ uint32_t raw_data_len;
+};
+
+
+struct ftdm_span {
+ ftdm_data_type_t data_type;
+ char *name;
+ uint32_t span_id;
+ uint32_t chan_count;
+ ftdm_span_flag_t flags;
+ struct ftdm_io_interface *fio;
+ fio_event_cb_t event_callback;
+ ftdm_mutex_t *mutex;
+ ftdm_trunk_type_t trunk_type;
+ ftdm_analog_start_type_t start_type;
+ ftdm_signal_type_t signal_type;
+ void *signal_data;
+ fio_signal_cb_t signal_cb;
+ ftdm_event_t event_header;
+ char last_error[256];
+ char tone_map[FTDM_TONEMAP_INVALID+1][FTDM_TONEMAP_LEN];
+ teletone_tone_map_t tone_detect_map[FTDM_TONEMAP_INVALID+1];
+ teletone_multi_tone_t tone_finder[FTDM_TONEMAP_INVALID+1];
+ ftdm_channel_t *channels[FTDM_MAX_CHANNELS_SPAN+1];
+ fio_channel_outgoing_call_t outgoing_call;
+ fio_channel_set_sig_status_t set_channel_sig_status;
+ fio_channel_get_sig_status_t get_channel_sig_status;
+ fio_span_set_sig_status_t set_span_sig_status;
+ fio_span_get_sig_status_t get_span_sig_status;
+ fio_channel_request_t channel_request;
+ ftdm_span_start_t start;
+ ftdm_span_stop_t stop;
+ void *mod_data;
+ char *type;
+ char *dtmf_hangup;
+ size_t dtmf_hangup_len;
+ int suggest_chan_id;
+ ftdm_state_map_t *state_map;
+ ftdm_caller_data_t default_caller_data;
+ ftdm_queue_t *pendingchans;
+ struct ftdm_span *next;
+};
+
+struct ftdm_group {
+ char *name;
+ uint32_t group_id;
+ uint32_t chan_count;
+ ftdm_channel_t *channels[FTDM_MAX_CHANNELS_GROUP];
+ uint32_t last_used_index;
+ ftdm_mutex_t *mutex;
+ struct ftdm_group *next;
+};
+
+FT_DECLARE_DATA extern ftdm_logger_t ftdm_log;
+
+typedef enum {
+ FTDM_CRASH_NEVER = 0,
+ FTDM_CRASH_ON_ASSERT
+} ftdm_crash_policy_t;
+
+FT_DECLARE_DATA extern ftdm_crash_policy_t g_ftdm_crash_policy;
+
+typedef void *(*ftdm_malloc_func_t)(void *pool, ftdm_size_t len);
+typedef void *(*ftdm_calloc_func_t)(void *pool, ftdm_size_t elements, ftdm_size_t len);
+typedef void (*ftdm_free_func_t)(void *pool, void *ptr);
+typedef struct ftdm_memory_handler {
+ void *pool;
+ ftdm_malloc_func_t malloc;
+ ftdm_calloc_func_t calloc;
+ ftdm_free_func_t free;
+} ftdm_memory_handler_t;
+
+FT_DECLARE_DATA extern ftdm_memory_handler_t g_ftdm_mem_handler;
+
+struct ftdm_io_interface {
+ const char *name;
+ fio_configure_span_t configure_span;
+ fio_configure_t configure;
+ fio_open_t open;
+ fio_close_t close;
+ fio_channel_destroy_t channel_destroy;
+ fio_span_destroy_t span_destroy;
+ fio_get_alarms_t get_alarms;
+ fio_command_t command;
+ fio_wait_t wait;
+ fio_read_t read;
+ fio_write_t write;
+ fio_span_poll_event_t poll_event;
+ fio_span_next_event_t next_event;
+ fio_api_t api;
+};
+
+/*! \brief Override the default queue handler */
+FT_DECLARE(ftdm_status_t) ftdm_global_set_queue_handler(ftdm_queue_handler_t *handler);
+
+/*! \brief Duplicate string */
+FT_DECLARE(char *) ftdm_strdup(const char *str);
+FT_DECLARE(char *) ftdm_strndup(const char *str, ftdm_size_t inlen);
+
+FT_DECLARE(ftdm_size_t) ftdm_fsk_modulator_generate_bit(ftdm_fsk_modulator_t *fsk_trans, int8_t bit, int16_t *buf, ftdm_size_t buflen);
+FT_DECLARE(int32_t) ftdm_fsk_modulator_generate_carrier_bits(ftdm_fsk_modulator_t *fsk_trans, uint32_t bits);
+FT_DECLARE(void) ftdm_fsk_modulator_generate_chan_sieze(ftdm_fsk_modulator_t *fsk_trans);
+FT_DECLARE(void) ftdm_fsk_modulator_send_data(ftdm_fsk_modulator_t *fsk_trans);
+#define ftdm_fsk_modulator_send_all(_it) ftdm_fsk_modulator_generate_chan_sieze(_it); \
+ ftdm_fsk_modulator_generate_carrier_bits(_it, _it->carrier_bits_start); \
+ ftdm_fsk_modulator_send_data(_it); \
+ ftdm_fsk_modulator_generate_carrier_bits(_it, _it->carrier_bits_stop)
+
+FT_DECLARE(ftdm_status_t) ftdm_fsk_modulator_init(ftdm_fsk_modulator_t *fsk_trans,
+ fsk_modem_types_t modem_type,
+ uint32_t sample_rate,
+ ftdm_fsk_data_state_t *fsk_data,
+ float db_level,
+ uint32_t carrier_bits_start,
+ uint32_t carrier_bits_stop,
+ uint32_t chan_sieze_bits,
+ ftdm_fsk_write_sample_t write_sample_callback,
+ void *user_data);
+FT_DECLARE(int8_t) ftdm_bitstream_get_bit(ftdm_bitstream_t *bsp);
+FT_DECLARE(void) ftdm_bitstream_init(ftdm_bitstream_t *bsp, uint8_t *data, uint32_t datalen, ftdm_endian_t endian, uint8_t ss);
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_parse(ftdm_fsk_data_state_t *state, ftdm_size_t *type, char **data, ftdm_size_t *len);
+FT_DECLARE(ftdm_status_t) ftdm_fsk_demod_feed(ftdm_fsk_data_state_t *state, int16_t *data, size_t samples);
+FT_DECLARE(ftdm_status_t) ftdm_fsk_demod_destroy(ftdm_fsk_data_state_t *state);
+FT_DECLARE(int) ftdm_fsk_demod_init(ftdm_fsk_data_state_t *state, int rate, uint8_t *buf, size_t bufsize);
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_init(ftdm_fsk_data_state_t *state, uint8_t *data, uint32_t datalen);
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_mdmf(ftdm_fsk_data_state_t *state, ftdm_mdmf_type_t type, const uint8_t *data, uint32_t datalen);
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_checksum(ftdm_fsk_data_state_t *state);
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_sdmf(ftdm_fsk_data_state_t *state, const char *date, char *number);
+FT_DECLARE(ftdm_status_t) ftdm_channel_outgoing_call(ftdm_channel_t *ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_set_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status);
+FT_DECLARE(ftdm_status_t) ftdm_channel_get_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t *status);
+FT_DECLARE(ftdm_status_t) ftdm_span_set_sig_status(ftdm_span_t *span, ftdm_signaling_status_t status);
+FT_DECLARE(ftdm_status_t) ftdm_span_get_sig_status(ftdm_span_t *span, ftdm_signaling_status_t *status);
+FT_DECLARE(void) ftdm_channel_rotate_tokens(ftdm_channel_t *ftdmchan);
+FT_DECLARE(void) ftdm_channel_clear_detected_tones(ftdm_channel_t *ftdmchan);
+FT_DECLARE(void) ftdm_channel_clear_needed_tones(ftdm_channel_t *ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_get_alarms(ftdm_channel_t *ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_send_fsk_data(ftdm_channel_t *ftdmchan, ftdm_fsk_data_state_t *fsk_data, float db_level);
+FT_DECLARE(ftdm_status_t) ftdm_channel_clear_token(ftdm_channel_t *ftdmchan, const char *token);
+FT_DECLARE(void) ftdm_channel_replace_token(ftdm_channel_t *ftdmchan, const char *old_token, const char *new_token);
+FT_DECLARE(ftdm_status_t) ftdm_channel_add_token(ftdm_channel_t *ftdmchan, char *token, int end);
+FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int lock);
+FT_DECLARE(ftdm_status_t) ftdm_span_load_tones(ftdm_span_t *span, const char *mapname);
+FT_DECLARE(ftdm_size_t) ftdm_channel_dequeue_dtmf(ftdm_channel_t *ftdmchan, char *dtmf, ftdm_size_t len);
+FT_DECLARE(ftdm_status_t) ftdm_channel_queue_dtmf(ftdm_channel_t *ftdmchan, const char *dtmf);
+FT_DECLARE(void) ftdm_channel_flush_dtmf(ftdm_channel_t *ftdmchan);
+FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void);
+FT_DECLARE(ftdm_status_t) ftdm_span_poll_event(ftdm_span_t *span, uint32_t ms);
+FT_DECLARE(ftdm_status_t) ftdm_span_next_event(ftdm_span_t *span, ftdm_event_t **event);
+FT_DECLARE(ftdm_status_t) ftdm_span_find(uint32_t id, ftdm_span_t **span);
+FT_DECLARE(ftdm_status_t) ftdm_span_create(ftdm_io_interface_t *fio, ftdm_span_t **span, const char *name);
+FT_DECLARE(ftdm_status_t) ftdm_span_close_all(void);
+FT_DECLARE(ftdm_status_t) ftdm_span_add_channel(ftdm_span_t *span, ftdm_socket_t sockfd, ftdm_chan_type_t type, ftdm_channel_t **chan);
+FT_DECLARE(ftdm_status_t) ftdm_span_set_event_callback(ftdm_span_t *span, fio_event_cb_t event_callback);
+FT_DECLARE(ftdm_status_t) ftdm_channel_add_to_group(const char* name, ftdm_channel_t* ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_remove_from_group(ftdm_group_t* group, ftdm_channel_t* ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_group_find(uint32_t id, ftdm_group_t **group);
+FT_DECLARE(ftdm_status_t) ftdm_group_find_by_name(const char *name, ftdm_group_t **group);
+FT_DECLARE(ftdm_status_t) ftdm_group_create(ftdm_group_t **group, const char *name);
+FT_DECLARE(ftdm_status_t) ftdm_channel_set_event_callback(ftdm_channel_t *ftdmchan, fio_event_cb_t event_callback);
+FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_span_channel_use_count(ftdm_span_t *span, uint32_t *count);
+FT_DECLARE(ftdm_status_t) ftdm_group_channel_use_count(ftdm_group_t *group, uint32_t *count);
+FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_close(ftdm_channel_t **ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_use(ftdm_channel_t *ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_command_t command, void *obj);
+FT_DECLARE(ftdm_status_t) ftdm_channel_wait(ftdm_channel_t *ftdmchan, ftdm_wait_flag_t *flags, int32_t to);
+FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t *datalen);
+FT_DECLARE(void) ftdm_generate_sln_silence(int16_t *data, uint32_t samples, uint32_t divisor);
+FT_DECLARE(ftdm_status_t) ftdm_channel_write(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t datasize, ftdm_size_t *datalen);
+FT_DECLARE(ftdm_status_t) ftdm_channel_add_var(ftdm_channel_t *ftdmchan, const char *var_name, const char *value);
+FT_DECLARE(const char *) ftdm_channel_get_var(ftdm_channel_t *ftdmchan, const char *var_name);
+FT_DECLARE(ftdm_status_t) ftdm_channel_clear_vars(ftdm_channel_t *ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_global_init(void);
+FT_DECLARE(ftdm_status_t) ftdm_global_configuration(void);
+FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void);
+FT_DECLARE(ftdm_status_t) ftdm_global_set_memory_handler(ftdm_memory_handler_t *handler);
+FT_DECLARE(void) ftdm_global_set_crash_policy(ftdm_crash_policy_t policy);
+FT_DECLARE(void) ftdm_global_set_logger(ftdm_logger_t logger);
+FT_DECLARE(void) ftdm_global_set_default_logger(int level);
+FT_DECLARE(uint32_t) ftdm_separate_string(char *buf, char delim, char **array, int arraylen);
+FT_DECLARE(void) print_bits(uint8_t *b, int bl, char *buf, int blen, int e, uint8_t ss);
+FT_DECLARE(void) print_hex_bytes(uint8_t *data, ftdm_size_t dlen, char *buf, ftdm_size_t blen);
+FT_DECLARE_NONSTD(int) ftdm_hash_equalkeys(void *k1, void *k2);
+FT_DECLARE_NONSTD(uint32_t) ftdm_hash_hashfromstring(void *ky);
+FT_DECLARE(uint32_t) ftdm_running(void);
+FT_DECLARE(ftdm_status_t) ftdm_channel_complete_state(ftdm_channel_t *ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_init(ftdm_channel_t *ftdmchan);
+FT_DECLARE(int) ftdm_load_modules(void);
+FT_DECLARE(ftdm_status_t) ftdm_unload_modules(void);
+FT_DECLARE(ftdm_status_t) ftdm_configure_span(const char *type, ftdm_span_t *span, fio_signal_cb_t sig_cb, ...);
+FT_DECLARE(ftdm_status_t) ftdm_configure_span_signaling(const char *type, ftdm_span_t *span, fio_signal_cb_t sig_cb, ftdm_conf_parameter_t *parameters);
+FT_DECLARE(ftdm_status_t) ftdm_span_start(ftdm_span_t *span);
+FT_DECLARE(ftdm_status_t) ftdm_span_stop(ftdm_span_t *span);
+FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t *sigmsg);
+FT_DECLARE(char *) ftdm_build_dso_path(const char *name, char *path, ftdm_size_t len);
+FT_DECLARE(ftdm_status_t) ftdm_global_add_io_interface(ftdm_io_interface_t *io_interface);
+FT_DECLARE(int) ftdm_load_module(const char *name);
+FT_DECLARE(int) ftdm_load_module_assume(const char *name);
+FT_DECLARE(ftdm_status_t) ftdm_span_find_by_name(const char *name, ftdm_span_t **span);
+FT_DECLARE(char *) ftdm_api_execute(const char *type, const char *cmd);
+FT_DECLARE(int) ftdm_vasprintf(char **ret, const char *fmt, va_list ap);
+FT_DECLARE(ftdm_status_t) ftdm_channel_set_caller_data(ftdm_channel_t *ftdmchan, ftdm_caller_data_t *caller_data);
+
+FIO_CODEC_FUNCTION(fio_slin2ulaw);
+FIO_CODEC_FUNCTION(fio_ulaw2slin);
+FIO_CODEC_FUNCTION(fio_slin2alaw);
+FIO_CODEC_FUNCTION(fio_alaw2slin);
+FIO_CODEC_FUNCTION(fio_ulaw2alaw);
+FIO_CODEC_FUNCTION(fio_alaw2ulaw);
+
+#ifdef DEBUG_LOCKS
+#define ftdm_mutex_lock(_x) printf("++++++lock %s:%d\n", __FILE__, __LINE__) && _ftdm_mutex_lock(_x)
+#define ftdm_mutex_trylock(_x) printf("++++++try %s:%d\n", __FILE__, __LINE__) && _ftdm_mutex_trylock(_x)
+#define ftdm_mutex_unlock(_x) printf("------unlock %s:%d\n", __FILE__, __LINE__) && _ftdm_mutex_unlock(_x)
+#else
+#define ftdm_mutex_lock(_x) _ftdm_mutex_lock(_x)
+#define ftdm_mutex_trylock(_x) _ftdm_mutex_trylock(_x)
+#define ftdm_mutex_unlock(_x) _ftdm_mutex_unlock(_x)
+#endif
+
+/*!
+ \brief Assert condition
+*/
+#define ftdm_assert(assertion, msg) \
+ if (!(assertion)) { \
+ ftdm_log(FTDM_LOG_CRIT, msg); \
+ if (g_ftdm_crash_policy & FTDM_CRASH_ON_ASSERT) { \
+ ftdm_abort(); \
+ } \
+ }
+
+/*!
+ \brief Assert condition and return
+*/
+#define ftdm_assert_return(assertion, retval, msg) \
+ if (!(assertion)) { \
+ ftdm_log(FTDM_LOG_CRIT, msg); \
+ if (g_ftdm_crash_policy & FTDM_CRASH_ON_ASSERT) { \
+ ftdm_abort(); \
+ } else { \
+ return retval; \
+ } \
+ }
+
+/*!
+ \brief Allocate uninitialized memory
+ \command chunksize the chunk size
+*/
+#define ftdm_malloc(chunksize) g_ftdm_mem_handler.malloc(g_ftdm_mem_handler.pool, chunksize)
+
+/*!
+ \brief Allocate initialized memory
+ \command chunksize the chunk size
+*/
+#define ftdm_calloc(elements, chunksize) g_ftdm_mem_handler.calloc(g_ftdm_mem_handler.pool, elements, chunksize)
+
+/*!
+ \brief Free chunk of memory
+ \command chunksize the chunk size
+*/
+#define ftdm_free(chunk) g_ftdm_mem_handler.free(g_ftdm_mem_handler.pool, chunk)
+
+/*!
+ \brief Free a pointer and set it to NULL unless it already is NULL
+ \command it the pointer
+*/
+#define ftdm_safe_free(it) if (it) { ftdm_free(it); it = NULL; }
+
+/*!
+ \brief Socket the given socket
+ \command it the socket
+*/
+#define ftdm_socket_close(it) if (it > -1) { close(it); it = -1;}
+
+#define ftdm_array_len(array) sizeof(array)/sizeof(array[0])
+
+static __inline__ void ftdm_abort(void)
+{
+#ifdef __cplusplus
+ ::abort();
+#else
+ abort();
+#endif
+}
+
+static __inline__ void ftdm_set_state_all(ftdm_span_t *span, ftdm_channel_state_t state)
+{
+ uint32_t j;
+ ftdm_mutex_lock(span->mutex);
+ for(j = 1; j <= span->chan_count; j++) {
+ ftdm_set_state_locked((span->channels[j]), state);
+ }
+ ftdm_mutex_unlock(span->mutex);
+}
+
+static __inline__ int ftdm_check_state_all(ftdm_span_t *span, ftdm_channel_state_t state)
+{
+ uint32_t j;
+ for(j = 1; j <= span->chan_count; j++) {
+ if (span->channels[j]->state != state || ftdm_test_flag(span->channels[j], FTDM_CHANNEL_STATE_CHANGE)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static __inline__ void ftdm_set_flag_all(ftdm_span_t *span, uint32_t flag)
+{
+ uint32_t j;
+ ftdm_mutex_lock(span->mutex);
+ for(j = 1; j <= span->chan_count; j++) {
+ ftdm_set_flag_locked((span->channels[j]), flag);
+ }
+ ftdm_mutex_unlock(span->mutex);
+}
+
+static __inline__ void ftdm_clear_flag_all(ftdm_span_t *span, uint32_t flag)
+{
+ uint32_t j;
+ ftdm_mutex_lock(span->mutex);
+ for(j = 1; j <= span->chan_count; j++) {
+ ftdm_clear_flag_locked((span->channels[j]), flag);
+ }
+ ftdm_mutex_unlock(span->mutex);
+}
+
+#ifdef __cplusplus
+} /* extern C */
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/include/fsk.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/include/fsk.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/fsk.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,121 @@
+/*
+ * bell202.h
+ *
+ * Copyright (c) 2005 Robert Krten. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * This module contains the manifest constants and declarations for
+ * the Bell-202 1200 baud FSK modem.
+ *
+ * 2005 03 20 R. Krten created
+*/
+
+#ifndef __FSK_H__
+#define __FSK_H__
+#include "uart.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ int freq_space; /* Frequency of the 0 bit */
+ int freq_mark; /* Frequency of the 1 bit */
+ int baud_rate; /* baud rate for the modem */
+} fsk_modem_definition_t;
+
+/* Must be kept in sync with fsk_modem_definitions array in fsk.c */
+/* V.23 definitions: http://www.itu.int/rec/recommendation.asp?type=folders&lang=e&parent=T-REC-V.23 */
+typedef enum {
+ FSK_V23_FORWARD_MODE1 = 0, /* Maximum 600 bps for long haul */
+ FSK_V23_FORWARD_MODE2, /* Standard 1200 bps V.23 */
+ FSK_V23_BACKWARD, /* 75 bps return path for V.23 */
+ FSK_BELL202 /* Bell 202 half-duplex 1200 bps */
+} fsk_modem_types_t;
+
+typedef enum {
+ FSK_STATE_CHANSEIZE = 0,
+ FSK_STATE_CARRIERSIG,
+ FSK_STATE_DATA
+} fsk_state_t;
+
+typedef struct dsp_fsk_attr_s
+{
+ int sample_rate; /* sample rate in HZ */
+ bithandler_func_t bithandler; /* bit handler */
+ void *bithandler_arg; /* arbitrary ID passed to bithandler as first argument */
+ bytehandler_func_t bytehandler; /* byte handler */
+ void *bytehandler_arg; /* arbitrary ID passed to bytehandler as first argument */
+} dsp_fsk_attr_t;
+
+typedef struct
+{
+ fsk_state_t state;
+ dsp_fsk_attr_t attr; /* attributes structure */
+ double *correlates[4]; /* one for each of sin/cos for mark/space */
+ int corrsize; /* correlate size (also number of samples in ring buffer) */
+ double *buffer; /* sample ring buffer */
+ int ringstart; /* ring buffer start offset */
+ double cellpos; /* bit cell position */
+ double celladj; /* bit cell adjustment for each sample */
+ int previous_bit; /* previous bit (for detecting a transition to sync-up cell position) */
+ int current_bit; /* current bit */
+ int last_bit;
+ int downsampling_count; /* number of samples to skip */
+ int current_downsample; /* current skip count */
+ int conscutive_state_bits; /* number of bits in a row that matches the pattern for the current state */
+} dsp_fsk_handle_t;
+
+/*
+ * Function prototypes
+ *
+ * General calling order is:
+ * a) create the attributes structure (dsp_fsk_attr_init)
+ * b) initialize fields in the attributes structure (dsp_fsk_attr_set_*)
+ * c) create a Bell-202 handle (dsp_fsk_create)
+ * d) feed samples through the handler (dsp_fsk_sample)
+*/
+
+void dsp_fsk_attr_init(dsp_fsk_attr_t *attributes);
+
+bithandler_func_t dsp_fsk_attr_get_bithandler(dsp_fsk_attr_t *attributes, void **bithandler_arg);
+void dsp_fsk_attr_set_bithandler(dsp_fsk_attr_t *attributes, bithandler_func_t bithandler, void *bithandler_arg);
+bytehandler_func_t dsp_fsk_attr_get_bytehandler(dsp_fsk_attr_t *attributes, void **bytehandler_arg);
+void dsp_fsk_attr_set_bytehandler(dsp_fsk_attr_t *attributes, bytehandler_func_t bytehandler, void *bytehandler_arg);
+int dsp_fsk_attr_get_samplerate(dsp_fsk_attr_t *attributes);
+int dsp_fsk_attr_set_samplerate(dsp_fsk_attr_t *attributes, int samplerate);
+
+dsp_fsk_handle_t * dsp_fsk_create(dsp_fsk_attr_t *attributes);
+void dsp_fsk_destroy(dsp_fsk_handle_t **handle);
+
+void dsp_fsk_sample(dsp_fsk_handle_t *handle, double normalized_sample);
+
+extern fsk_modem_definition_t fsk_modem_definitions[];
+
+#ifdef __cplusplus
+} /* extern C */
+#endif
+
+#endif
+
Added: freeswitch/trunk/libs/freetdm/src/include/ftdm_buffer.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/include/ftdm_buffer.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/ftdm_buffer.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#ifndef FTDM_BUFFER_H
+#define FTDM_BUFFER_H
+
+#include "freetdm.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup ftdm_buffer Buffer Routines
+ * @ingroup buffer
+ * The purpose of this module is to make a plain buffering interface that can be used for read/write buffers
+ * throughout the application.
+ * @{
+ */
+struct ftdm_buffer;
+typedef struct ftdm_buffer ftdm_buffer_t;
+
+/*! \brief Allocate a new dynamic ftdm_buffer
+ * \param buffer returned pointer to the new buffer
+ * \param blocksize length to realloc by as data is added
+ * \param start_len ammount of memory to reserve initially
+ * \param max_len length the buffer is allowed to grow to
+ * \return status
+ */
+FT_DECLARE(ftdm_status_t) ftdm_buffer_create(ftdm_buffer_t **buffer, ftdm_size_t blocksize, ftdm_size_t start_len, ftdm_size_t max_len);
+
+/*! \brief Get the length of a ftdm_buffer_t
+ * \param buffer any buffer of type ftdm_buffer_t
+ * \return int size of the buffer.
+ */
+FT_DECLARE(ftdm_size_t) ftdm_buffer_len(ftdm_buffer_t *buffer);
+
+/*! \brief Get the freespace of a ftdm_buffer_t
+ * \param buffer any buffer of type ftdm_buffer_t
+ * \return int freespace in the buffer.
+ */
+FT_DECLARE(ftdm_size_t) ftdm_buffer_freespace(ftdm_buffer_t *buffer);
+
+/*! \brief Get the in use amount of a ftdm_buffer_t
+ * \param buffer any buffer of type ftdm_buffer_t
+ * \return int ammount of buffer curently in use
+ */
+FT_DECLARE(ftdm_size_t) ftdm_buffer_inuse(ftdm_buffer_t *buffer);
+
+/*! \brief Read data from a ftdm_buffer_t up to the ammount of datalen if it is available. Remove read data from buffer.
+ * \param buffer any buffer of type ftdm_buffer_t
+ * \param data pointer to the read data to be returned
+ * \param datalen amount of data to be returned
+ * \return int ammount of data actually read
+ */
+FT_DECLARE(ftdm_size_t) ftdm_buffer_read(ftdm_buffer_t *buffer, void *data, ftdm_size_t datalen);
+
+/*! \brief Read data endlessly from a ftdm_buffer_t
+ * \param buffer any buffer of type ftdm_buffer_t
+ * \param data pointer to the read data to be returned
+ * \param datalen amount of data to be returned
+ * \return int ammount of data actually read
+ * \note Once you have read all the data from the buffer it will loop around.
+ */
+FT_DECLARE(ftdm_size_t) ftdm_buffer_read_loop(ftdm_buffer_t *buffer, void *data, ftdm_size_t datalen);
+
+/*! \brief Assign a number of loops to read
+ * \param buffer any buffer of type ftdm_buffer_t
+ * \param loops the number of loops (-1 for infinite)
+ */
+FT_DECLARE(void) ftdm_buffer_set_loops(ftdm_buffer_t *buffer, int32_t loops);
+
+/*! \brief Write data into a ftdm_buffer_t up to the length of datalen
+ * \param buffer any buffer of type ftdm_buffer_t
+ * \param data pointer to the data to be written
+ * \param datalen amount of data to be written
+ * \return int amount of buffer used after the write, or 0 if no space available
+ */
+FT_DECLARE(ftdm_size_t) ftdm_buffer_write(ftdm_buffer_t *buffer, const void *data, ftdm_size_t datalen);
+
+/*! \brief Remove data from the buffer
+ * \param buffer any buffer of type ftdm_buffer_t
+ * \param datalen amount of data to be removed
+ * \return int size of buffer, or 0 if unable to toss that much data
+ */
+FT_DECLARE(ftdm_size_t) ftdm_buffer_toss(ftdm_buffer_t *buffer, ftdm_size_t datalen);
+
+/*! \brief Remove all data from the buffer
+ * \param buffer any buffer of type ftdm_buffer_t
+ */
+FT_DECLARE(void) ftdm_buffer_zero(ftdm_buffer_t *buffer);
+
+/*! \brief Destroy the buffer
+ * \param buffer buffer to destroy
+ * \note only neccessary on dynamic buffers (noop on pooled ones)
+ */
+FT_DECLARE(void) ftdm_buffer_destroy(ftdm_buffer_t **buffer);
+
+/*! \brief Seek to offset from the beginning of the buffer
+ * \param buffer buffer to seek
+ * \param datalen offset in bytes
+ * \return new position
+ */
+FT_DECLARE(ftdm_size_t) ftdm_buffer_seek(ftdm_buffer_t *buffer, ftdm_size_t datalen);
+
+/** @} */
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_zwrite(ftdm_buffer_t *buffer, const void *data, ftdm_size_t datalen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/include/ftdm_config.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/include/ftdm_config.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/ftdm_config.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+/**
+ * @defgroup config Config File Parser
+ * @ingroup config
+ * This module implements a basic interface and file format parser
+ *
+ * <pre>
+ *
+ * EXAMPLE
+ *
+ * [category1]
+ * var1 => val1
+ * var2 => val2
+ * \# lines that begin with \# are comments
+ * \#var3 => val3
+ * </pre>
+ * @{
+ */
+
+#ifndef FTDM_CONFIG_H
+#define FTDM_CONFIG_H
+
+#include "freetdm.h"
+#define FTDM_URL_SEPARATOR "://"
+
+
+#ifdef WIN32
+#define FTDM_PATH_SEPARATOR "\\"
+#ifndef FTDM_CONFIG_DIR
+#define FTDM_CONFIG_DIR "c:\\freetdm"
+#endif
+#define ftdm_is_file_path(file) (*(file +1) == ':' || *file == '/' || strstr(file, SWITCH_URL_SEPARATOR))
+#else
+#define FTDM_PATH_SEPARATOR "/"
+#ifndef FTDM_CONFIG_DIR
+#define FTDM_CONFIG_DIR "/etc/freetdm"
+#endif
+#define ftdm_is_file_path(file) ((*file == '/') || strstr(file, SWITCH_URL_SEPARATOR))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ftdm_config ftdm_config_t;
+
+/*! \brief A simple file handle representing an open configuration file **/
+struct ftdm_config {
+ /*! FILE stream buffer to the opened file */
+ FILE *file;
+ /*! path to the file */
+ char path[512];
+ /*! current category */
+ char category[256];
+ /*! current section */
+ char section[256];
+ /*! buffer of current line being read */
+ char buf[1024];
+ /*! current line number in file */
+ int lineno;
+ /*! current category number in file */
+ int catno;
+ /*! current section number in file */
+ int sectno;
+
+ int lockto;
+};
+
+/*!
+ \brief Open a configuration file
+ \param cfg (ftdm_config_t *) config handle to use
+ \param file_path path to the file
+ \return 1 (true) on success 0 (false) on failure
+*/
+int ftdm_config_open_file(ftdm_config_t * cfg, const char *file_path);
+
+/*!
+ \brief Close a previously opened configuration file
+ \param cfg (ftdm_config_t *) config handle to use
+*/
+void ftdm_config_close_file(ftdm_config_t * cfg);
+
+/*!
+ \brief Retrieve next name/value pair from configuration file
+ \param cfg (ftdm_config_t *) config handle to use
+ \param var pointer to aim at the new variable name
+ \param val pointer to aim at the new value
+*/
+int ftdm_config_next_pair(ftdm_config_t * cfg, char **var, char **val);
+
+/*!
+ \brief Retrieve the CAS bits from a configuration string value
+ \param strvalue pointer to the configuration string value (expected to be in format whatever:xxxx)
+ \param outbits pointer to aim at the CAS bits
+*/
+FT_DECLARE (int) ftdm_config_get_cas_bits(char *strvalue, unsigned char *outbits);
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+#endif
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/include/ftdm_dso.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/include/ftdm_dso.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/ftdm_dso.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,51 @@
+/*
+ * Cross Platform dso/dll load abstraction
+ * Copyright(C) 2008 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer.
+ *
+ */
+
+
+#ifndef _FTDM_DSO_H
+#define _FTDM_DSO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*ftdm_func_ptr_t) (void);
+typedef void * ftdm_dso_lib_t;
+
+FT_DECLARE(void) ftdm_dso_destroy(ftdm_dso_lib_t *lib);
+FT_DECLARE(ftdm_dso_lib_t) ftdm_dso_open(const char *path, char **err);
+FT_DECLARE(void *) ftdm_dso_func_sym(ftdm_dso_lib_t lib, const char *sym, char **err);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4
+ */
+
Added: freeswitch/trunk/libs/freetdm/src/include/ftdm_m3ua.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/include/ftdm_m3ua.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/ftdm_m3ua.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,134 @@
+/*
+ * ftdm_m3ua.h
+ * freetdm
+ *
+ * Created by Shane Burrell on 4/3/08.
+ * Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ *
+ * 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.
+ */
+
+
+//#include "m3ua_client.h"
+#include "freetdm.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+enum e_sigboost_event_id_values
+{
+ SIGBOOST_EVENT_CALL_START = 0x80, /*128*/
+ SIGBOOST_EVENT_CALL_START_ACK = 0x81, /*129*/
+ SIGBOOST_EVENT_CALL_START_NACK = 0x82, /*130*/
+ SIGBOOST_EVENT_CALL_START_NACK_ACK = 0x83, /*131*/
+ SIGBOOST_EVENT_CALL_ANSWERED = 0x84, /*132*/
+ SIGBOOST_EVENT_CALL_STOPPED = 0x85, /*133*/
+ SIGBOOST_EVENT_CALL_STOPPED_ACK = 0x86, /*134*/
+ SIGBOOST_EVENT_SYSTEM_RESTART = 0x87, /*135*/
+ SIGBOOST_EVENT_SYSTEM_RESTART_ACK = 0x88, /*136*/
+ /* Following IDs are ss7boost to sangoma_mgd only. */
+ SIGBOOST_EVENT_HEARTBEAT = 0x89, /*137*/
+ SIGBOOST_EVENT_INSERT_CHECK_LOOP = 0x8a, /*138*/
+ SIGBOOST_EVENT_REMOVE_CHECK_LOOP = 0x8b, /*139*/
+ SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE = 0x8c, /*140*/
+};
+enum e_sigboost_release_cause_values
+{
+ SIGBOOST_RELEASE_CAUSE_UNDEFINED = 0,
+ SIGBOOST_RELEASE_CAUSE_NORMAL = 16,
+ SIGBOOST_RELEASE_CAUSE_BUSY = 17,
+ /* probable elimination */
+ //SIGBOOST_RELEASE_CAUSE_BUSY = 0x91, /* 145 */
+ //SIGBOOST_RELEASE_CAUSE_CALLED_NOT_EXIST = 0x92, /* 146 */
+ //SIGBOOST_RELEASE_CAUSE_CIRCUIT_RESET = 0x93, /* 147 */
+ //SIGBOOST_RELEASE_CAUSE_NOANSWER = 0x94, /* 148 */
+};
+
+enum e_sigboost_call_setup_ack_nack_cause_values
+{
+ SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY = 117, /* unused Q.850 value */
+ SIGBOOST_CALL_SETUP_NACK_TEST_CKT_BUSY = 118, /* unused Q.850 value */
+ SIGBOOST_CALL_SETUP_NACK_INVALID_NUMBER = 28,
+ /* probable elimination */
+ //SIGBOOST_CALL_SETUP_RESERVED = 0x00,
+ //SIGBOOST_CALL_SETUP_CIRCUIT_RESET = 0x10,
+ //SIGBOOST_CALL_SETUP_NACK_CKT_START_TIMEOUT = 0x11,
+ //SIGBOOST_CALL_SETUP_NACK_AUTO_CALL_GAP = 0x17,
+};
+typedef enum {
+ M3UA_SPAN_SIGNALING_M3UA,
+ M3UA_SPAN_SIGNALING_SS7BOX,
+
+} M3UA_TSpanSignaling;
+#define M3UA_SPAN_STRINGS "M3UA", "SS7BOX"
+FTDM_STR2ENUM_P(m3ua_str2span, m3ua_span2str, M3UA_TSpanSignaling)
+
+
+
+typedef enum {
+ FTDM_M3UA_RUNNING = (1 << 0)
+} ftdm_m3uat_flag_t;
+
+/*typedef struct m3ua_data {
+ m3uac_connection_t mcon;
+ m3uac_connection_t pcon;
+ fio_signal_cb_t signal_cb;
+ uint32_t flags;
+} m3ua_data_t;
+
+*/
+/*typedef struct mu3a_link {
+ ss7bc_connection_t mcon;
+ ss7bc_connection_t pcon;
+ fio_signal_cb_t signal_cb;
+ uint32_t flags;
+} ftdm_m3ua_data_t;
+*/
+
+ftdm_status_t m3ua_init(ftdm_io_interface_t **zint);
+ftdm_status_t m3ua_destroy(void);
+ftdm_status_t m3ua_start(ftdm_span_t *span);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/freetdm/src/include/ftdm_threadmutex.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/include/ftdm_threadmutex.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/ftdm_threadmutex.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,68 @@
+/*
+ * Cross Platform Thread/Mutex abstraction
+ * Copyright(C) 2007 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer.
+ *
+ * Contributors:
+ *
+ * Moises Silva <moy@sangoma.com>
+ *
+ */
+
+
+#ifndef _FTDM_THREADMUTEX_H
+#define _FTDM_THREADMUTEX_H
+
+#include "freetdm.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef struct ftdm_mutex ftdm_mutex_t;
+typedef struct ftdm_thread ftdm_thread_t;
+typedef struct ftdm_interrupt ftdm_interrupt_t;
+typedef void *(*ftdm_thread_function_t) (ftdm_thread_t *, void *);
+
+FT_DECLARE(ftdm_status_t) ftdm_thread_create_detached(ftdm_thread_function_t func, void *data);
+FT_DECLARE(ftdm_status_t) ftdm_thread_create_detached_ex(ftdm_thread_function_t func, void *data, ftdm_size_t stack_size);
+FT_DECLARE(void) ftdm_thread_override_default_stacksize(ftdm_size_t size);
+FT_DECLARE(ftdm_status_t) ftdm_mutex_create(ftdm_mutex_t **mutex);
+FT_DECLARE(ftdm_status_t) ftdm_mutex_destroy(ftdm_mutex_t **mutex);
+FT_DECLARE(ftdm_status_t) _ftdm_mutex_lock(ftdm_mutex_t *mutex);
+FT_DECLARE(ftdm_status_t) _ftdm_mutex_trylock(ftdm_mutex_t *mutex);
+FT_DECLARE(ftdm_status_t) _ftdm_mutex_unlock(ftdm_mutex_t *mutex);
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_create(ftdm_interrupt_t **cond, ftdm_socket_t device);
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_destroy(ftdm_interrupt_t **cond);
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_signal(ftdm_interrupt_t *cond);
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_wait(ftdm_interrupt_t *cond, int ms);
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_multiple_wait(ftdm_interrupt_t *interrupts[], ftdm_size_t size, int ms);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/freetdm/src/include/ftdm_types.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/include/ftdm_types.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/ftdm_types.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,708 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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:
+ *
+ * Moises Silva <moy@sangoma.com>
+ *
+ */
+
+#ifndef FTDM_TYPES_H
+#define FTDM_TYPES_H
+#include "fsk.h"
+
+#define FTDM_INVALID_SOCKET -1
+#ifdef WIN32
+#include <windows.h>
+typedef HANDLE ftdm_socket_t;
+typedef unsigned __int64 uint64_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int8 uint8_t;
+typedef __int64 int64_t;
+typedef __int32 int32_t;
+typedef __int16 int16_t;
+typedef __int8 int8_t;
+typedef intptr_t ftdm_ssize_t;
+typedef int ftdm_filehandle_t;
+#else
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <stdarg.h>
+typedef int ftdm_socket_t;
+typedef ssize_t ftdm_ssize_t;
+typedef int ftdm_filehandle_t;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define TAG_END NULL
+
+typedef size_t ftdm_size_t;
+struct ftdm_io_interface;
+
+#define FTDM_COMMAND_OBJ_INT *((int *)obj)
+#define FTDM_COMMAND_OBJ_CHAR_P (char *)obj
+#define FTDM_COMMAND_OBJ_FLOAT *(float *)obj
+#define FTDM_FSK_MOD_FACTOR 0x10000
+#define FTDM_DEFAULT_DTMF_ON 250
+#define FTDM_DEFAULT_DTMF_OFF 50
+
+#define FTDM_END -1
+#define FTDM_ANY_STATE -1
+
+typedef uint64_t ftdm_time_t;
+
+typedef enum {
+ FTDM_ENDIAN_BIG = 1,
+ FTDM_ENDIAN_LITTLE = -1
+} ftdm_endian_t;
+
+typedef enum {
+ FTDM_CID_TYPE_SDMF = 0x04,
+ FTDM_CID_TYPE_MDMF = 0x80
+} ftdm_cid_type_t;
+
+typedef enum {
+ MDMF_DATETIME = 1,
+ MDMF_PHONE_NUM = 2,
+ MDMF_DDN = 3,
+ MDMF_NO_NUM = 4,
+ MDMF_PHONE_NAME = 7,
+ MDMF_NO_NAME = 8,
+ MDMF_ALT_ROUTE = 9,
+ MDMF_INVALID = 10
+} ftdm_mdmf_type_t;
+#define MDMF_STRINGS "X", "DATETIME", "PHONE_NUM", "DDN", "NO_NUM", "X", "X", "PHONE_NAME", "NO_NAME", "ALT_ROUTE", "INVALID"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_mdmf_type, ftdm_mdmf_type2str, ftdm_mdmf_type_t)
+
+#define FTDM_TONEMAP_LEN 128
+typedef enum {
+ FTDM_TONEMAP_NONE,
+ FTDM_TONEMAP_DIAL,
+ FTDM_TONEMAP_RING,
+ FTDM_TONEMAP_BUSY,
+ FTDM_TONEMAP_FAIL1,
+ FTDM_TONEMAP_FAIL2,
+ FTDM_TONEMAP_FAIL3,
+ FTDM_TONEMAP_ATTN,
+ FTDM_TONEMAP_CALLWAITING_CAS,
+ FTDM_TONEMAP_CALLWAITING_SAS,
+ FTDM_TONEMAP_CALLWAITING_ACK,
+ FTDM_TONEMAP_INVALID
+} ftdm_tonemap_t;
+#define TONEMAP_STRINGS "NONE", "DIAL", "RING", "BUSY", "FAIL1", "FAIL2", "FAIL3", "ATTN", "CALLWAITING-CAS", "CALLWAITING-SAS", "CALLWAITING-ACK", "INVALID"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_tonemap, ftdm_tonemap2str, ftdm_tonemap_t)
+
+typedef enum {
+ FTDM_TRUNK_E1,
+ FTDM_TRUNK_T1,
+ FTDM_TRUNK_J1,
+ FTDM_TRUNK_BRI,
+ FTDM_TRUNK_BRI_PTMP,
+ FTDM_TRUNK_FXO,
+ FTDM_TRUNK_FXS,
+ FTDM_TRUNK_EM,
+ FTDM_TRUNK_NONE
+} ftdm_trunk_type_t;
+#define TRUNK_STRINGS "E1", "T1", "J1", "BRI", "BRI_PTMP", "FXO", "FXS", "EM", "NONE"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_trunk_type, ftdm_trunk_type2str, ftdm_trunk_type_t)
+
+typedef enum {
+ FTDM_ANALOG_START_KEWL,
+ FTDM_ANALOG_START_LOOP,
+ FTDM_ANALOG_START_GROUND,
+ FTDM_ANALOG_START_WINK,
+ FTDM_ANALOG_START_NA
+} ftdm_analog_start_type_t;
+#define START_TYPE_STRINGS "KEWL", "LOOP", "GROUND", "WINK", "NA"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_analog_start_type, ftdm_analog_start_type2str, ftdm_analog_start_type_t)
+
+typedef enum {
+ FTDM_OOB_ONHOOK,
+ FTDM_OOB_OFFHOOK,
+ FTDM_OOB_WINK,
+ FTDM_OOB_FLASH,
+ FTDM_OOB_RING_START,
+ FTDM_OOB_RING_STOP,
+ FTDM_OOB_ALARM_TRAP,
+ FTDM_OOB_ALARM_CLEAR,
+ FTDM_OOB_NOOP,
+ FTDM_OOB_CAS_BITS_CHANGE,
+ FTDM_OOB_INVALID
+} ftdm_oob_event_t;
+#define OOB_STRINGS "DTMF", "ONHOOK", "OFFHOOK", "WINK", "FLASH", "RING_START", "RING_STOP", "ALARM_TRAP", "ALARM_CLEAR", "NOOP", "CAS_BITS_CHANGE", "INVALID"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_oob_event, ftdm_oob_event2str, ftdm_oob_event_t)
+
+typedef enum {
+ FTDM_ALARM_NONE = 0,
+ FTDM_ALARM_RECOVER = (1 << 0),
+ FTDM_ALARM_LOOPBACK = (1 << 2),
+ FTDM_ALARM_YELLOW = (1 << 3),
+ FTDM_ALARM_RED = (1 << 4),
+ FTDM_ALARM_BLUE = (1 << 5),
+ FTDM_ALARM_NOTOPEN = ( 1 << 6),
+ FTDM_ALARM_AIS = ( 1 << 7),
+ FTDM_ALARM_RAI = ( 1 << 8),
+ FTDM_ALARM_GENERAL = ( 1 << 30)
+} ftdm_alarm_flag_t;
+
+typedef enum {
+ FTDM_SIGTYPE_NONE,
+ FTDM_SIGTYPE_ISDN,
+ FTDM_SIGTYPE_RBS,
+ FTDM_SIGTYPE_ANALOG,
+ FTDM_SIGTYPE_SANGOMABOOST,
+ FTDM_SIGTYPE_M3UA,
+ FTDM_SIGTYPE_R2
+} ftdm_signal_type_t;
+
+/*!
+ \brief Signaling status on a given span or specific channel on protocols that support it
+ */
+typedef enum {
+ /* The signaling link is down (no d-chans up in the span/group, MFC-R2 bit pattern unidentified) */
+ FTDM_SIG_STATE_DOWN,
+ /* The signaling link is suspended (MFC-R2 bit pattern blocked, ss7 blocked?) */
+ FTDM_SIG_STATE_SUSPENDED,
+ /* The signaling link is ready and calls can be placed */
+ FTDM_SIG_STATE_UP,
+ /* Invalid status */
+ FTDM_SIG_STATE_INVALID
+} ftdm_signaling_status_t;
+#define SIGSTATUS_STRINGS "DOWN", "SUSPENDED", "UP", "INVALID"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_signaling_status, ftdm_signaling_status2str, ftdm_signaling_status_t)
+
+typedef enum {
+ FTDM_SIGEVENT_START,
+ FTDM_SIGEVENT_STOP,
+ FTDM_SIGEVENT_TRANSFER,
+ FTDM_SIGEVENT_ANSWER,
+ FTDM_SIGEVENT_UP,
+ FTDM_SIGEVENT_FLASH,
+ FTDM_SIGEVENT_PROGRESS,
+ FTDM_SIGEVENT_PROGRESS_MEDIA,
+ FTDM_SIGEVENT_NOTIFY,
+ FTDM_SIGEVENT_TONE_DETECTED,
+ FTDM_SIGEVENT_ALARM_TRAP,
+ FTDM_SIGEVENT_ALARM_CLEAR,
+ FTDM_SIGEVENT_MISC,
+ FTDM_SIGEVENT_COLLECTED_DIGIT,
+ FTDM_SIGEVENT_ADD_CALL,
+ FTDM_SIGEVENT_RESTART,
+ /* Signaling status changed (D-chan up, down, R2 blocked etc) */
+ FTDM_SIGEVENT_SIGSTATUS_CHANGED,
+ FTDM_SIGEVENT_INVALID
+} ftdm_signal_event_t;
+#define SIGNAL_STRINGS "START", "STOP", "TRANSFER", "ANSWER", "UP", "FLASH", "PROGRESS", \
+ "PROGRESS_MEDIA", "NOTIFY", "TONE_DETECTED", "ALARM_TRAP", "ALARM_CLEAR", "MISC", \
+ "COLLECTED_DIGIT", "ADD_CALL", "RESTART", "SIGLINK_CHANGED", "HWSTATUS_CHANGED", "INVALID"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_signal_event, ftdm_signal_event2str, ftdm_signal_event_t)
+
+typedef enum {
+ FTDM_EVENT_NONE,
+ FTDM_EVENT_DTMF,
+ FTDM_EVENT_OOB,
+ FTDM_EVENT_COUNT
+} ftdm_event_type_t;
+
+typedef enum {
+ FTDM_TOP_DOWN,
+ FTDM_BOTTOM_UP
+} ftdm_direction_t;
+
+typedef enum {
+ FTDM_SUCCESS,
+ FTDM_FAIL,
+ FTDM_MEMERR,
+ FTDM_TIMEOUT,
+ FTDM_NOTIMPL,
+ FTDM_CHECKSUM_ERROR,
+ FTDM_STATUS_COUNT,
+ FTDM_BREAK
+} ftdm_status_t;
+
+typedef enum {
+ FTDM_NO_FLAGS = 0,
+ FTDM_READ = (1 << 0),
+ FTDM_WRITE = (1 << 1),
+ FTDM_EVENTS = (1 << 2)
+} ftdm_wait_flag_t;
+
+typedef enum {
+ FTDM_CODEC_ULAW = 0,
+ FTDM_CODEC_ALAW = 8,
+ FTDM_CODEC_SLIN = 10,
+ FTDM_CODEC_NONE = (1 << 30)
+} ftdm_codec_t;
+
+typedef enum {
+ FTDM_TONE_DTMF = (1 << 0)
+} ftdm_tone_type_t;
+
+typedef enum {
+ FTDM_COMMAND_NOOP,
+ FTDM_COMMAND_SET_INTERVAL,
+ FTDM_COMMAND_GET_INTERVAL,
+ FTDM_COMMAND_SET_CODEC,
+ FTDM_COMMAND_GET_CODEC,
+ FTDM_COMMAND_SET_NATIVE_CODEC,
+ FTDM_COMMAND_GET_NATIVE_CODEC,
+ FTDM_COMMAND_ENABLE_DTMF_DETECT,
+ FTDM_COMMAND_DISABLE_DTMF_DETECT,
+ FTDM_COMMAND_SEND_DTMF,
+ FTDM_COMMAND_SET_DTMF_ON_PERIOD,
+ FTDM_COMMAND_GET_DTMF_ON_PERIOD,
+ FTDM_COMMAND_SET_DTMF_OFF_PERIOD,
+ FTDM_COMMAND_GET_DTMF_OFF_PERIOD,
+ FTDM_COMMAND_GENERATE_RING_ON,
+ FTDM_COMMAND_GENERATE_RING_OFF,
+ FTDM_COMMAND_OFFHOOK,
+ FTDM_COMMAND_ONHOOK,
+ FTDM_COMMAND_FLASH,
+ FTDM_COMMAND_WINK,
+ FTDM_COMMAND_ENABLE_PROGRESS_DETECT,
+ FTDM_COMMAND_DISABLE_PROGRESS_DETECT,
+ FTDM_COMMAND_TRACE_INPUT,
+ FTDM_COMMAND_TRACE_OUTPUT,
+ FTDM_COMMAND_ENABLE_CALLERID_DETECT,
+ FTDM_COMMAND_DISABLE_CALLERID_DETECT,
+ FTDM_COMMAND_ENABLE_ECHOCANCEL,
+ FTDM_COMMAND_DISABLE_ECHOCANCEL,
+ FTDM_COMMAND_ENABLE_ECHOTRAIN,
+ FTDM_COMMAND_DISABLE_ECHOTRAIN,
+ FTDM_COMMAND_SET_CAS_BITS,
+ FTDM_COMMAND_GET_CAS_BITS,
+ FTDM_COMMAND_SET_RX_GAIN,
+ FTDM_COMMAND_GET_RX_GAIN,
+ FTDM_COMMAND_SET_TX_GAIN,
+ FTDM_COMMAND_GET_TX_GAIN,
+ FTDM_COMMAND_FLUSH_TX_BUFFERS,
+ FTDM_COMMAND_FLUSH_RX_BUFFERS,
+ FTDM_COMMAND_FLUSH_BUFFERS,
+ FTDM_COMMAND_SET_PRE_BUFFER_SIZE,
+ FTDM_COMMAND_SET_LINK_STATUS,
+ FTDM_COMMAND_GET_LINK_STATUS,
+ FTDM_COMMAND_ENABLE_LOOP,
+ FTDM_COMMAND_DISABLE_LOOP,
+ FTDM_COMMAND_COUNT
+} ftdm_command_t;
+
+typedef enum {
+ FTDM_SPAN_CONFIGURED = (1 << 0),
+ FTDM_SPAN_READY = (1 << 1),
+ FTDM_SPAN_STATE_CHANGE = (1 << 2),
+ FTDM_SPAN_SUSPENDED = (1 << 3),
+ FTDM_SPAN_IN_THREAD = (1 << 4),
+ FTDM_SPAN_STOP_THREAD = (1 << 5)
+} ftdm_span_flag_t;
+
+typedef enum {
+ FTDM_CHAN_TYPE_B,
+ FTDM_CHAN_TYPE_DQ921,
+ FTDM_CHAN_TYPE_DQ931,
+ FTDM_CHAN_TYPE_FXS,
+ FTDM_CHAN_TYPE_FXO,
+ FTDM_CHAN_TYPE_EM,
+ FTDM_CHAN_TYPE_CAS,
+ FTDM_CHAN_TYPE_COUNT
+} ftdm_chan_type_t;
+
+#define FTDM_IS_VOICE_CHANNEL(ftdm_chan) ((ftdm_chan)->type != FTDM_CHAN_TYPE_DQ921 && (ftdm_chan)->type != FTDM_CHAN_TYPE_DQ931)
+
+#define CHAN_TYPE_STRINGS "B", "DQ921", "DQ931", "FXS", "FXO", "EM", "CAS", "INVALID"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_chan_type, ftdm_chan_type2str, ftdm_chan_type_t)
+
+typedef enum {
+ FTDM_CHANNEL_FEATURE_DTMF_DETECT = (1 << 0),
+ FTDM_CHANNEL_FEATURE_DTMF_GENERATE = (1 << 1),
+ FTDM_CHANNEL_FEATURE_CODECS = (1 << 2),
+ FTDM_CHANNEL_FEATURE_INTERVAL = (1 << 3),
+ FTDM_CHANNEL_FEATURE_CALLERID = (1 << 4),
+ FTDM_CHANNEL_FEATURE_PROGRESS = (1 << 5)
+} ftdm_channel_feature_t;
+
+typedef enum {
+ FTDM_CHANNEL_STATE_DOWN,
+ FTDM_CHANNEL_STATE_HOLD,
+ FTDM_CHANNEL_STATE_SUSPENDED,
+ FTDM_CHANNEL_STATE_DIALTONE,
+ FTDM_CHANNEL_STATE_COLLECT,
+ FTDM_CHANNEL_STATE_RING,
+ FTDM_CHANNEL_STATE_BUSY,
+ FTDM_CHANNEL_STATE_ATTN,
+ FTDM_CHANNEL_STATE_GENRING,
+ FTDM_CHANNEL_STATE_DIALING,
+ FTDM_CHANNEL_STATE_GET_CALLERID,
+ FTDM_CHANNEL_STATE_CALLWAITING,
+ FTDM_CHANNEL_STATE_RESTART,
+ FTDM_CHANNEL_STATE_PROGRESS,
+ FTDM_CHANNEL_STATE_PROGRESS_MEDIA,
+ FTDM_CHANNEL_STATE_UP,
+ FTDM_CHANNEL_STATE_IDLE,
+ FTDM_CHANNEL_STATE_TERMINATING,
+ FTDM_CHANNEL_STATE_CANCEL,
+ FTDM_CHANNEL_STATE_HANGUP,
+ FTDM_CHANNEL_STATE_HANGUP_COMPLETE,
+ FTDM_CHANNEL_STATE_IN_LOOP,
+ FTDM_CHANNEL_STATE_INVALID
+} ftdm_channel_state_t;
+#define CHANNEL_STATE_STRINGS "DOWN", "HOLD", "SUSPENDED", "DIALTONE", "COLLECT", \
+ "RING", "BUSY", "ATTN", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", \
+ "RESTART", "PROGRESS", "PROGRESS_MEDIA", "UP", "IDLE", "TERMINATING", "CANCEL", "HANGUP", "HANGUP_COMPLETE", "INVALID"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t)
+
+typedef enum {
+ FTDM_CHANNEL_CONFIGURED = (1 << 0),
+ FTDM_CHANNEL_READY = (1 << 1),
+ FTDM_CHANNEL_OPEN = (1 << 2),
+ FTDM_CHANNEL_DTMF_DETECT = (1 << 3),
+ FTDM_CHANNEL_SUPRESS_DTMF = (1 << 4),
+ FTDM_CHANNEL_TRANSCODE = (1 << 5),
+ FTDM_CHANNEL_BUFFER = (1 << 6),
+ FTDM_CHANNEL_EVENT = (1 << 7),
+ FTDM_CHANNEL_INTHREAD = (1 << 8),
+ FTDM_CHANNEL_WINK = (1 << 9),
+ FTDM_CHANNEL_FLASH = (1 << 10),
+ FTDM_CHANNEL_STATE_CHANGE = (1 << 11),
+ FTDM_CHANNEL_HOLD = (1 << 12),
+ FTDM_CHANNEL_INUSE = (1 << 13),
+ FTDM_CHANNEL_OFFHOOK = (1 << 14),
+ FTDM_CHANNEL_RINGING = (1 << 15),
+ FTDM_CHANNEL_PROGRESS_DETECT = (1 << 16),
+ FTDM_CHANNEL_CALLERID_DETECT = (1 << 17),
+ FTDM_CHANNEL_OUTBOUND = (1 << 18),
+ FTDM_CHANNEL_SUSPENDED = (1 << 19),
+ FTDM_CHANNEL_3WAY = (1 << 20),
+ FTDM_CHANNEL_PROGRESS = (1 << 21),
+ FTDM_CHANNEL_MEDIA = (1 << 22),
+ FTDM_CHANNEL_ANSWERED = (1 << 23),
+ FTDM_CHANNEL_MUTE = (1 << 24),
+ FTDM_CHANNEL_USE_RX_GAIN = (1 << 25),
+ FTDM_CHANNEL_USE_TX_GAIN = (1 << 26),
+ FTDM_CHANNEL_IN_ALARM = (1 << 27),
+} ftdm_channel_flag_t;
+#if defined(__cplusplus) && defined(WIN32)
+ // fix C2676
+__inline__ ftdm_channel_flag_t operator|=(ftdm_channel_flag_t a, int32_t b) {
+ a = (ftdm_channel_flag_t)(a | b);
+ return a;
+}
+__inline__ ftdm_channel_flag_t operator&=(ftdm_channel_flag_t a, int32_t b) {
+ a = (ftdm_channel_flag_t)(a & b);
+ return a;
+}
+#endif
+
+typedef enum {
+ ZSM_NONE,
+ ZSM_UNACCEPTABLE,
+ ZSM_ACCEPTABLE
+} ftdm_state_map_type_t;
+
+typedef enum {
+ ZSD_INBOUND,
+ ZSD_OUTBOUND,
+} ftdm_state_direction_t;
+
+#define FTDM_MAP_NODE_SIZE 512
+#define FTDM_MAP_MAX FTDM_CHANNEL_STATE_INVALID+2
+
+struct ftdm_state_map_node {
+ ftdm_state_direction_t direction;
+ ftdm_state_map_type_t type;
+ ftdm_channel_state_t check_states[FTDM_MAP_MAX];
+ ftdm_channel_state_t states[FTDM_MAP_MAX];
+};
+typedef struct ftdm_state_map_node ftdm_state_map_node_t;
+
+struct ftdm_state_map {
+ ftdm_state_map_node_t nodes[FTDM_MAP_NODE_SIZE];
+};
+typedef struct ftdm_state_map ftdm_state_map_t;
+
+typedef enum ftdm_channel_hw_link_status {
+ FTDM_HW_LINK_DISCONNECTED = 0,
+ FTDM_HW_LINK_CONNECTED
+} ftdm_channel_hw_link_status_t;
+
+typedef struct ftdm_conf_parameter_s {
+ const char *var;
+ const char *val;
+} ftdm_conf_parameter_t;
+
+typedef struct ftdm_channel ftdm_channel_t;
+typedef struct ftdm_event ftdm_event_t;
+typedef struct ftdm_sigmsg ftdm_sigmsg_t;
+typedef struct ftdm_span ftdm_span_t;
+typedef struct ftdm_group ftdm_group_t;
+typedef struct ftdm_caller_data ftdm_caller_data_t;
+typedef struct ftdm_io_interface ftdm_io_interface_t;
+
+struct ftdm_stream_handle;
+typedef struct ftdm_stream_handle ftdm_stream_handle_t;
+
+typedef ftdm_status_t (*ftdm_stream_handle_raw_write_function_t) (ftdm_stream_handle_t *handle, uint8_t *data, ftdm_size_t datalen);
+typedef ftdm_status_t (*ftdm_stream_handle_write_function_t) (ftdm_stream_handle_t *handle, const char *fmt, ...);
+
+#define FIO_CHANNEL_REQUEST_ARGS (ftdm_span_t *span, uint32_t chan_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
+#define FIO_CHANNEL_OUTGOING_CALL_ARGS (ftdm_channel_t *ftdmchan)
+#define FIO_CHANNEL_SET_SIG_STATUS_ARGS (ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status)
+#define FIO_CHANNEL_GET_SIG_STATUS_ARGS (ftdm_channel_t *ftdmchan, ftdm_signaling_status_t *status)
+#define FIO_SPAN_SET_SIG_STATUS_ARGS (ftdm_span_t *span, ftdm_signaling_status_t status)
+#define FIO_SPAN_GET_SIG_STATUS_ARGS (ftdm_span_t *span, ftdm_signaling_status_t *status)
+#define FIO_SPAN_POLL_EVENT_ARGS (ftdm_span_t *span, uint32_t ms)
+#define FIO_SPAN_NEXT_EVENT_ARGS (ftdm_span_t *span, ftdm_event_t **event)
+#define FIO_SIGNAL_CB_ARGS (ftdm_sigmsg_t *sigmsg)
+#define FIO_EVENT_CB_ARGS (ftdm_channel_t *ftdmchan, ftdm_event_t *event)
+#define FIO_CODEC_ARGS (void *data, ftdm_size_t max, ftdm_size_t *datalen)
+#define FIO_CONFIGURE_SPAN_ARGS (ftdm_span_t *span, const char *str, ftdm_chan_type_t type, char *name, char *number)
+#define FIO_CONFIGURE_ARGS (const char *category, const char *var, const char *val, int lineno)
+#define FIO_OPEN_ARGS (ftdm_channel_t *ftdmchan)
+#define FIO_CLOSE_ARGS (ftdm_channel_t *ftdmchan)
+#define FIO_CHANNEL_DESTROY_ARGS (ftdm_channel_t *ftdmchan)
+#define FIO_SPAN_DESTROY_ARGS (ftdm_span_t *span)
+#define FIO_COMMAND_ARGS (ftdm_channel_t *ftdmchan, ftdm_command_t command, void *obj)
+#define FIO_WAIT_ARGS (ftdm_channel_t *ftdmchan, ftdm_wait_flag_t *flags, int32_t to)
+#define FIO_GET_ALARMS_ARGS (ftdm_channel_t *ftdmchan)
+#define FIO_READ_ARGS (ftdm_channel_t *ftdmchan, void *data, ftdm_size_t *datalen)
+#define FIO_WRITE_ARGS (ftdm_channel_t *ftdmchan, void *data, ftdm_size_t *datalen)
+#define FIO_IO_LOAD_ARGS (ftdm_io_interface_t **fio)
+#define FIO_IO_UNLOAD_ARGS (void)
+#define FIO_SIG_LOAD_ARGS (void)
+#define FIO_SIG_CONFIGURE_ARGS (ftdm_span_t *span, fio_signal_cb_t sig_cb, va_list ap)
+#define FIO_CONFIGURE_SPAN_SIGNALING_ARGS (ftdm_span_t *span, fio_signal_cb_t sig_cb, ftdm_conf_parameter_t *ftdm_parameters)
+#define FIO_SIG_UNLOAD_ARGS (void)
+#define FIO_API_ARGS (ftdm_stream_handle_t *stream, const char *data)
+
+typedef ftdm_status_t (*fio_channel_request_t) FIO_CHANNEL_REQUEST_ARGS ;
+typedef ftdm_status_t (*fio_channel_outgoing_call_t) FIO_CHANNEL_OUTGOING_CALL_ARGS ;
+typedef ftdm_status_t (*fio_channel_set_sig_status_t) FIO_CHANNEL_SET_SIG_STATUS_ARGS;
+typedef ftdm_status_t (*fio_channel_get_sig_status_t) FIO_CHANNEL_GET_SIG_STATUS_ARGS;
+typedef ftdm_status_t (*fio_span_set_sig_status_t) FIO_SPAN_SET_SIG_STATUS_ARGS;
+typedef ftdm_status_t (*fio_span_get_sig_status_t) FIO_SPAN_GET_SIG_STATUS_ARGS;
+typedef ftdm_status_t (*fio_span_poll_event_t) FIO_SPAN_POLL_EVENT_ARGS ;
+typedef ftdm_status_t (*fio_span_next_event_t) FIO_SPAN_NEXT_EVENT_ARGS ;
+typedef ftdm_status_t (*fio_signal_cb_t) FIO_SIGNAL_CB_ARGS ;
+typedef ftdm_status_t (*fio_event_cb_t) FIO_EVENT_CB_ARGS ;
+typedef ftdm_status_t (*fio_codec_t) FIO_CODEC_ARGS ;
+typedef ftdm_status_t (*fio_configure_span_t) FIO_CONFIGURE_SPAN_ARGS ;
+typedef ftdm_status_t (*fio_configure_t) FIO_CONFIGURE_ARGS ;
+typedef ftdm_status_t (*fio_open_t) FIO_OPEN_ARGS ;
+typedef ftdm_status_t (*fio_close_t) FIO_CLOSE_ARGS ;
+typedef ftdm_status_t (*fio_channel_destroy_t) FIO_CHANNEL_DESTROY_ARGS ;
+typedef ftdm_status_t (*fio_span_destroy_t) FIO_SPAN_DESTROY_ARGS ;
+typedef ftdm_status_t (*fio_get_alarms_t) FIO_GET_ALARMS_ARGS ;
+typedef ftdm_status_t (*fio_command_t) FIO_COMMAND_ARGS ;
+typedef ftdm_status_t (*fio_wait_t) FIO_WAIT_ARGS ;
+typedef ftdm_status_t (*fio_read_t) FIO_READ_ARGS ;
+typedef ftdm_status_t (*fio_write_t) FIO_WRITE_ARGS ;
+typedef ftdm_status_t (*fio_io_load_t) FIO_IO_LOAD_ARGS ;
+typedef ftdm_status_t (*fio_sig_load_t) FIO_SIG_LOAD_ARGS ;
+typedef ftdm_status_t (*fio_sig_configure_t) FIO_SIG_CONFIGURE_ARGS ;
+typedef ftdm_status_t (*fio_configure_span_signaling_t) FIO_CONFIGURE_SPAN_SIGNALING_ARGS ;
+typedef ftdm_status_t (*fio_io_unload_t) FIO_IO_UNLOAD_ARGS ;
+typedef ftdm_status_t (*fio_sig_unload_t) FIO_SIG_UNLOAD_ARGS ;
+typedef ftdm_status_t (*fio_api_t) FIO_API_ARGS ;
+
+
+#define FIO_CHANNEL_REQUEST_FUNCTION(name) ftdm_status_t name FIO_CHANNEL_REQUEST_ARGS
+#define FIO_CHANNEL_OUTGOING_CALL_FUNCTION(name) ftdm_status_t name FIO_CHANNEL_OUTGOING_CALL_ARGS
+#define FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(name) ftdm_status_t name FIO_CHANNEL_SET_SIG_STATUS_ARGS
+#define FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(name) ftdm_status_t name FIO_CHANNEL_GET_SIG_STATUS_ARGS
+#define FIO_SPAN_SET_SIG_STATUS_FUNCTION(name) ftdm_status_t name FIO_SPAN_SET_SIG_STATUS_ARGS
+#define FIO_SPAN_GET_SIG_STATUS_FUNCTION(name) ftdm_status_t name FIO_SPAN_GET_SIG_STATUS_ARGS
+#define FIO_SPAN_POLL_EVENT_FUNCTION(name) ftdm_status_t name FIO_SPAN_POLL_EVENT_ARGS
+#define FIO_SPAN_NEXT_EVENT_FUNCTION(name) ftdm_status_t name FIO_SPAN_NEXT_EVENT_ARGS
+#define FIO_SIGNAL_CB_FUNCTION(name) ftdm_status_t name FIO_SIGNAL_CB_ARGS
+#define FIO_EVENT_CB_FUNCTION(name) ftdm_status_t name FIO_EVENT_CB_ARGS
+#define FIO_CODEC_FUNCTION(name) FT_DECLARE_NONSTD(ftdm_status_t) name FIO_CODEC_ARGS
+#define FIO_CONFIGURE_SPAN_FUNCTION(name) ftdm_status_t name FIO_CONFIGURE_SPAN_ARGS
+#define FIO_CONFIGURE_FUNCTION(name) ftdm_status_t name FIO_CONFIGURE_ARGS
+#define FIO_OPEN_FUNCTION(name) ftdm_status_t name FIO_OPEN_ARGS
+#define FIO_CLOSE_FUNCTION(name) ftdm_status_t name FIO_CLOSE_ARGS
+#define FIO_CHANNEL_DESTROY_FUNCTION(name) ftdm_status_t name FIO_CHANNEL_DESTROY_ARGS
+#define FIO_SPAN_DESTROY_FUNCTION(name) ftdm_status_t name FIO_SPAN_DESTROY_ARGS
+#define FIO_GET_ALARMS_FUNCTION(name) ftdm_status_t name FIO_GET_ALARMS_ARGS
+#define FIO_COMMAND_FUNCTION(name) ftdm_status_t name FIO_COMMAND_ARGS
+#define FIO_WAIT_FUNCTION(name) ftdm_status_t name FIO_WAIT_ARGS
+#define FIO_READ_FUNCTION(name) ftdm_status_t name FIO_READ_ARGS
+#define FIO_WRITE_FUNCTION(name) ftdm_status_t name FIO_WRITE_ARGS
+#define FIO_IO_LOAD_FUNCTION(name) ftdm_status_t name FIO_IO_LOAD_ARGS
+#define FIO_SIG_LOAD_FUNCTION(name) ftdm_status_t name FIO_SIG_LOAD_ARGS
+#define FIO_SIG_CONFIGURE_FUNCTION(name) ftdm_status_t name FIO_SIG_CONFIGURE_ARGS
+#define FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(name) ftdm_status_t name FIO_CONFIGURE_SPAN_SIGNALING_ARGS
+#define FIO_IO_UNLOAD_FUNCTION(name) ftdm_status_t name FIO_IO_UNLOAD_ARGS
+#define FIO_SIG_UNLOAD_FUNCTION(name) ftdm_status_t name FIO_SIG_UNLOAD_ARGS
+#define FIO_API_FUNCTION(name) ftdm_status_t name FIO_API_ARGS
+
+#include "ftdm_dso.h"
+
+typedef struct {
+ char name[256];
+ fio_io_load_t io_load;
+ fio_io_unload_t io_unload;
+ fio_sig_load_t sig_load;
+ fio_sig_configure_t sig_configure;
+ fio_sig_unload_t sig_unload;
+ /*!
+ \brief configure a given span signaling
+ \see sig_configure
+ This is just like sig_configure but receives
+ an array of paramters instead of va_list
+ I'd like to deprecate sig_configure and move
+ all modules to use sigparam_configure
+ */
+ fio_configure_span_signaling_t configure_span_signaling;
+ ftdm_dso_lib_t lib;
+ char path[256];
+} ftdm_module_t;
+
+#ifndef __FUNCTION__
+#define __FUNCTION__ (const char *)__func__
+#endif
+
+#define FTDM_PRE __FILE__, __FUNCTION__, __LINE__
+#define FTDM_LOG_LEVEL_DEBUG 7
+#define FTDM_LOG_LEVEL_INFO 6
+#define FTDM_LOG_LEVEL_NOTICE 5
+#define FTDM_LOG_LEVEL_WARNING 4
+#define FTDM_LOG_LEVEL_ERROR 3
+#define FTDM_LOG_LEVEL_CRIT 2
+#define FTDM_LOG_LEVEL_ALERT 1
+#define FTDM_LOG_LEVEL_EMERG 0
+
+#define FTDM_LOG_DEBUG FTDM_PRE, FTDM_LOG_LEVEL_DEBUG
+#define FTDM_LOG_INFO FTDM_PRE, FTDM_LOG_LEVEL_INFO
+#define FTDM_LOG_NOTICE FTDM_PRE, FTDM_LOG_LEVEL_NOTICE
+#define FTDM_LOG_WARNING FTDM_PRE, FTDM_LOG_LEVEL_WARNING
+#define FTDM_LOG_ERROR FTDM_PRE, FTDM_LOG_LEVEL_ERROR
+#define FTDM_LOG_CRIT FTDM_PRE, FTDM_LOG_LEVEL_CRIT
+#define FTDM_LOG_ALERT FTDM_PRE, FTDM_LOG_LEVEL_ALERT
+#define FTDM_LOG_EMERG FTDM_PRE, FTDM_LOG_LEVEL_EMERG
+
+typedef struct ftdm_fsk_data_state ftdm_fsk_data_state_t;
+typedef int (*ftdm_fsk_data_decoder_t)(ftdm_fsk_data_state_t *state);
+typedef ftdm_status_t (*ftdm_fsk_write_sample_t)(int16_t *buf, ftdm_size_t buflen, void *user_data);
+typedef void (*ftdm_logger_t)(const char *file, const char *func, int line, int level, const char *fmt, ...);
+typedef struct hashtable ftdm_hash_t;
+typedef struct hashtable_iterator ftdm_hash_iterator_t;
+typedef struct key ftdm_hash_key_t;
+typedef struct value ftdm_hash_val_t;
+typedef struct ftdm_bitstream ftdm_bitstream_t;
+typedef struct ftdm_fsk_modulator ftdm_fsk_modulator_t;
+typedef ftdm_status_t (*ftdm_span_start_t)(ftdm_span_t *span);
+typedef ftdm_status_t (*ftdm_span_stop_t)(ftdm_span_t *span);
+
+typedef enum {
+ FTDM_CAUSE_NONE = 0,
+ FTDM_CAUSE_UNALLOCATED = 1,
+ FTDM_CAUSE_NO_ROUTE_TRANSIT_NET = 2,
+ FTDM_CAUSE_NO_ROUTE_DESTINATION = 3,
+ FTDM_CAUSE_CHANNEL_UNACCEPTABLE = 6,
+ FTDM_CAUSE_CALL_AWARDED_DELIVERED = 7,
+ FTDM_CAUSE_NORMAL_CLEARING = 16,
+ FTDM_CAUSE_USER_BUSY = 17,
+ FTDM_CAUSE_NO_USER_RESPONSE = 18,
+ FTDM_CAUSE_NO_ANSWER = 19,
+ FTDM_CAUSE_SUBSCRIBER_ABSENT = 20,
+ FTDM_CAUSE_CALL_REJECTED = 21,
+ FTDM_CAUSE_NUMBER_CHANGED = 22,
+ FTDM_CAUSE_REDIRECTION_TO_NEW_DESTINATION = 23,
+ FTDM_CAUSE_EXCHANGE_ROUTING_ERROR = 25,
+ FTDM_CAUSE_DESTINATION_OUT_OF_ORDER = 27,
+ FTDM_CAUSE_INVALID_NUMBER_FORMAT = 28,
+ FTDM_CAUSE_FACILITY_REJECTED = 29,
+ FTDM_CAUSE_RESPONSE_TO_STATUS_ENQUIRY = 30,
+ FTDM_CAUSE_NORMAL_UNSPECIFIED = 31,
+ FTDM_CAUSE_NORMAL_CIRCUIT_CONGESTION = 34,
+ FTDM_CAUSE_NETWORK_OUT_OF_ORDER = 38,
+ FTDM_CAUSE_NORMAL_TEMPORARY_FAILURE = 41,
+ FTDM_CAUSE_SWITCH_CONGESTION = 42,
+ FTDM_CAUSE_ACCESS_INFO_DISCARDED = 43,
+ FTDM_CAUSE_REQUESTED_CHAN_UNAVAIL = 44,
+ FTDM_CAUSE_PRE_EMPTED = 45,
+ FTDM_CAUSE_FACILITY_NOT_SUBSCRIBED = 50,
+ FTDM_CAUSE_OUTGOING_CALL_BARRED = 52,
+ FTDM_CAUSE_INCOMING_CALL_BARRED = 54,
+ FTDM_CAUSE_BEARERCAPABILITY_NOTAUTH = 57,
+ FTDM_CAUSE_BEARERCAPABILITY_NOTAVAIL = 58,
+ FTDM_CAUSE_SERVICE_UNAVAILABLE = 63,
+ FTDM_CAUSE_BEARERCAPABILITY_NOTIMPL = 65,
+ FTDM_CAUSE_CHAN_NOT_IMPLEMENTED = 66,
+ FTDM_CAUSE_FACILITY_NOT_IMPLEMENTED = 69,
+ FTDM_CAUSE_SERVICE_NOT_IMPLEMENTED = 79,
+ FTDM_CAUSE_INVALID_CALL_REFERENCE = 81,
+ FTDM_CAUSE_INCOMPATIBLE_DESTINATION = 88,
+ FTDM_CAUSE_INVALID_MSG_UNSPECIFIED = 95,
+ FTDM_CAUSE_MANDATORY_IE_MISSING = 96,
+ FTDM_CAUSE_MESSAGE_TYPE_NONEXIST = 97,
+ FTDM_CAUSE_WRONG_MESSAGE = 98,
+ FTDM_CAUSE_IE_NONEXIST = 99,
+ FTDM_CAUSE_INVALID_IE_CONTENTS = 100,
+ FTDM_CAUSE_WRONG_CALL_STATE = 101,
+ FTDM_CAUSE_RECOVERY_ON_TIMER_EXPIRE = 102,
+ FTDM_CAUSE_MANDATORY_IE_LENGTH_ERROR = 103,
+ FTDM_CAUSE_PROTOCOL_ERROR = 111,
+ FTDM_CAUSE_INTERWORKING = 127,
+ FTDM_CAUSE_SUCCESS = 142,
+ FTDM_CAUSE_ORIGINATOR_CANCEL = 487,
+ FTDM_CAUSE_CRASH = 500,
+ FTDM_CAUSE_SYSTEM_SHUTDOWN = 501,
+ FTDM_CAUSE_LOSE_RACE = 502,
+ FTDM_CAUSE_MANAGER_REQUEST = 503,
+ FTDM_CAUSE_BLIND_TRANSFER = 600,
+ FTDM_CAUSE_ATTENDED_TRANSFER = 601,
+ FTDM_CAUSE_ALLOTTED_TIMEOUT = 602,
+ FTDM_CAUSE_USER_CHALLENGE = 603,
+ FTDM_CAUSE_MEDIA_TIMEOUT = 604
+} ftdm_call_cause_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/freetdm/src/include/g711.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/include/g711.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/g711.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,395 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * g711.h - In line A-law and u-law conversion routines
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2001 Steve Underwood
+ *
+ * Despite my general liking of the GPL, I place this code in the
+ * public domain for the benefit of all mankind - even the slimy
+ * ones who might try to proprietize my work and use it to my
+ * detriment.
+ *
+ * $Id: g711.h,v 1.1 2006/06/07 15:46:39 steveu Exp $
+ */
+
+/*! \file */
+
+/*! \page g711_page A-law and mu-law handling
+ Lookup tables for A-law and u-law look attractive, until you consider the impact
+ on the CPU cache. If it causes a substantial area of your processor cache to get
+ hit too often, cache sloshing will severely slow things down. The main reason
+ these routines are slow in C, is the lack of direct access to the CPU's "find
+ the first 1" instruction. A little in-line assembler fixes that, and the
+ conversion routines can be faster than lookup tables, in most real world usage.
+ A "find the first 1" instruction is available on most modern CPUs, and is a
+ much underused feature.
+
+ If an assembly language method of bit searching is not available, these routines
+ revert to a method that can be a little slow, so the cache thrashing might not
+ seem so bad :(
+
+ Feel free to submit patches to add fast "find the first 1" support for your own
+ favourite processor.
+
+ Look up tables are used for transcoding between A-law and u-law, since it is
+ difficult to achieve the precise transcoding procedure laid down in the G.711
+ specification by other means.
+*/
+
+#if !defined(_G711_H_)
+#define _G711_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+ typedef unsigned __int8 uint8_t;
+ typedef __int16 int16_t;
+ typedef __int32 int32_t;
+ typedef unsigned __int16 uint16_t;
+#else
+#include <stdint.h>
+#endif
+
+#if defined(__i386__)
+ /*! \brief Find the bit position of the highest set bit in a word
+ \param bits The word to be searched
+ \return The bit number of the highest set bit, or -1 if the word is zero. */
+ static __inline__ int top_bit(unsigned int bits)
+ {
+ int res;
+
+ __asm__ __volatile__(" movl $-1,%%edx;\n"
+ " bsrl %%eax,%%edx;\n"
+ : "=d" (res)
+ : "a" (bits));
+ return res;
+ }
+ /*- End of function --------------------------------------------------------*/
+
+ /*! \brief Find the bit position of the lowest set bit in a word
+ \param bits The word to be searched
+ \return The bit number of the lowest set bit, or -1 if the word is zero. */
+ static __inline__ int bottom_bit(unsigned int bits)
+ {
+ int res;
+
+ __asm__ __volatile__(" movl $-1,%%edx;\n"
+ " bsfl %%eax,%%edx;\n"
+ : "=d" (res)
+ : "a" (bits));
+ return res;
+ }
+ /*- End of function --------------------------------------------------------*/
+#elif defined(__x86_64__)
+ static __inline__ int top_bit(unsigned int bits)
+ {
+ int res;
+
+ __asm__ __volatile__(" movq $-1,%%rdx;\n"
+ " bsrq %%rax,%%rdx;\n"
+ : "=d" (res)
+ : "a" (bits));
+ return res;
+ }
+ /*- End of function --------------------------------------------------------*/
+
+ static __inline__ int bottom_bit(unsigned int bits)
+ {
+ int res;
+
+ __asm__ __volatile__(" movq $-1,%%rdx;\n"
+ " bsfq %%rax,%%rdx;\n"
+ : "=d" (res)
+ : "a" (bits));
+ return res;
+ }
+ /*- End of function --------------------------------------------------------*/
+#else
+ static __inline__ int top_bit(unsigned int bits)
+ {
+ int i;
+
+ if (bits == 0)
+ return -1;
+ i = 0;
+ if (bits & 0xFFFF0000)
+ {
+ bits &= 0xFFFF0000;
+ i += 16;
+ }
+ if (bits & 0xFF00FF00)
+ {
+ bits &= 0xFF00FF00;
+ i += 8;
+ }
+ if (bits & 0xF0F0F0F0)
+ {
+ bits &= 0xF0F0F0F0;
+ i += 4;
+ }
+ if (bits & 0xCCCCCCCC)
+ {
+ bits &= 0xCCCCCCCC;
+ i += 2;
+ }
+ if (bits & 0xAAAAAAAA)
+ {
+ bits &= 0xAAAAAAAA;
+ i += 1;
+ }
+ return i;
+ }
+ /*- End of function --------------------------------------------------------*/
+
+ static __inline__ int bottom_bit(unsigned int bits)
+ {
+ int i;
+
+ if (bits == 0)
+ return -1;
+ i = 32;
+ if (bits & 0x0000FFFF)
+ {
+ bits &= 0x0000FFFF;
+ i -= 16;
+ }
+ if (bits & 0x00FF00FF)
+ {
+ bits &= 0x00FF00FF;
+ i -= 8;
+ }
+ if (bits & 0x0F0F0F0F)
+ {
+ bits &= 0x0F0F0F0F;
+ i -= 4;
+ }
+ if (bits & 0x33333333)
+ {
+ bits &= 0x33333333;
+ i -= 2;
+ }
+ if (bits & 0x55555555)
+ {
+ bits &= 0x55555555;
+ i -= 1;
+ }
+ return i;
+ }
+ /*- End of function --------------------------------------------------------*/
+#endif
+
+ /* N.B. It is tempting to use look-up tables for A-law and u-law conversion.
+ * However, you should consider the cache footprint.
+ *
+ * A 64K byte table for linear to x-law and a 512 byte table for x-law to
+ * linear sound like peanuts these days, and shouldn't an array lookup be
+ * real fast? No! When the cache sloshes as badly as this one will, a tight
+ * calculation may be better. The messiest part is normally finding the
+ * segment, but a little inline assembly can fix that on an i386, x86_64 and
+ * many other modern processors.
+ */
+
+ /*
+ * Mu-law is basically as follows:
+ *
+ * Biased Linear Input Code Compressed Code
+ * ------------------------ ---------------
+ * 00000001wxyza 000wxyz
+ * 0000001wxyzab 001wxyz
+ * 000001wxyzabc 010wxyz
+ * 00001wxyzabcd 011wxyz
+ * 0001wxyzabcde 100wxyz
+ * 001wxyzabcdef 101wxyz
+ * 01wxyzabcdefg 110wxyz
+ * 1wxyzabcdefgh 111wxyz
+ *
+ * Each biased linear code has a leading 1 which identifies the segment
+ * number. The value of the segment number is equal to 7 minus the number
+ * of leading 0's. The quantization interval is directly available as the
+ * four bits wxyz. * The trailing bits (a - h) are ignored.
+ *
+ * Ordinarily the complement of the resulting code word is used for
+ * transmission, and so the code word is complemented before it is returned.
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+
+ /*#define ULAW_ZEROTRAP*/ /* turn on the trap as per the MIL-STD */
+#define ULAW_BIAS 0x84 /* Bias for linear code. */
+
+ /*! \brief Encode a linear sample to u-law
+ \param linear The sample to encode.
+ \return The u-law value.
+ */
+ static __inline__ uint8_t linear_to_ulaw(int linear)
+ {
+ uint8_t u_val;
+ int mask;
+ int seg;
+
+ /* Get the sign and the magnitude of the value. */
+ if (linear < 0)
+ {
+ linear = ULAW_BIAS - linear;
+ mask = 0x7F;
+ }
+ else
+ {
+ linear = ULAW_BIAS + linear;
+ mask = 0xFF;
+ }
+
+ seg = top_bit(linear | 0xFF) - 7;
+
+ /*
+ * Combine the sign, segment, quantization bits,
+ * and complement the code word.
+ */
+ if (seg >= 8)
+ u_val = (uint8_t) (0x7F ^ mask);
+ else
+ u_val = (uint8_t) (((seg << 4) | ((linear >> (seg + 3)) & 0xF)) ^ mask);
+#ifdef ULAW_ZEROTRAP
+ /* Optional ITU trap */
+ if (u_val == 0)
+ u_val = 0x02;
+#endif
+ return u_val;
+ }
+ /*- End of function --------------------------------------------------------*/
+
+ /*! \brief Decode an u-law sample to a linear value.
+ \param ulaw The u-law sample to decode.
+ \return The linear value.
+ */
+ static __inline__ int16_t ulaw_to_linear(uint8_t ulaw)
+ {
+ int t;
+
+ /* Complement to obtain normal u-law value. */
+ ulaw = ~ulaw;
+ /*
+ * Extract and bias the quantization bits. Then
+ * shift up by the segment number and subtract out the bias.
+ */
+ t = (((ulaw & 0x0F) << 3) + ULAW_BIAS) << (((int) ulaw & 0x70) >> 4);
+ return (int16_t) ((ulaw & 0x80) ? (ULAW_BIAS - t) : (t - ULAW_BIAS));
+ }
+ /*- End of function --------------------------------------------------------*/
+
+ /*
+ * A-law is basically as follows:
+ *
+ * Linear Input Code Compressed Code
+ * ----------------- ---------------
+ * 0000000wxyza 000wxyz
+ * 0000001wxyza 001wxyz
+ * 000001wxyzab 010wxyz
+ * 00001wxyzabc 011wxyz
+ * 0001wxyzabcd 100wxyz
+ * 001wxyzabcde 101wxyz
+ * 01wxyzabcdef 110wxyz
+ * 1wxyzabcdefg 111wxyz
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+
+#define ALAW_AMI_MASK 0x55
+
+ /*! \brief Encode a linear sample to A-law
+ \param linear The sample to encode.
+ \return The A-law value.
+ */
+ static __inline__ uint8_t linear_to_alaw(int linear)
+ {
+ int mask;
+ int seg;
+
+ if (linear >= 0)
+ {
+ /* Sign (bit 7) bit = 1 */
+ mask = ALAW_AMI_MASK | 0x80;
+ }
+ else
+ {
+ /* Sign (bit 7) bit = 0 */
+ mask = ALAW_AMI_MASK;
+ linear = -linear - 8;
+ }
+
+ /* Convert the scaled magnitude to segment number. */
+ seg = top_bit(linear | 0xFF) - 7;
+ if (seg >= 8)
+ {
+ if (linear >= 0)
+ {
+ /* Out of range. Return maximum value. */
+ return (uint8_t) (0x7F ^ mask);
+ }
+ /* We must be just a tiny step below zero */
+ return (uint8_t) (0x00 ^ mask);
+ }
+ /* Combine the sign, segment, and quantization bits. */
+ return (uint8_t) (((seg << 4) | ((linear >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask);
+ }
+ /*- End of function --------------------------------------------------------*/
+
+ /*! \brief Decode an A-law sample to a linear value.
+ \param alaw The A-law sample to decode.
+ \return The linear value.
+ */
+ static __inline__ int16_t alaw_to_linear(uint8_t alaw)
+ {
+ int i;
+ int seg;
+
+ alaw ^= ALAW_AMI_MASK;
+ i = ((alaw & 0x0F) << 4);
+ seg = (((int) alaw & 0x70) >> 4);
+ if (seg)
+ i = (i + 0x108) << (seg - 1);
+ else
+ i += 8;
+ return (int16_t) ((alaw & 0x80) ? i : -i);
+ }
+ /*- End of function --------------------------------------------------------*/
+
+ /*! \brief Transcode from A-law to u-law, using the procedure defined in G.711.
+ \param alaw The A-law sample to transcode.
+ \return The best matching u-law value.
+ */
+ uint8_t alaw_to_ulaw(uint8_t alaw);
+
+ /*! \brief Transcode from u-law to A-law, using the procedure defined in G.711.
+ \param alaw The u-law sample to transcode.
+ \return The best matching A-law value.
+ */
+ uint8_t ulaw_to_alaw(uint8_t ulaw);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/*- End of file ------------------------------------------------------------*/
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/include/hashtable.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/include/hashtable.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/hashtable.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,235 @@
+/* Copyright (C) 2002 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_CWC22_H__
+#define __HASHTABLE_CWC22_H__
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+#endif
+#include "freetdm.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct hashtable;
+struct hashtable_iterator;
+
+/* Example of use:
+ *
+ * struct hashtable *h;
+ * struct some_key *k;
+ * struct some_value *v;
+ *
+ * static unsigned int hash_from_key_fn( void *k );
+ * static int keys_equal_fn ( void *key1, void *key2 );
+ *
+ * h = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
+ * k = (struct some_key *) malloc(sizeof(struct some_key));
+ * v = (struct some_value *) malloc(sizeof(struct some_value));
+ *
+ * (initialise k and v to suitable values)
+ *
+ * if (! hashtable_insert(h,k,v) )
+ * { exit(-1); }
+ *
+ * if (NULL == (found = hashtable_search(h,k) ))
+ * { printf("not found!"); }
+ *
+ * if (NULL == (found = hashtable_remove(h,k) ))
+ * { printf("Not found\n"); }
+ *
+ */
+
+/* Macros may be used to define type-safe(r) hashtable access functions, with
+ * methods specialized to take known key and value types as parameters.
+ *
+ * Example:
+ *
+ * Insert this at the start of your file:
+ *
+ * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value);
+ *
+ * This defines the functions 'insert_some', 'search_some' and 'remove_some'.
+ * These operate just like hashtable_insert etc., with the same parameters,
+ * but their function signatures have 'struct some_key *' rather than
+ * 'void *', and hence can generate compile time errors if your program is
+ * supplying incorrect data as a key (and similarly for value).
+ *
+ * Note that the hash and key equality functions passed to create_hashtable
+ * still take 'void *' parameters instead of 'some key *'. This shouldn't be
+ * a difficult issue as they're only defined and passed once, and the other
+ * functions will ensure that only valid keys are supplied to them.
+ *
+ * The cost for this checking is increased code size and runtime overhead
+ * - if performance is important, it may be worth switching back to the
+ * unsafe methods once your program has been debugged with the safe methods.
+ * This just requires switching to some simple alternative defines - eg:
+ * #define insert_some hashtable_insert
+ *
+ */
+
+/*****************************************************************************
+ * create_hashtable
+
+ * @name create_hashtable
+ * @param minsize minimum initial size of hashtable
+ * @param hashfunction function for hashing keys
+ * @param key_eq_fn function for determining key equality
+ * @return newly created hashtable or NULL on failure
+ */
+
+FT_DECLARE(struct hashtable *)
+create_hashtable(unsigned int minsize,
+ unsigned int (*hashfunction) (void*),
+ int (*key_eq_fn) (void*,void*));
+
+/*****************************************************************************
+ * hashtable_insert
+
+ * @name hashtable_insert
+ * @param h the hashtable to insert into
+ * @param k the key - hashtable claims ownership and will free on removal
+ * @param v the value - does not claim ownership
+ * @return non-zero for successful insertion
+ *
+ * This function will cause the table to expand if the insertion would take
+ * the ratio of entries to table size over the maximum load factor.
+ *
+ * This function does not check for repeated insertions with a duplicate key.
+ * The value returned when using a duplicate key is undefined -- when
+ * the hashtable changes size, the order of retrieval of duplicate key
+ * entries is reversed.
+ * If in doubt, remove before insert.
+ */
+
+
+typedef enum {
+ HASHTABLE_FLAG_NONE = 0,
+ HASHTABLE_FLAG_FREE_KEY = (1 << 0),
+ HASHTABLE_FLAG_FREE_VALUE = (1 << 1)
+} hashtable_flag_t;
+
+FT_DECLARE(int)
+hashtable_insert(struct hashtable *h, void *k, void *v, hashtable_flag_t flags);
+
+#define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \
+ int fnname (struct hashtable *h, keytype *k, valuetype *v) \
+ { \
+ return hashtable_insert(h,k,v); \
+ }
+
+/*****************************************************************************
+ * hashtable_search
+
+ * @name hashtable_search
+ * @param h the hashtable to search
+ * @param k the key to search for - does not claim ownership
+ * @return the value associated with the key, or NULL if none found
+ */
+
+FT_DECLARE(void *)
+hashtable_search(struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
+ valuetype * fnname (struct hashtable *h, keytype *k) \
+ { \
+ return (valuetype *) (hashtable_search(h,k)); \
+ }
+
+/*****************************************************************************
+ * hashtable_remove
+
+ * @name hashtable_remove
+ * @param h the hashtable to remove the item from
+ * @param k the key to search for - does not claim ownership
+ * @return the value associated with the key, or NULL if none found
+ */
+
+FT_DECLARE(void *) /* returns value */
+hashtable_remove(struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
+ valuetype * fnname (struct hashtable *h, keytype *k) \
+ { \
+ return (valuetype *) (hashtable_remove(h,k)); \
+ }
+
+
+/*****************************************************************************
+ * hashtable_count
+
+ * @name hashtable_count
+ * @param h the hashtable
+ * @return the number of items stored in the hashtable
+ */
+FT_DECLARE(unsigned int)
+hashtable_count(struct hashtable *h);
+
+
+/*****************************************************************************
+ * hashtable_destroy
+
+ * @name hashtable_destroy
+ * @param h the hashtable
+ * @param free_values whether to call 'free' on the remaining values
+ */
+
+FT_DECLARE(void)
+hashtable_destroy(struct hashtable *h);
+
+FT_DECLARE(struct hashtable_iterator*) hashtable_first(struct hashtable *h);
+FT_DECLARE(struct hashtable_iterator*) hashtable_next(struct hashtable_iterator *i);
+FT_DECLARE(void) hashtable_this(struct hashtable_iterator *i, const void **key, int *klen, void **val);
+
+#ifdef __cplusplus
+} /* extern C */
+#endif
+
+#endif /* __HASHTABLE_CWC22_H__ */
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * 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.
+ */
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/include/hashtable_itr.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/include/hashtable_itr.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/hashtable_itr.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,134 @@
+/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_ITR_CWC22__
+#define __HASHTABLE_ITR_CWC22__
+#include "hashtable.h"
+#include "hashtable_private.h" /* needed to enable inlining */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*****************************************************************************/
+/* This struct is only concrete here to allow the inlining of two of the
+ * accessor functions. */
+struct hashtable_itr
+{
+ struct hashtable *h;
+ struct entry *e;
+ struct entry *parent;
+ unsigned int index;
+};
+
+
+/*****************************************************************************/
+/* hashtable_iterator
+ */
+
+struct hashtable_itr *
+hashtable_iterator(struct hashtable *h);
+
+/*****************************************************************************/
+/* hashtable_iterator_key
+ * - return the value of the (key,value) pair at the current position */
+extern __inline__ void *
+hashtable_iterator_key(struct hashtable_itr *i);
+
+extern __inline__ void *
+hashtable_iterator_key(struct hashtable_itr *i)
+{
+ return i->e->k;
+}
+
+/*****************************************************************************/
+/* value - return the value of the (key,value) pair at the current position */
+
+extern __inline__ void *
+hashtable_iterator_value(struct hashtable_itr *i);
+
+extern __inline__ void *
+hashtable_iterator_value(struct hashtable_itr *i)
+{
+ return i->e->v;
+}
+
+/*****************************************************************************/
+/* advance - advance the iterator to the next element
+ * returns zero if advanced to end of table */
+
+int
+hashtable_iterator_advance(struct hashtable_itr *itr);
+
+/*****************************************************************************/
+/* remove - remove current element and advance the iterator to the next element
+ * NB: if you need the value to free it, read it before
+ * removing. ie: beware memory leaks!
+ * returns zero if advanced to end of table */
+
+int
+hashtable_iterator_remove(struct hashtable_itr *itr);
+
+/*****************************************************************************/
+/* search - overwrite the supplied iterator, to point to the entry
+ * matching the supplied key.
+ h points to the hashtable to be searched.
+ * returns zero if not found. */
+int
+hashtable_iterator_search(struct hashtable_itr *itr,
+ struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \
+ int fnname (struct hashtable_itr *i, struct hashtable *h, keytype *k) \
+ { \
+ return (hashtable_iterator_search(i,h,k)); \
+ }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __HASHTABLE_ITR_CWC22__*/
+
+/*
+ * Copyright (c) 2002, 2004, Christopher Clark
+ * 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.
+ */
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/freetdm/src/include/hashtable_private.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/include/hashtable_private.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/hashtable_private.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,110 @@
+/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_PRIVATE_CWC22_H__
+#define __HASHTABLE_PRIVATE_CWC22_H__
+
+#include "hashtable.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*****************************************************************************/
+
+struct entry
+{
+ void *k, *v;
+ unsigned int h;
+ hashtable_flag_t flags;
+ struct entry *next;
+};
+
+struct hashtable_iterator {
+ unsigned int pos;
+ struct entry *e;
+ struct hashtable *h;
+};
+
+struct hashtable {
+ unsigned int tablelength;
+ struct entry **table;
+ unsigned int entrycount;
+ unsigned int loadlimit;
+ unsigned int primeindex;
+ unsigned int (*hashfn) (void *k);
+ int (*eqfn) (void *k1, void *k2);
+ struct hashtable_iterator iterator;
+};
+
+/*****************************************************************************/
+unsigned int
+hash(struct hashtable *h, void *k);
+
+/*****************************************************************************/
+/* indexFor */
+static __inline__ unsigned int
+indexFor(unsigned int tablelength, unsigned int hashvalue) {
+ return (hashvalue % tablelength);
+}
+
+/* Only works if tablelength == 2^N */
+/*static inline unsigned int
+ indexFor(unsigned int tablelength, unsigned int hashvalue)
+ {
+ return (hashvalue & (tablelength - 1u));
+ }
+*/
+
+/*****************************************************************************/
+#define freekey(X) free(X)
+/*define freekey(X) ; */
+
+#ifdef __cplusplus
+}
+#endif
+
+/*****************************************************************************/
+
+#endif /* __HASHTABLE_PRIVATE_CWC22_H__*/
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * 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.
+ */
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/include/libteletone.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/include/libteletone.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/libteletone.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,161 @@
+/*
+ * libteletone
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mftilla 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.mftilla.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 libteletone
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * libteletone.h -- Tone Generator/Detector
+ *
+ *
+ *
+ * Exception:
+ * The author hereby grants the use of this source code under the
+ * following license if and only if the source code is distributed
+ * as part of the freetdm library. Any use or distribution of this
+ * source code outside the scope of the freetdm library will nullify the
+ * following license and reinact the MPL 1.1 as stated above.
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+#ifndef LIBTELETONE_H
+#define LIBTELETONE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <math.h>
+
+#define TELETONE_MAX_DTMF_DIGITS 128
+#define TELETONE_MAX_TONES 18
+#define TELETONE_TONE_RANGE 127
+
+typedef double teletone_process_t;
+
+/*! \file libteletone.h
+ \brief Top level include file
+
+ This file should be included by applications using the library
+*/
+
+/*! \brief An abstraction to store a tone mapping */
+typedef struct {
+ /*! An array of tone frequencies */
+ teletone_process_t freqs[TELETONE_MAX_TONES];
+} teletone_tone_map_t;
+
+#if !defined(M_PI)
+/* C99 systems may not define M_PI */
+#define M_PI 3.14159265358979323846264338327
+#endif
+
+#ifdef _MSC_VER
+typedef __int16 int16_t;
+#endif
+
+#if (_MSC_VER >= 1400) // VC8+
+#define teletone_assert(expr) assert(expr);__analysis_assume( expr )
+#else
+#define teletone_assert(expr) assert(expr)
+#endif
+
+#ifdef _MSC_VER
+#if defined(TT_DECLARE_STATIC)
+#define TELETONE_API(type) type __stdcall
+#define TELETONE_API_NONSTD(type) type __cdecl
+#define TELETONE_API_DATA
+#elif defined(TELETONE_EXPORTS)
+#define TELETONE_API(type) __declspec(dllexport) type __stdcall
+#define TELETONE_API_NONSTD(type) __declspec(dllexport) type __cdecl
+#define TELETONE_API_DATA __declspec(dllexport)
+#else
+#define TELETONE_API(type) __declspec(dllimport) type __stdcall
+#define TELETONE_API_NONSTD(type) __declspec(dllimport) type __cdecl
+#define TELETONE_API_DATA __declspec(dllimport)
+#endif
+#else
+#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(HAVE_VISIBILITY)
+#define TELETONE_API(type) __attribute__((visibility("default"))) type
+#define TELETONE_API_NONSTD(type) __attribute__((visibility("default"))) type
+#define TELETONE_API_DATA __attribute__((visibility("default")))
+#else
+#define TELETONE_API(type) type
+#define TELETONE_API_NONSTD(type) type
+#define TELETONE_API_DATA
+#endif
+#endif
+
+#include <libteletone_generate.h>
+#include <libteletone_detect.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/include/libteletone_detect.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/include/libteletone_detect.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/libteletone_detect.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,240 @@
+/*
+ * libteletone
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * libteletone_detect.c Tone Detection Code
+ *
+ * Exception:
+ * The author hereby grants the use of this source code under the
+ * following license if and only if the source code is distributed
+ * as part of the freetdm library. Any use or distribution of this
+ * source code outside the scope of the freetdm library will nullify the
+ * following license and reinact the MPL 1.1 as stated above.
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ *
+ *********************************************************************************
+ *
+ * Derived from tone_detect.h - General telephony tone detection, and specific
+ * detection of DTMF.
+ *
+ * Copyright (C) 2001 Steve Underwood <steveu@coppice.org>
+ *
+ * Despite my general liking of the GPL, I place this code in the
+ * public domain for the benefit of all mankind - even the slimy
+ * ones who might try to proprietize my work and use it to my
+ * detriment.
+ *
+ *
+ */
+
+#ifndef LIBTELETONE_DETECT_H
+#define LIBTELETONE_DETECT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <libteletone.h>
+
+ /*! \file libteletone_detect.h
+ \brief Tone Detection Routines
+
+ This module is responsible for tone detection specifics
+ */
+
+#ifndef FALSE
+#define FALSE 0
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+#endif
+
+ /* Basic DTMF specs:
+ *
+ * Minimum tone on = 40ms
+ * Minimum tone off = 50ms
+ * Maximum digit rate = 10 per second
+ * Normal twist <= 8dB accepted
+ * Reverse twist <= 4dB accepted
+ * S/N >= 15dB will detect OK
+ * Attenuation <= 26dB will detect OK
+ * Frequency tolerance +- 1.5% will detect, +-3.5% will reject
+ */
+
+#define DTMF_THRESHOLD 8.0e7
+#define DTMF_NORMAL_TWIST 6.3 /* 8dB */
+#define DTMF_REVERSE_TWIST 2.5 /* 4dB */
+#define DTMF_RELATIVE_PEAK_ROW 6.3 /* 8dB */
+#define DTMF_RELATIVE_PEAK_COL 6.3 /* 8dB */
+#define DTMF_2ND_HARMONIC_ROW 2.5 /* 4dB */
+#define DTMF_2ND_HARMONIC_COL 63.1 /* 18dB */
+#define GRID_FACTOR 4
+#define BLOCK_LEN 102
+#define M_TWO_PI 2.0*M_PI
+
+ /*! \brief A continer for the elements of a Goertzel Algorithm (The names are from his formula) */
+ typedef struct {
+ float v2;
+ float v3;
+ double fac;
+ } teletone_goertzel_state_t;
+
+ /*! \brief A container for a DTMF detection state.*/
+ typedef struct {
+ int hit1;
+ int hit2;
+ int hit3;
+ int hit4;
+ int mhit;
+
+ teletone_goertzel_state_t row_out[GRID_FACTOR];
+ teletone_goertzel_state_t col_out[GRID_FACTOR];
+ teletone_goertzel_state_t row_out2nd[GRID_FACTOR];
+ teletone_goertzel_state_t col_out2nd[GRID_FACTOR];
+ float energy;
+
+ int current_sample;
+ char digits[TELETONE_MAX_DTMF_DIGITS + 1];
+ int current_digits;
+ int detected_digits;
+ int lost_digits;
+ int digit_hits[16];
+ } teletone_dtmf_detect_state_t;
+
+ /*! \brief An abstraction to store the coefficient of a tone frequency */
+ typedef struct {
+ float fac;
+ } teletone_detection_descriptor_t;
+
+ /*! \brief A container for a single multi-tone detection
+ TELETONE_MAX_TONES dictates the maximum simultaneous tones that can be present
+ in a multi-tone representation.
+ */
+ typedef struct {
+ int sample_rate;
+
+ teletone_detection_descriptor_t tdd[TELETONE_MAX_TONES];
+ teletone_goertzel_state_t gs[TELETONE_MAX_TONES];
+ teletone_goertzel_state_t gs2[TELETONE_MAX_TONES];
+ int tone_count;
+
+ float energy;
+ int current_sample;
+
+ int min_samples;
+ int total_samples;
+
+ int positives;
+ int negatives;
+ int hits;
+
+ int positive_factor;
+ int negative_factor;
+ int hit_factor;
+
+ } teletone_multi_tone_t;
+
+
+ /*!
+ \brief Initilize a multi-frequency tone detector
+ \param mt the multi-frequency tone descriptor
+ \param map a representation of the multi-frequency tone
+ */
+TELETONE_API(void) teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map);
+
+ /*!
+ \brief Check a sample buffer for the presence of the mulit-frequency tone described by mt
+ \param mt the multi-frequency tone descriptor
+ \param sample_buffer an array aof 16 bit signed linear samples
+ \param samples the number of samples present in sample_buffer
+ \return true when the tone was detected or false when it is not
+ */
+TELETONE_API(int) teletone_multi_tone_detect (teletone_multi_tone_t *mt,
+ int16_t sample_buffer[],
+ int samples);
+
+ /*!
+ \brief Initilize a DTMF detection state object
+ \param dtmf_detect_state the DTMF detection state to initilize
+ \param sample_rate the desired sample rate
+ */
+TELETONE_API(void) teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate);
+
+ /*!
+ \brief Check a sample buffer for the presence of DTMF digits
+ \param dtmf_detect_state the detection state object to check
+ \param sample_buffer an array aof 16 bit signed linear samples
+ \param samples the number of samples present in sample_buffer
+ \return true when DTMF was detected or false when it is not
+ */
+TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
+ int16_t sample_buffer[],
+ int samples);
+ /*!
+ \brief retrieve any collected digits into a string buffer
+ \param dtmf_detect_state the detection state object to check
+ \param buf the string buffer to write to
+ \param max the maximum length of buf
+ \return the number of characters written to buf
+ */
+TELETONE_API(int) teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state,
+ char *buf,
+ int max);
+
+ /*!
+ \brief Step through the Goertzel Algorithm for each sample in a buffer
+ \param goertzel_state the goertzel state to step the samples through
+ \param sample_buffer an array aof 16 bit signed linear samples
+ \param samples the number of samples present in sample_buffer
+ */
+TELETONE_API(void) teletone_goertzel_update(teletone_goertzel_state_t *goertzel_state,
+ int16_t sample_buffer[],
+ int samples);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/include/libteletone_generate.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/include/libteletone_generate.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/libteletone_generate.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,281 @@
+/*
+ * libteletone
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+#ifndef LIBTELETONE_GENERATE_H
+#define LIBTELETONE_GENERATE_H
+#ifdef __cplusplus
+extern "C" {
+#ifdef _doh
+}
+#endif
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+#ifndef __inline__
+#define __inline__ inline
+#endif
+#endif
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+
+typedef unsigned __int64 uint64_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int8 uint8_t;
+typedef __int64 int64_t;
+typedef __int32 int32_t;
+typedef __int16 int16_t;
+typedef __int8 int8_t;
+#else
+#include <stdint.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <math.h>
+#if !defined(powf) && !defined(_WIN64)
+extern float powf (float, float);
+#endif
+#include <string.h>
+#include <errno.h>
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+#include <assert.h>
+#include <stdarg.h>
+#include <libteletone.h>
+
+#define TELETONE_VOL_DB_MAX 0
+#define TELETONE_VOL_DB_MIN -63
+#define MAX_PHASE_TONES 4
+
+struct teletone_dds_state {
+ uint32_t phase_rate[MAX_PHASE_TONES];
+ uint32_t scale_factor;
+ uint32_t phase_accumulator;
+ teletone_process_t tx_level;
+};
+typedef struct teletone_dds_state teletone_dds_state_t;
+
+#define SINE_TABLE_MAX 128
+#define SINE_TABLE_LEN (SINE_TABLE_MAX - 1)
+#define MAX_PHASE_ACCUMULATOR 0x10000 * 0x10000
+/* 3.14 == the max power on ulaw (alaw is 3.17) */
+/* 3.02 represents twice the power */
+#define DBM0_MAX_POWER (3.14f + 3.02f)
+
+TELETONE_API_DATA extern int16_t TELETONE_SINES[SINE_TABLE_MAX];
+
+static __inline__ int32_t teletone_dds_phase_rate(teletone_process_t tone, uint32_t rate)
+{
+ return (int32_t) ((tone * MAX_PHASE_ACCUMULATOR) / rate);
+}
+
+static __inline__ int16_t teletone_dds_state_modulate_sample(teletone_dds_state_t *dds, uint32_t pindex)
+{
+ int32_t bitmask = dds->phase_accumulator, sine_index = (bitmask >>= 23) & SINE_TABLE_LEN;
+ int16_t sample;
+
+ if (pindex >= MAX_PHASE_TONES) {
+ pindex = 0;
+ }
+
+ if (bitmask & SINE_TABLE_MAX) {
+ sine_index = SINE_TABLE_LEN - sine_index;
+ }
+
+ sample = TELETONE_SINES[sine_index];
+
+ if (bitmask & (SINE_TABLE_MAX * 2)) {
+ sample *= -1;
+ }
+
+ dds->phase_accumulator += dds->phase_rate[pindex];
+ return (int16_t) (sample * dds->scale_factor >> 15);
+}
+
+static __inline__ void teletone_dds_state_set_tx_level(teletone_dds_state_t *dds, float tx_level)
+{
+ dds->scale_factor = (int) (powf(10.0f, (tx_level - DBM0_MAX_POWER) / 20.0f) * (32767.0f * 1.414214f));
+ dds->tx_level = tx_level;
+}
+
+static __inline__ void teletone_dds_state_reset_accum(teletone_dds_state_t *dds)
+{
+ dds->phase_accumulator = 0;
+}
+
+static __inline__ int teletone_dds_state_set_tone(teletone_dds_state_t *dds, teletone_process_t tone, uint32_t rate, uint32_t pindex)
+{
+ if (pindex < MAX_PHASE_TONES) {
+ dds->phase_rate[pindex] = teletone_dds_phase_rate(tone, rate);
+ return 0;
+ }
+
+ return -1;
+}
+
+
+
+/*! \file libteletone_generate.h
+ \brief Tone Generation Routines
+
+ This module is responsible for tone generation specifics
+*/
+
+typedef int16_t teletone_audio_t;
+struct teletone_generation_session;
+typedef int (*tone_handler)(struct teletone_generation_session *ts, teletone_tone_map_t *map);
+
+/*! \brief An abstraction to store a tone generation session */
+struct teletone_generation_session {
+ /*! An array of tone mappings to character mappings */
+ teletone_tone_map_t TONES[TELETONE_TONE_RANGE];
+ /*! The number of channels the output audio should be in */
+ int channels;
+ /*! The Rate in hz of the output audio */
+ int rate;
+ /*! The duration (in samples) of the output audio */
+ int duration;
+ /*! The duration of silence to append after the initial audio is generated */
+ int wait;
+ /*! The duration (in samples) of the output audio (takes prescedence over actual duration value) */
+ int tmp_duration;
+ /*! The duration of silence to append after the initial audio is generated (takes prescedence over actual wait value)*/
+ int tmp_wait;
+ /*! Number of loops to repeat a single instruction*/
+ int loops;
+ /*! Number of loops to repeat the entire set of instructions*/
+ int LOOPS;
+ /*! Number to mutiply total samples by to determine when to begin ascent or decent e.g. 0=beginning 4=(last 25%) */
+ float decay_factor;
+ /*! Direction to perform volume increase/decrease 1/-1*/
+ int decay_direction;
+ /*! Number of samples between increase/decrease of volume */
+ int decay_step;
+ /*! Volume factor of the tone */
+ float volume;
+ /*! Debug on/off */
+ int debug;
+ /*! FILE stream to write debug data to */
+ FILE *debug_stream;
+ /*! Extra user data to attach to the session*/
+ void *user_data;
+ /*! Buffer for storing sample data (dynamic) */
+ teletone_audio_t *buffer;
+ /*! Size of the buffer */
+ int datalen;
+ /*! In-Use size of the buffer */
+ int samples;
+ /*! Callback function called during generation */
+ int dynamic;
+ tone_handler handler;
+};
+
+typedef struct teletone_generation_session teletone_generation_session_t;
+
+
+/*!
+ \brief Assign a set of tones to a tone_session indexed by a paticular index/character
+ \param ts the tone generation session
+ \param index the index to map the tone to
+ \param ... up to TELETONE_MAX_TONES frequencies terminated by 0.0
+ \return 0
+*/
+TELETONE_API(int) teletone_set_tone(teletone_generation_session_t *ts, int index, ...);
+
+/*!
+ \brief Assign a set of tones to a single tone map
+ \param map the map to assign the tones to
+ \param ... up to TELETONE_MAX_TONES frequencies terminated by 0.0
+ \return 0
+*/
+TELETONE_API(int) teletone_set_map(teletone_tone_map_t *map, ...);
+
+/*!
+ \brief Initilize a tone generation session
+ \param ts the tone generation session to initilize
+ \param buflen the size of the buffer(in samples) to dynamically allocate
+ \param handler a callback function to execute when a tone generation instruction is complete
+ \param user_data optional user data to send
+ \return 0
+*/
+TELETONE_API(int) teletone_init_session(teletone_generation_session_t *ts, int buflen, tone_handler handler, void *user_data);
+
+/*!
+ \brief Free the buffer allocated by a tone generation session
+ \param ts the tone generation session to destroy
+ \return 0
+*/
+TELETONE_API(int) teletone_destroy_session(teletone_generation_session_t *ts);
+
+/*!
+ \brief Execute a single tone generation instruction
+ \param ts the tone generation session to consult for parameters
+ \param map the tone mapping to use for the frequencies
+ \return 0
+*/
+TELETONE_API(int) teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *map);
+
+/*!
+ \brief Execute a tone generation script and call callbacks after each instruction
+ \param ts the tone generation session to execute on
+ \param cmd the script to execute
+ \return 0
+*/
+TELETONE_API(int) teletone_run(teletone_generation_session_t *ts, const char *cmd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/include/sangoma_tdm_api.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/include/sangoma_tdm_api.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/sangoma_tdm_api.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,321 @@
+/*****************************************************************************
+ * sangoma_tdm_api.h Sangoma TDM API Portability functions
+ *
+ * Author(s): Anthony Minessale II <anthmct@yahoo.com>
+ * Nenad Corbic <ncorbic@sangoma.com>
+ * Michael Jerris <mike@jerris.com>
+ * David Rokhvarg <davidr@sangoma.com>
+ *
+ * Copyright: (c) 2006 Nenad Corbic <ncorbic@sangoma.com>
+ * Anthony Minessale II
+ * (c) 1984-2007 Sangoma Technologies Inc.
+ *
+ * ============================================================================
+ */
+
+#ifndef _SANGOMA_TDM_API_H
+#define _SANGOMA_TDM_API_H
+
+/* This entire block of defines and includes from this line, through #define FNAME_LEN probably dont belong here */
+/* most of them probably belong in wanpipe_defines.h, then each header file listed included below properly included */
+/* in the header files that depend on them, leaving only the include for wanpipe_tdm_api.h left in this file or */
+/* possibly integrating the rest of this file diretly into wanpipe_tdm_api.h */
+#ifndef __WINDOWS__
+#if defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)
+#define __WINDOWS__
+#endif /* defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32) */
+#endif /* ndef __WINDOWS__ */
+
+#if defined(__WINDOWS__)
+#if defined(_MSC_VER)
+/* disable some warnings caused by wanpipe headers that will need to be fixed in those headers */
+#pragma warning(disable:4201 4214)
+
+/* sang_api.h(74) : warning C4201: nonstandard extension used : nameless struct/union */
+
+/* wanpipe_defines.h(219) : warning C4214: nonstandard extension used : bit field types other than int */
+/* wanpipe_defines.h(220) : warning C4214: nonstandard extension used : bit field types other than int */
+/* this will break for any compilers that are strict ansi or strict c99 */
+
+/* The following definition for that struct should resolve this warning and work for 32 and 64 bit */
+#if 0
+struct iphdr {
+
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned ihl:4,
+ version:4;
+#elif defined (__BIG_ENDIAN_BITFIELD)
+ unsigned version:4,
+ ihl:4;
+#else
+# error "unknown byteorder!"
+#endif
+ unsigned tos:8;
+ unsigned tot_len:16;
+ unsigned id:16;
+ unsigned frag_off:16;
+ __u8 ttl;
+ __u8 protocol;
+ __u16 check;
+ __u32 saddr;
+ __u32 daddr;
+ /*The options start here. */
+};
+#endif /* #if 0 */
+
+#define __inline__ __inline
+#endif /* defined(_MSC_VER) */
+#include <windows.h>
+/* do we like the name WP_INVALID_SOCKET or should it be changed? */
+#define WP_INVALID_SOCKET INVALID_HANDLE_VALUE
+#else /* defined(__WINDOWS__) */
+#define WP_INVALID_SOCKET -1
+#include <stropts.h>
+#include <poll.h>
+#include <sys/socket.h>
+#endif
+
+#include <wanpipe_defines.h>
+#include <wanpipe_cfg.h>
+#include <wanpipe_tdm_api.h>
+#include <sdla_te1_pmc.h>
+#ifdef __WINDOWS__
+#include <sang_status_defines.h>
+#include <sang_api.h>
+#endif
+#include <sdla_aft_te1.h>
+
+#define FNAME_LEN 50
+
+
+#if defined(__WINDOWS__)
+/* This might be broken on windows, as POLL_EVENT_TELEPHONY seems to be commented out in sang_api.h.. it should be added to POLLPRI */
+#define POLLPRI (POLL_EVENT_LINK_STATE | POLL_EVENT_LINK_CONNECT | POLL_EVENT_LINK_DISCONNECT)
+#endif
+
+/* return -1 for error, 0 for timeout or 1 for success. *flags is set to the poll evetns POLLIN | POLLOUT | POLLPRI based on the result of the poll */
+/* on windows we actually have POLLPRI defined with several events, so we could theoretically poll */
+/* for specific events. Is there any way to do this on *nix as well? */
+
+/* a cross platform way to poll on an actual pollset (span and/or list of spans) will probably also be needed for analog */
+/* so we can have one analong handler thread that will deal with all the idle analog channels for events */
+/* the alternative would be for the driver to provide one socket for all of the oob events for all analog channels */
+static __inline__ int tdmv_api_wait_socket(sng_fd_t fd, int timeout, int *flags)
+{
+#if defined(__WINDOWS__)
+ DWORD ln;
+ API_POLL_STRUCT api_poll;
+
+ memset(&api_poll, 0x00, sizeof(API_POLL_STRUCT));
+
+ api_poll.user_flags_bitmap = *flags;
+ api_poll.timeout = timeout;
+
+ if (!DeviceIoControl(
+ fd,
+ IoctlApiPoll,
+ (LPVOID)NULL,
+ 0L,
+ (LPVOID)&api_poll,
+ sizeof(API_POLL_STRUCT),
+ (LPDWORD)(&ln),
+ (LPOVERLAPPED)NULL)) {
+ return -1;
+ }
+
+ *flags = 0;
+
+ switch(api_poll.operation_status)
+ {
+ case SANG_STATUS_RX_DATA_AVAILABLE:
+ break;
+
+ case SANG_STATUS_RX_DATA_TIMEOUT:
+ return 0;
+
+ default:
+ return -1;
+ }
+
+ if (api_poll.poll_events_bitmap == 0){
+ return -1;
+ }
+
+ if (api_poll.poll_events_bitmap & POLL_EVENT_TIMEOUT) {
+ return 0;
+ }
+
+ *flags = api_poll.poll_events_bitmap;
+
+ return 1;
+#else
+ struct pollfd pfds[1];
+ int res;
+
+ memset(&pfds[0], 0, sizeof(pfds[0]));
+ pfds[0].fd = fd;
+ pfds[0].events = *flags;
+ res = poll(pfds, 1, timeout);
+ *flags = 0;
+
+ if (pfds[0].revents & POLLERR) {
+ res = -1;
+ }
+
+ if (res > 0) {
+ *flags = pfds[0].revents;
+ }
+
+ return res;
+#endif
+}
+
+/* on windows right now, there is no way to specify if we want to read events here or not, we allways get them here */
+/* we need some what to select if we are reading regular tdm msgs or events */
+/* need to either have 2 functions, 1 for events, 1 for regural read, or a flag on this function to choose */
+/* 2 functions preferred. Need implementation for the event function for both nix and windows that is threadsafe */
+static __inline__ int tdmv_api_readmsg_tdm(sng_fd_t fd, void *hdrbuf, int hdrlen, void *databuf, int datalen)
+{
+ /* What do we need to do here to avoid having to do all */
+ /* the memcpy's on windows and still maintain api compat with nix */
+ int rx_len=0;
+#if defined(__WINDOWS__)
+ static RX_DATA_STRUCT rx_data;
+ api_header_t *pri;
+ wp_tdm_api_rx_hdr_t *tdm_api_rx_hdr;
+ wp_tdm_api_rx_hdr_t *user_buf = (wp_tdm_api_rx_hdr_t*)hdrbuf;
+ DWORD ln;
+
+ if (hdrlen != sizeof(wp_tdm_api_rx_hdr_t)){
+ return -1;
+ }
+
+ if (!DeviceIoControl(
+ fd,
+ IoctlReadCommand,
+ (LPVOID)NULL,
+ 0L,
+ (LPVOID)&rx_data,
+ sizeof(RX_DATA_STRUCT),
+ (LPDWORD)(&ln),
+ (LPOVERLAPPED)NULL
+ )){
+ return -1;
+ }
+
+ pri = &rx_data.api_header;
+ tdm_api_rx_hdr = (wp_tdm_api_rx_hdr_t*)rx_data.data;
+
+ user_buf->wp_tdm_api_event_type = pri->operation_status;
+
+ switch(pri->operation_status)
+ {
+ case SANG_STATUS_RX_DATA_AVAILABLE:
+ if (pri->data_length > datalen){
+ break;
+ }
+ memcpy(databuf, rx_data.data, pri->data_length);
+ rx_len = pri->data_length;
+ break;
+
+ default:
+ break;
+ }
+
+#else
+ struct msghdr msg;
+ struct iovec iov[2];
+
+ memset(&msg,0,sizeof(struct msghdr));
+
+ iov[0].iov_len=hdrlen;
+ iov[0].iov_base=hdrbuf;
+
+ iov[1].iov_len=datalen;
+ iov[1].iov_base=databuf;
+
+ msg.msg_iovlen=2;
+ msg.msg_iov=iov;
+
+ rx_len = read(fd,&msg,datalen+hdrlen);
+
+ if (rx_len <= sizeof(wp_tdm_api_rx_hdr_t)){
+ return -EINVAL;
+ }
+
+ rx_len-=sizeof(wp_tdm_api_rx_hdr_t);
+#endif
+ return rx_len;
+}
+
+static __inline__ int tdmv_api_writemsg_tdm(sng_fd_t fd, void *hdrbuf, int hdrlen, void *databuf, unsigned short datalen)
+{
+ /* What do we need to do here to avoid having to do all */
+ /* the memcpy's on windows and still maintain api compat with nix */
+ int bsent = 0;
+#if defined(__WINDOWS__)
+ static TX_DATA_STRUCT local_tx_data;
+ api_header_t *pri;
+ DWORD ln;
+
+ /* Are these really not needed or used??? What about for nix?? */
+ (void)hdrbuf;
+ (void)hdrlen;
+
+ pri = &local_tx_data.api_header;
+
+ pri->data_length = datalen;
+ memcpy(local_tx_data.data, databuf, pri->data_length);
+
+ if (!DeviceIoControl(
+ fd,
+ IoctlWriteCommand,
+ (LPVOID)&local_tx_data,
+ (ULONG)sizeof(TX_DATA_STRUCT),
+ (LPVOID)&local_tx_data,
+ sizeof(TX_DATA_STRUCT),
+ (LPDWORD)(&ln),
+ (LPOVERLAPPED)NULL
+ )){
+ return -1;
+ }
+
+ if (local_tx_data.api_header.operation_status == SANG_STATUS_SUCCESS) {
+ bsent = datalen;
+ }
+#else
+ struct msghdr msg;
+ struct iovec iov[2];
+
+ memset(&msg,0,sizeof(struct msghdr));
+
+ iov[0].iov_len = hdrlen;
+ iov[0].iov_base = hdrbuf;
+
+ iov[1].iov_len = datalen;
+ iov[1].iov_base = databuf;
+
+ msg.msg_iovlen = 2;
+ msg.msg_iov = iov;
+
+ bsent = write(fd, &msg, datalen + hdrlen);
+ if (bsent > 0){
+ bsent -= sizeof(wp_tdm_api_tx_hdr_t);
+ }
+#endif
+ return bsent;
+}
+
+#endif /* _SANGOMA_TDM_API_H */
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/freetdm/src/include/uart.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/include/uart.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/uart.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,83 @@
+/*
+ * uart.h
+ *
+ * Copyright (c) 2005 Robert Krten. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * This module contains the manifest constants and declarations for
+ * the UART module.
+ *
+ * 2005 06 19 R. Krten created
+*/
+
+#ifndef __UART_H__
+#define __UART_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*bytehandler_func_t) (void *, int);
+typedef void (*bithandler_func_t) (void *, int);
+
+
+typedef struct dsp_uart_attr_s
+{
+ bytehandler_func_t bytehandler; /* byte handler */
+ void *bytehandler_arg; /* arbitrary ID passed to bytehandler as first argument */
+} dsp_uart_attr_t;
+
+typedef struct
+{
+ dsp_uart_attr_t attr;
+ int have_start; /* wait for start bit to show up */
+ int data; /* data buffer */
+ int nbits; /* number of bits accumulated so far */
+} dsp_uart_handle_t;
+
+/*
+ * Function prototypes
+ *
+ * General calling order is:
+ * a) create the attributes structure (dsp_uart_attr_init)
+ * b) initialize fields in the attributes structure (dsp_uart_attr_set_*)
+ * c) create a Bell-202 handle (dsp_uart_create)
+ * d) feed bits through dsp_uart_bit_handler
+*/
+
+void dsp_uart_attr_init(dsp_uart_attr_t *attributes);
+
+bytehandler_func_t dsp_uart_attr_get_bytehandler(dsp_uart_attr_t *attributes, void **bytehandler_arg);
+void dsp_uart_attr_set_bytehandler(dsp_uart_attr_t *attributes, bytehandler_func_t bytehandler, void *bytehandler_arg);
+
+dsp_uart_handle_t * dsp_uart_create(dsp_uart_attr_t *attributes);
+void dsp_uart_destroy(dsp_uart_handle_t **handle);
+
+void dsp_uart_bit_handler(void *handle, int bit);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
Added: freeswitch/trunk/libs/freetdm/src/isdn/5ESSStateNT.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/5ESSStateNT.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/5ESSStateNT.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,132 @@
+/*****************************************************************************
+
+ FileName: 5ESSStateNT.c
+
+ Contents: AT&T 5ESS ISDN State Engine for NT (Network Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ Copyright (c) 2007, Michael S. Collins, All rights reserved.
+ email:mcollins@fcnetwork.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "5ESS.h"
+
+/*****************************************************************************
+ Function: ATT5ESSCreateNT
+
+ Description: Will create the AT&T 5ESS ISDN NT as a Dialect in the stack. The first
+ bulk set up the message handlers, the second bulk the IE
+ encoders/coders, and the last bulk set up the state table.
+
+ Parameters: i Dialect index
+*****************************************************************************/
+void ATT5ESSCreateNT(L3UCHAR i)
+{
+ Q931SetMesProc(Q931mes_ALERTING, i, Q931ProcAlertingNT, Q931Umes_Alerting, Q931Pmes_Alerting);
+ Q931SetMesProc(Q931mes_CALL_PROCEEDING, i, Q931ProcCallProceedingNT, Q931Umes_CallProceeding, Q931Pmes_CallProceeding);
+ Q931SetMesProc(Q931mes_CONNECT, i, Q931ProcConnectNT, Q931Umes_Connect, Q931Pmes_Connect);
+ Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i, Q931ProcConnectAckNT, Q931Umes_ConnectAck, Q931Pmes_ConnectAck);
+ Q931SetMesProc(Q931mes_PROGRESS, i, Q931ProcProgressNT, Q931Umes_Progress, Q931Pmes_Progress);
+ Q931SetMesProc(Q931mes_SETUP, i, Q931ProcSetupNT, Q931Umes_Setup, Q931Pmes_Setup);
+ Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE, i, Q931ProcSetupAckNT, Q931Umes_SetupAck, Q931Pmes_SetupAck);
+ Q931SetMesProc(Q931mes_RESUME, i, Q931ProcResumeNT, Q931Umes_Resume, Q931Pmes_Resume);
+ Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE, i, Q931ProcResumeAckNT, Q931Umes_ResumeAck, Q931Pmes_ResumeAck);
+ Q931SetMesProc(Q931mes_RESUME_REJECT, i, Q931ProcResumeRejectNT, Q931Umes_ResumeReject, Q931Pmes_ResumeReject);
+ Q931SetMesProc(Q931mes_SUSPEND, i, Q931ProcSuspendNT, Q931Umes_Suspend, Q931Pmes_Suspend);
+ Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE, i, Q931ProcSuspendAckNT, Q931Umes_SuspendAck, Q931Pmes_SuspendAck);
+ Q931SetMesProc(Q931mes_SUSPEND_REJECT, i, Q931ProcSuspendRejectNT, Q931Umes_SuspendReject, Q931Pmes_SuspendReject);
+ Q931SetMesProc(Q931mes_USER_INFORMATION, i, Q931ProcUserInformationNT, Q931Umes_UserInformation, Q931Pmes_UserInformation);
+ Q931SetMesProc(Q931mes_DISCONNECT, i, Q931ProcDisconnectNT, Q931Umes_Disconnect, Q931Pmes_Disconnect);
+ Q931SetMesProc(Q931mes_RELEASE, i, Q931ProcReleaseNT, Q931Umes_Release, Q931Pmes_Release);
+ Q931SetMesProc(Q931mes_RELEASE_COMPLETE, i, Q931ProcReleaseCompleteNT, Q931Umes_ReleaseComplete, Q931Pmes_ReleaseComplete);
+ Q931SetMesProc(Q931mes_RESTART, i, Q931ProcRestartNT, Q931Umes_Restart, Q931Pmes_Restart);
+ Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE, i, Q931ProcRestartAckNT, Q931Umes_RestartAck, Q931Pmes_RestartAck);
+ Q931SetMesProc(Q931mes_CONGESTION_CONTROL, i, Q931ProcCongestionControlNT, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+ Q931SetMesProc(Q931mes_INFORMATION, i, Q931ProcInformationNT, Q931Umes_Information, Q931Pmes_Information);
+ Q931SetMesProc(Q931mes_NOTIFY, i, Q931ProcNotifyNT, Q931Umes_Notify, Q931Pmes_Notify);
+ Q931SetMesProc(Q931mes_STATUS, i, Q931ProcStatusNT, Q931Umes_Status, Q931Pmes_Status);
+ Q931SetMesProc(Q931mes_STATUS_ENQUIRY, i, Q931ProcStatusEnquiryNT, Q931Umes_StatusEnquiry, Q931Pmes_StatusEnquiry);
+ Q931SetMesProc(Q931mes_SEGMENT, i, Q931ProcSegmentNT, Q931Umes_Segment, Q931Pmes_Segment);
+
+ Q931SetMesProc(Q932mes_FACILITY, i, Q932ProcFacilityNT, Q932Umes_Facility, Q932Pmes_Facility);
+ Q931SetMesProc(Q932mes_HOLD, i, Q932ProcHoldNT, Q932Umes_Hold, Q932Pmes_Hold);
+ Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE, i, Q932ProcHoldAckNT, Q932Umes_HoldAck, Q932Pmes_HoldAck);
+ Q931SetMesProc(Q932mes_HOLD_REJECT, i, Q932ProcHoldRejectNT, Q932Umes_HoldReject, Q932Pmes_HoldReject);
+ Q931SetMesProc(Q932mes_REGISTER, i, Q932ProcRegisterNT, Q932Umes_Register, Q932Pmes_Register);
+ Q931SetMesProc(Q932mes_RETRIEVE, i, Q932ProcRetrieveNT, Q932Umes_Retrieve, Q932Pmes_Retrieve);
+ Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckNT, Q932Umes_RetrieveAck, Q932Pmes_RetrieveAck);
+ Q931SetMesProc(Q932mes_RETRIEVE_REJECT, i, Q932ProcRetrieveRejectNT, Q932Umes_RetrieveReject, Q932Pmes_RetrieveReject);
+
+ /* Set up the IE encoder/decoder handle table.*/
+ Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE, i, Q931Pie_Segment, Q931Uie_Segment);
+ Q931SetIEProc(Q931ie_BEARER_CAPABILITY, i, Q931Pie_BearerCap, Q931Uie_BearerCap);
+ Q931SetIEProc(Q931ie_CAUSE, i, Q931Pie_Cause, Q931Uie_Cause);
+ Q931SetIEProc(Q931ie_CALL_IDENTITY, i, Q931Pie_CallID, Q931Uie_CallID);
+ Q931SetIEProc(Q931ie_CALL_STATE, i, Q931Pie_CallState, Q931Uie_CallState);
+ Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION, i, Q931Pie_ChanID, Q931Uie_ChanID);
+ Q931SetIEProc(Q931ie_PROGRESS_INDICATOR, i, Q931Pie_ProgInd, Q931Uie_ProgInd);
+ Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES, i, Q931Pie_NetFac, Q931Uie_NetFac);
+ Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR, i, Q931Pie_NotifInd, Q931Uie_NotifInd);
+ Q931SetIEProc(Q931ie_DISPLAY, i, Q931Pie_Display, Q931Uie_Display);
+ Q931SetIEProc(Q931ie_DATETIME, i, Q931Pie_DateTime, Q931Uie_DateTime);
+ Q931SetIEProc(Q931ie_KEYPAD_FACILITY, i, Q931Pie_KeypadFac, Q931Uie_KeypadFac);
+ Q931SetIEProc(Q931ie_SIGNAL, i, Q931Pie_Signal, Q931Uie_Signal);
+ Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER, i, Q931Pie_CallingNum, Q931Uie_CallingNum);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS, i, Q931Pie_CallingSub, Q931Uie_CallingSub);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER, i, Q931Pie_CalledNum, Q931Uie_CalledNum);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS, i, Q931Pie_CalledSub, Q931Uie_CalledSub);
+ Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_RESTART_INDICATOR, i, Q931Pie_RestartInd, Q931Uie_RestartInd);
+ Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY, i, Q931Pie_LLComp, Q931Uie_LLComp);
+ Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY, i, Q931Pie_HLComp, Q931Uie_HLComp);
+ Q931SetIEProc(Q931ie_USER_USER, i, Q931Pie_UserUser, Q931Uie_UserUser);
+ Q931SetIEProc(Q931ie_GENERIC_DIGITS, i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+ Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_FACILITY, i, Q931Pie_Generic, Q931Uie_Generic);
+
+ /* The following define a state machine. The point is that the Message */
+ /* procs can when search this to find out if the message/state */
+ /* combination is legale. If not, the proc for unexpected message apply.*/
+
+ /* TODO define state table here */
+}
Added: freeswitch/trunk/libs/freetdm/src/isdn/5ESSStateTE.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/5ESSStateTE.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/5ESSStateTE.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,291 @@
+/*****************************************************************************
+
+ FileName: 5ESSStateTE.c
+
+ Contents: AT&T 5ESS ISDN State Engine for TE (User Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ This reference implementation uses a process per message,
+ meaning that each message must check call states. This
+ is easier for dialect maintenance as each message proc
+ can be replaced individually. A new TE variant only
+ need to copy the Q931CreateTE and replace those procs or
+ need to override.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ Copyright (c) 2007, Michael S. Collins, All rights reserved.
+ email:mcollins@fcnetwork.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "5ESS.h"
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+ Function: ATT5ESSCreateTE
+
+ Description: Will create the AT&T 5ESS TE as a Dialect in the stack. The first
+ bulk set up the message handlers, the second bulk the IE
+ encoders/coders, and the last bulk set up the state table.
+
+ Parameters: i Dialect index
+*****************************************************************************/
+void ATT5ESSCreateTE(L3UCHAR i)
+{
+ Q931SetMesProc(Q931mes_ALERTING, i, Q931ProcAlertingTE, Q931Umes_Alerting, Q931Pmes_Alerting);
+ Q931SetMesProc(Q931mes_CALL_PROCEEDING, i, Q931ProcCallProceedingTE, Q931Umes_CallProceeding, Q931Pmes_CallProceeding);
+ Q931SetMesProc(Q931mes_CONNECT, i, ATT5ESSProc0x07TE, ATT5ESSUmes_0x07, ATT5ESSPmes_0x07);
+ Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i, ATT5ESSProc0x0fTE, ATT5ESSUmes_0x0f, ATT5ESSPmes_0x0f);
+ Q931SetMesProc(Q931mes_PROGRESS, i, Q931ProcProgressTE, Q931Umes_Progress, Q931Pmes_Progress);
+ Q931SetMesProc(Q931mes_SETUP, i, Q931ProcSetupTE, ATT5ESSUmes_Setup, ATT5ESSPmes_Setup);
+ Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE, i, Q931ProcSetupAckTE, Q931Umes_SetupAck, Q931Pmes_SetupAck);
+ Q931SetMesProc(Q931mes_RESUME, i, Q931ProcResumeTE, Q931Umes_Resume, Q931Pmes_Resume);
+ Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE, i, Q931ProcResumeAckTE, Q931Umes_ResumeAck, Q931Pmes_ResumeAck);
+ Q931SetMesProc(Q931mes_RESUME_REJECT, i, Q931ProcResumeRejectTE, Q931Umes_ResumeReject, Q931Pmes_ResumeReject);
+ Q931SetMesProc(Q931mes_SUSPEND, i, Q931ProcSuspendTE, Q931Umes_Suspend, Q931Pmes_Suspend);
+ Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE, i, Q931ProcSuspendAckTE, Q931Umes_SuspendAck, Q931Pmes_SuspendAck);
+ Q931SetMesProc(Q931mes_SUSPEND_REJECT, i, Q931ProcSuspendRejectTE, Q931Umes_SuspendReject, Q931Pmes_SuspendReject);
+ Q931SetMesProc(Q931mes_USER_INFORMATION, i, Q931ProcUserInformationTE, Q931Umes_UserInformation, Q931Pmes_UserInformation);
+ Q931SetMesProc(Q931mes_DISCONNECT, i, Q931ProcDisconnectTE, Q931Umes_Disconnect, Q931Pmes_Disconnect);
+ Q931SetMesProc(Q931mes_RELEASE, i, Q931ProcReleaseTE, Q931Umes_Release, Q931Pmes_Release);
+ Q931SetMesProc(Q931mes_RELEASE_COMPLETE, i, Q931ProcReleaseCompleteTE, Q931Umes_ReleaseComplete, Q931Pmes_ReleaseComplete);
+ Q931SetMesProc(Q931mes_RESTART, i, Q931ProcRestartTE, Q931Umes_Restart, Q931Pmes_Restart);
+ Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE, i, Q931ProcRestartAckTE, Q931Umes_RestartAck, Q931Pmes_RestartAck);
+ Q931SetMesProc(Q931mes_CONGESTION_CONTROL, i, Q931ProcCongestionControlTE, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+ Q931SetMesProc(Q931mes_INFORMATION, i, Q931ProcInformationTE, Q931Umes_Information, Q931Pmes_Information);
+ Q931SetMesProc(Q931mes_NOTIFY, i, Q931ProcNotifyTE, Q931Umes_Notify, Q931Pmes_Notify);
+ Q931SetMesProc(Q931mes_STATUS, i, Q931ProcStatusTE, Q931Umes_Status, Q931Pmes_Status);
+ Q931SetMesProc(Q931mes_STATUS_ENQUIRY, i, Q931ProcStatusEnquiryTE, Q931Umes_StatusEnquiry, Q931Pmes_StatusEnquiry);
+ Q931SetMesProc(Q931mes_SEGMENT, i, Q931ProcSegmentTE, Q931Umes_Segment, Q931Pmes_Segment);
+
+ Q931SetMesProc(Q932mes_FACILITY, i, Q932ProcFacilityTE, Q932Umes_Facility, Q932Pmes_Facility);
+ Q931SetMesProc(Q932mes_HOLD, i, Q932ProcHoldTE, Q932Umes_Hold, Q932Pmes_Hold);
+ Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE, i, Q932ProcHoldAckTE, Q932Umes_HoldAck, Q932Pmes_HoldAck);
+ Q931SetMesProc(Q932mes_HOLD_REJECT, i, Q932ProcHoldRejectTE, Q932Umes_HoldReject, Q932Pmes_HoldReject);
+ Q931SetMesProc(Q932mes_REGISTER, i, Q932ProcRegisterTE, Q932Umes_Register, Q932Pmes_Register);
+ Q931SetMesProc(Q932mes_RETRIEVE, i, Q932ProcRetrieveTE, Q932Umes_Retrieve, Q932Pmes_Retrieve);
+ Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckTE, Q932Umes_RetrieveAck, Q932Pmes_RetrieveAck);
+ Q931SetMesProc(Q932mes_RETRIEVE_REJECT, i, Q932ProcRetrieveRejectTE, Q932Umes_RetrieveReject, Q932Pmes_RetrieveReject);
+
+ /* Set up the IE encoder/decoder handle table.*/
+ Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE, i, Q931Pie_Segment, Q931Uie_Segment);
+ Q931SetIEProc(Q931ie_BEARER_CAPABILITY, i, Q931Pie_BearerCap, Q931Uie_BearerCap);
+ Q931SetIEProc(Q931ie_CAUSE, i, Q931Pie_Cause, Q931Uie_Cause);
+ Q931SetIEProc(Q931ie_CALL_IDENTITY, i, Q931Pie_CallID, Q931Uie_CallID);
+ Q931SetIEProc(Q931ie_CALL_STATE, i, Q931Pie_CallState, Q931Uie_CallState);
+ Q931SetIEProc(Q931ie_CHANGE_STATUS, i, Q931Pie_ChangeStatus, Q931Uie_ChangeStatus);
+ Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION, i, Q931Pie_ChanID, Q931Uie_ChanID);
+ Q931SetIEProc(Q931ie_PROGRESS_INDICATOR, i, Q931Pie_ProgInd, Q931Uie_ProgInd);
+ Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES, i, Q931Pie_NetFac, Q931Uie_NetFac);
+ Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR, i, Q931Pie_NotifInd, Q931Uie_NotifInd);
+ Q931SetIEProc(Q931ie_DISPLAY, i, Q931Pie_Display, Q931Uie_Display);
+ Q931SetIEProc(Q931ie_DATETIME, i, Q931Pie_DateTime, Q931Uie_DateTime);
+ Q931SetIEProc(Q931ie_KEYPAD_FACILITY, i, Q931Pie_KeypadFac, Q931Uie_KeypadFac);
+ Q931SetIEProc(Q931ie_SIGNAL, i, Q931Pie_Signal, Q931Uie_Signal);
+ Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER, i, Q931Pie_CallingNum, Q931Uie_CallingNum);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS, i, Q931Pie_CallingSub, Q931Uie_CallingSub);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER, i, Q931Pie_CalledNum, Q931Uie_CalledNum);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS, i, Q931Pie_CalledSub, Q931Uie_CalledSub);
+ Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_RESTART_INDICATOR, i, Q931Pie_RestartInd, Q931Uie_RestartInd);
+ Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY, i, Q931Pie_LLComp, Q931Uie_LLComp);
+ Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY, i, Q931Pie_HLComp, Q931Uie_HLComp);
+ Q931SetIEProc(Q931ie_USER_USER, i, Q931Pie_UserUser, Q931Uie_UserUser);
+ Q931SetIEProc(Q931ie_GENERIC_DIGITS, i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+ Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_FACILITY, i, Q931Pie_Generic, Q931Uie_Generic);
+
+ /* The following define a state machine. The point is that the Message */
+ /* procs can when search this to find out if the message/state */
+ /* combination is legale. If not, the proc for unexpected message apply.*/
+
+ /* State 0 Idle */
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RESUME, 2);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP, 2);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_STATUS, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE_COMPLETE, 4);
+
+ /* State 1 Call Initiating */
+ Q931AddStateEntry(i, Q931_U1, Q931mes_DISCONNECT, 2);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_SETUP_ACKNOWLEDGE, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_RELEASE_COMPLETE, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_CALL_PROCEEDING, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_CONNECT, 4);
+
+ /* State 2 Overlap Sending */
+ Q931AddStateEntry(i, Q931_U2, Q931mes_INFORMATION, 2);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_CALL_PROCEEDING, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_PROGRESS, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_CONNECT, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_RELEASE, 2);
+
+ /* State 3 Outgoing Call Proceeding */
+ Q931AddStateEntry(i, Q931_U3, Q931mes_PROGRESS, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_CONNECT, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_RELEASE, 2);
+
+ /* State 4 Call Delivered */
+ Q931AddStateEntry(i, Q931_U4, Q931mes_CONNECT, 4);
+
+ /* State 6 Call Precent */
+ Q931AddStateEntry(i, Q931_U6, Q931mes_INFORMATION, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_ALERTING, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_CALL_PROCEEDING, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_CONNECT, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE_COMPLETE, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_DISCONNECT, 4);
+
+ /* State 7 Call Received */
+ Q931AddStateEntry(i, Q931_U7, Q931mes_CONNECT, 2);
+
+ /* State 8 Connect request */
+ Q931AddStateEntry(i, Q931_U8, Q931mes_CONNECT_ACKNOWLEDGE, 4);
+
+ /* State 9 Incoming Call Proceeding */
+ Q931AddStateEntry(i, Q931_U9, Q931mes_CONNECT, 2);
+ Q931AddStateEntry(i, Q931_U9, Q931mes_ALERTING, 2);
+ Q931AddStateEntry(i, Q931_U9, Q931mes_PROGRESS, 2);
+
+ /* State 10 Active */
+ Q931AddStateEntry(i, Q931_U10, Q931mes_SUSPEND, 2);
+ Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY, 4);
+ Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY, 2);
+
+ /* State 11 Disconnect Request */
+ Q931AddStateEntry(i, Q931_U11, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U11, Q931mes_DISCONNECT, 4);
+ Q931AddStateEntry(i, Q931_U11, Q931mes_NOTIFY, 4);
+
+ /* State 12 Disconnect Ind */
+ Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 2);
+
+ /* State 15 Suspend Request */
+ Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_ACKNOWLEDGE, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_REJECT, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_DISCONNECT, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_RELEASE, 4);
+
+/* TODO
+ Q931AddStateEntry(i, Q931_U17,
+ Q931AddStateEntry(i, Q931_U19,
+ Q931AddStateEntry(i, Q931_U25,
+*/
+}
+
+/*****************************************************************************
+
+ Function: ATT5ESSProc0x0fTE
+
+*****************************************************************************/
+L3INT ATT5ESSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ if (pMes->ProtDisc == 8) {
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ }
+ if (iFrom == 4) {
+ /* TODO Add proc here*/
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom ==2) {
+ /* TODO Add proc here*/
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+
+ if (pMes->ProtDisc == 3 && pTrunk->autoServiceAck) {
+ printf("autoServiceAck is on, responding to Service Req from network...\n");
+ Q931AckService(pTrunk, buf);
+ }
+ }
+ return ret;
+
+}
+
+/*****************************************************************************
+
+ Function: ATT5ESSProc0x07TE
+
+*****************************************************************************/
+L3INT ATT5ESSProc0x07TE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ if (pMes->ProtDisc == 8) {
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ }
+ if (iFrom == 4) {
+ /* TODO Add proc here*/
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here*/
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+
+}
Added: freeswitch/trunk/libs/freetdm/src/isdn/5ESSmes.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/5ESSmes.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/5ESSmes.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,361 @@
+/*****************************************************************************
+
+ FileName: 5ESSmes.c
+
+ Contents: Pack/Unpack functions. These functions will unpack a 5ESS ISDN
+ message from the bit packed original format into structs
+ that contains variables sized by the user. It will also pack
+ the struct back into a Q.931 message as required.
+
+ See 5ESS.h for description.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ Copyright (c) 2007, Michael S. Collins, All rights reserved.
+ email:mcollins@fcnetwork.com
+
+ 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 Case Labs, Ltd 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.
+
+*****************************************************************************/
+
+#include "5ESS.h"
+
+/*****************************************************************************
+
+ Function: ATT5ESSUmes_Setup
+
+*****************************************************************************/
+L3INT ATT5ESSUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT ir = 0;
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+ L3UCHAR last_codeset = 0, codeset = 0;
+ L3UCHAR shift_nolock = 1;
+
+ while (IOff < Size) {
+
+ if (shift_nolock) {
+ codeset = last_codeset;
+ }
+
+ if ((IBuf[IOff] & 0xF0) == Q931ie_SHIFT) {
+ shift_nolock = (IBuf[IOff] & 0x08);
+ if (shift_nolock) {
+ last_codeset = codeset;
+ }
+ codeset = ((IBuf[IOff] & 0x07));
+ IOff++;
+ }
+
+ if (codeset == 0) {
+ switch (IBuf[IOff])
+ {
+ case Q931ie_SENDING_COMPLETE:
+ case Q931ie_BEARER_CAPABILITY:
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_NETWORK_SPECIFIC_FACILITIES:
+ case Q931ie_DISPLAY:
+ case Q931ie_DATETIME:
+ case Q931ie_KEYPAD_FACILITY:
+ case Q931ie_SIGNAL:
+ case Q931ie_CALLING_PARTY_NUMBER:
+ case Q931ie_CALLING_PARTY_SUBADDRESS:
+ case Q931ie_CALLED_PARTY_NUMBER:
+ case Q931ie_CALLED_PARTY_SUBADDRESS:
+ case Q931ie_TRANSIT_NETWORK_SELECTION:
+ case Q931ie_LOW_LAYER_COMPATIBILITY:
+ case Q931ie_HIGH_LAYER_COMPATIBILITY:
+ case Q931ie_FACILITY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ case Q931ie_REPEAT_INDICATOR:
+ if (ir < 2) {
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ ir++;
+ } else {
+ return Q931E_ILLEGAL_IE;
+ }
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ } else if (codeset == 6) {
+ switch (IBuf[IOff])
+ {
+ case Q931ie_GENERIC_DIGITS:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ } else if (codeset == 7) {
+ switch (IBuf[IOff])
+ {
+ case Q931ie_DISPLAY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ } else {
+ return Q931E_ILLEGAL_IE;
+ }
+ }
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: ATT5ESSPmes_Setup
+
+ Decription: Pack a Q931mes_Generic into a real Q.931 message. The user will
+ set up a SETUP message and issue this to the stack where it
+ is processed by Q931ProcSetup that processes and validates
+ it before it actually sends it out. This function is called
+ to compute the real Q.931 message.
+
+ Parameters: IBuf[IN] Ptr to un-packed struct
+ ISize[IN] Size of input buffer (unpacked message).
+ OBuf[OUT] Ptr to packed 'octet' wise message.
+ OSize[OUT] Size of packed message.
+
+ Called By: Q931ProcSetup
+
+*****************************************************************************/
+L3INT ATT5ESSPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3INT rc = Q931E_NO_ERROR;
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Sending Complete */
+ if (Q931IsIEPresent(pMes->SendComplete)) {
+ OBuf[Octet++] = (L3UCHAR)(pMes->SendComplete & 0x00ff);
+ }
+
+ /* Repeat Indicator */
+ if (Q931IsIEPresent(pMes->RepeatInd)) {
+ OBuf[Octet++] = (L3UCHAR)(pMes->RepeatInd & 0x00ff);
+ }
+
+ /* Bearer capability */
+ if (Q931IsIEPresent(pMes->BearerCap)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ } else {
+ rc = Q931E_BEARERCAP;
+ }
+
+ /* Channel Identification */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Network specific facilities */
+ if (Q931IsIEPresent(pMes->NetFac)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_NETWORK_SPECIFIC_FACILITIES](pTrunk, Q931GetIEPtr(pMes->NetFac,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Date/Time */
+ if (Q931IsIEPresent(pMes->DateTime)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Keypad Facility */
+ if (Q931IsIEPresent(pMes->KeypadFac)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Calling Party Number */
+ if (Q931IsIEPresent(pMes->CallingNum)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CallingNum,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Calling Party Subaddress */
+ if (Q931IsIEPresent(pMes->CallingSub)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CallingSub,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Called Party number */
+ if (Q931IsIEPresent(pMes->CalledNum)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Called party subaddress */
+ if (Q931IsIEPresent(pMes->CalledSub)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CalledSub,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Transit network selection */
+ if (Q931IsIEPresent(pMes->TransNetSel)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_TRANSIT_NETWORK_SELECTION](pTrunk, Q931GetIEPtr(pMes->TransNetSel,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Repeat Indicator */
+ if (Q931IsIEPresent(pMes->LLRepeatInd)) {
+ rc = Q931E_UNKNOWN_IE;/* TODO */
+ }
+
+ /* Low Layer Compatibility */
+ if (Q931IsIEPresent(pMes->LLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* High Layer Compatibility */
+ if (Q931IsIEPresent(pMes->HLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+
+/*****************************************************************************
+
+ Function: ATT5ESSUmes_0x0f
+
+*****************************************************************************/
+L3INT ATT5ESSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ if (mes->ProtDisc == 8) {
+ return Q931Umes_ConnectAck(pTrunk, IBuf, mes, IOff, Size);
+ }
+
+ if (mes->ProtDisc == 3) {
+ return Q931Umes_Service(pTrunk, IBuf, mes, IOff, Size);
+ }
+
+ return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+ Function: ATT5ESSPmes_0x0f
+
+*****************************************************************************/
+L3INT ATT5ESSPmes_0x0f(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *mes = (Q931mes_Generic *)IBuf;
+
+ if (mes->ProtDisc == 8) {
+ return Q931Pmes_ConnectAck(pTrunk, IBuf, ISize, OBuf, OSize);
+ }
+
+ if (mes->ProtDisc == 3) {
+ return Q931Pmes_Service(pTrunk, IBuf, ISize, OBuf, OSize);
+ }
+
+ return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+ Function: ATT5ESSUmes_0x07
+
+*****************************************************************************/
+L3INT ATT5ESSUmes_0x07(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ if (mes->ProtDisc == 8) {
+ return Q931Umes_Connect(pTrunk, IBuf, mes, IOff, Size);
+ }
+
+ if (mes->ProtDisc == 3) {
+ return Q931Umes_ServiceAck(pTrunk, IBuf, mes, IOff, Size);
+ }
+
+ return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+ Function: ATT5ESSPmes_0x07
+
+*****************************************************************************/
+L3INT ATT5ESSPmes_0x07(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *mes = (Q931mes_Generic *)IBuf;
+
+ if (mes->ProtDisc == 8) {
+ return Q931Pmes_Connect(pTrunk, IBuf, ISize, OBuf, OSize);
+ }
+
+ if (mes->ProtDisc == 3) {
+ return Q931Pmes_ServiceAck(pTrunk, IBuf, ISize, OBuf, OSize);
+ }
+
+ return Q931E_UNKNOWN_MESSAGE;
+}
Added: freeswitch/trunk/libs/freetdm/src/isdn/DMSStateNT.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/DMSStateNT.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/DMSStateNT.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,126 @@
+/*****************************************************************************
+
+ FileName: DMSStateNT.c
+
+ Contents: DMS-100 ISDN State Engine for NT (Network Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "DMS.h"
+
+/*****************************************************************************
+ Function: DMSCreateNT
+
+ Description: Will create the National ISDN NT as a Dialect in the stack. The first
+ bulk set up the message handlers, the second bulk the IE
+ encoders/coders, and the last bulk set up the state table.
+
+ Parameters: i Dialect index
+*****************************************************************************/
+void DMSCreateNT(L3UCHAR i)
+{
+ Q931SetMesProc(Q931mes_ALERTING, i, Q931ProcAlertingNT, Q931Umes_Alerting, Q931Pmes_Alerting);
+ Q931SetMesProc(Q931mes_CALL_PROCEEDING, i, Q931ProcCallProceedingNT, Q931Umes_CallProceeding, Q931Pmes_CallProceeding);
+ Q931SetMesProc(Q931mes_CONNECT, i, Q931ProcConnectNT, Q931Umes_Connect, Q931Pmes_Connect);
+ Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i, Q931ProcConnectAckNT, Q931Umes_ConnectAck, Q931Pmes_ConnectAck);
+ Q931SetMesProc(Q931mes_PROGRESS, i, Q931ProcProgressNT, Q931Umes_Progress, Q931Pmes_Progress);
+ Q931SetMesProc(Q931mes_SETUP, i, Q931ProcSetupNT, DMSUmes_Setup, DMSPmes_Setup);
+ Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE, i, Q931ProcSetupAckNT, Q931Umes_SetupAck, Q931Pmes_SetupAck);
+ Q931SetMesProc(Q931mes_RESUME, i, Q931ProcResumeNT, Q931Umes_Resume, Q931Pmes_Resume);
+ Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE, i, Q931ProcResumeAckNT, Q931Umes_ResumeAck, Q931Pmes_ResumeAck);
+ Q931SetMesProc(Q931mes_RESUME_REJECT, i, Q931ProcResumeRejectNT, Q931Umes_ResumeReject, Q931Pmes_ResumeReject);
+ Q931SetMesProc(Q931mes_SUSPEND, i, Q931ProcSuspendNT, Q931Umes_Suspend, Q931Pmes_Suspend);
+ Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE, i, Q931ProcSuspendAckNT, Q931Umes_SuspendAck, Q931Pmes_SuspendAck);
+ Q931SetMesProc(Q931mes_SUSPEND_REJECT, i, Q931ProcSuspendRejectNT, Q931Umes_SuspendReject, Q931Pmes_SuspendReject);
+ Q931SetMesProc(Q931mes_USER_INFORMATION, i, Q931ProcUserInformationNT, Q931Umes_UserInformation, Q931Pmes_UserInformation);
+ Q931SetMesProc(Q931mes_DISCONNECT, i, Q931ProcDisconnectNT, Q931Umes_Disconnect, Q931Pmes_Disconnect);
+ Q931SetMesProc(Q931mes_RELEASE, i, Q931ProcReleaseNT, Q931Umes_Release, Q931Pmes_Release);
+ Q931SetMesProc(Q931mes_RELEASE_COMPLETE, i, Q931ProcReleaseCompleteNT, Q931Umes_ReleaseComplete, Q931Pmes_ReleaseComplete);
+ Q931SetMesProc(Q931mes_RESTART, i, Q931ProcRestartNT, Q931Umes_Restart, Q931Pmes_Restart);
+ Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE, i, Q931ProcRestartAckNT, Q931Umes_RestartAck, Q931Pmes_RestartAck);
+ Q931SetMesProc(Q931mes_CONGESTION_CONTROL, i, Q931ProcCongestionControlNT, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+ Q931SetMesProc(Q931mes_INFORMATION, i, Q931ProcInformationNT, Q931Umes_Information, Q931Pmes_Information);
+ Q931SetMesProc(Q931mes_NOTIFY, i, Q931ProcNotifyNT, Q931Umes_Notify, Q931Pmes_Notify);
+ Q931SetMesProc(Q931mes_STATUS, i, Q931ProcStatusNT, Q931Umes_Status, Q931Pmes_Status);
+ Q931SetMesProc(Q931mes_STATUS_ENQUIRY, i, Q931ProcStatusEnquiryNT, Q931Umes_StatusEnquiry, Q931Pmes_StatusEnquiry);
+ Q931SetMesProc(Q931mes_SEGMENT, i, Q931ProcSegmentNT, Q931Umes_Segment, Q931Pmes_Segment);
+
+ Q931SetMesProc(Q932mes_FACILITY, i, Q932ProcFacilityNT, Q932Umes_Facility, Q932Pmes_Facility);
+ Q931SetMesProc(Q932mes_HOLD, i, Q932ProcHoldNT, Q932Umes_Hold, Q932Pmes_Hold);
+ Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE, i, Q932ProcHoldAckNT, Q932Umes_HoldAck, Q932Pmes_HoldAck);
+ Q931SetMesProc(Q932mes_HOLD_REJECT, i, Q932ProcHoldRejectNT, Q932Umes_HoldReject, Q932Pmes_HoldReject);
+ Q931SetMesProc(Q932mes_REGISTER, i, Q932ProcRegisterNT, Q932Umes_Register, Q932Pmes_Register);
+ Q931SetMesProc(Q932mes_RETRIEVE, i, Q932ProcRetrieveNT, Q932Umes_Retrieve, Q932Pmes_Retrieve);
+ Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckNT, Q932Umes_RetrieveAck, Q932Pmes_RetrieveAck);
+ Q931SetMesProc(Q932mes_RETRIEVE_REJECT, i, Q932ProcRetrieveRejectNT, Q932Umes_RetrieveReject, Q932Pmes_RetrieveReject);
+
+ /* Set up the IE encoder/decoder handle table.*/
+ Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE, i, Q931Pie_Segment, Q931Uie_Segment);
+ Q931SetIEProc(Q931ie_BEARER_CAPABILITY, i, Q931Pie_BearerCap, Q931Uie_BearerCap);
+ Q931SetIEProc(Q931ie_CAUSE, i, Q931Pie_Cause, Q931Uie_Cause);
+ Q931SetIEProc(Q931ie_CALL_IDENTITY, i, Q931Pie_CallID, Q931Uie_CallID);
+ Q931SetIEProc(Q931ie_CALL_STATE, i, Q931Pie_CallState, Q931Uie_CallState);
+ Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION, i, Q931Pie_ChanID, Q931Uie_ChanID);
+ Q931SetIEProc(Q931ie_PROGRESS_INDICATOR, i, Q931Pie_ProgInd, Q931Uie_ProgInd);
+ Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES, i, Q931Pie_NetFac, Q931Uie_NetFac);
+ Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR, i, Q931Pie_NotifInd, Q931Uie_NotifInd);
+ Q931SetIEProc(Q931ie_DISPLAY, i, Q931Pie_Display, Q931Uie_Display);
+ Q931SetIEProc(Q931ie_DATETIME, i, Q931Pie_DateTime, Q931Uie_DateTime);
+ Q931SetIEProc(Q931ie_KEYPAD_FACILITY, i, Q931Pie_KeypadFac, Q931Uie_KeypadFac);
+ Q931SetIEProc(Q931ie_SIGNAL, i, Q931Pie_Signal, Q931Uie_Signal);
+ Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER, i, Q931Pie_CallingNum, Q931Uie_CallingNum);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS, i, Q931Pie_CallingSub, Q931Uie_CallingSub);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER, i, Q931Pie_CalledNum, Q931Uie_CalledNum);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS, i, Q931Pie_CalledSub, Q931Uie_CalledSub);
+ Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_RESTART_INDICATOR, i, Q931Pie_RestartInd, Q931Uie_RestartInd);
+ Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY, i, Q931Pie_LLComp, Q931Uie_LLComp);
+ Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY, i, Q931Pie_HLComp, Q931Uie_HLComp);
+ Q931SetIEProc(Q931ie_USER_USER, i, Q931Pie_UserUser, Q931Uie_UserUser);
+ Q931SetIEProc(Q931ie_GENERIC_DIGITS, i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+ /* The following define a state machine. The point is that the Message */
+ /* procs can when search this to find out if the message/state */
+ /* combination is legale. If not, the proc for unexpected message apply.*/
+
+ /* TODO define state table here */
+}
Added: freeswitch/trunk/libs/freetdm/src/isdn/DMSStateTE.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/DMSStateTE.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/DMSStateTE.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,284 @@
+/*****************************************************************************
+
+ FileName: DMSStateTE.c
+
+ Contents: DMS-100 ISDN State Engine for TE (User Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ This reference implementation uses a process per message,
+ meaning that each message must check call states. This
+ is easier for dialect maintenance as each message proc
+ can be replaced individually. A new TE variant only
+ need to copy the Q931CreateTE and replace those procs or
+ need to override.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "DMS.h"
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+ Function: DMSCreateTE
+
+ Description: Will create the National TE as a Dialect in the stack. The first
+ bulk set up the message handlers, the second bulk the IE
+ encoders/coders, and the last bulk set up the state table.
+
+ Parameters: i Dialect index
+*****************************************************************************/
+void DMSCreateTE(L3UCHAR i)
+{
+ Q931SetMesProc(Q931mes_ALERTING, i, Q931ProcAlertingTE, Q931Umes_Alerting, Q931Pmes_Alerting);
+ Q931SetMesProc(Q931mes_CALL_PROCEEDING, i, Q931ProcCallProceedingTE, Q931Umes_CallProceeding, Q931Pmes_CallProceeding);
+ Q931SetMesProc(Q931mes_CONNECT, i, DMSProc0x07TE, DMSUmes_0x07, DMSPmes_0x07);
+ Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i, DMSProc0x0fTE, DMSUmes_0x0f, DMSPmes_0x0f);
+ Q931SetMesProc(Q931mes_PROGRESS, i, Q931ProcProgressTE, Q931Umes_Progress, Q931Pmes_Progress);
+ Q931SetMesProc(Q931mes_SETUP, i, Q931ProcSetupTE, DMSUmes_Setup, DMSPmes_Setup);
+ Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE, i, Q931ProcSetupAckTE, Q931Umes_SetupAck, Q931Pmes_SetupAck);
+ Q931SetMesProc(Q931mes_RESUME, i, Q931ProcResumeTE, Q931Umes_Resume, Q931Pmes_Resume);
+ Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE, i, Q931ProcResumeAckTE, Q931Umes_ResumeAck, Q931Pmes_ResumeAck);
+ Q931SetMesProc(Q931mes_RESUME_REJECT, i, Q931ProcResumeRejectTE, Q931Umes_ResumeReject, Q931Pmes_ResumeReject);
+ Q931SetMesProc(Q931mes_SUSPEND, i, Q931ProcSuspendTE, Q931Umes_Suspend, Q931Pmes_Suspend);
+ Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE, i, Q931ProcSuspendAckTE, Q931Umes_SuspendAck, Q931Pmes_SuspendAck);
+ Q931SetMesProc(Q931mes_SUSPEND_REJECT, i, Q931ProcSuspendRejectTE, Q931Umes_SuspendReject, Q931Pmes_SuspendReject);
+ Q931SetMesProc(Q931mes_USER_INFORMATION, i, Q931ProcUserInformationTE, Q931Umes_UserInformation, Q931Pmes_UserInformation);
+ Q931SetMesProc(Q931mes_DISCONNECT, i, Q931ProcDisconnectTE, Q931Umes_Disconnect, Q931Pmes_Disconnect);
+ Q931SetMesProc(Q931mes_RELEASE, i, Q931ProcReleaseTE, Q931Umes_Release, Q931Pmes_Release);
+ Q931SetMesProc(Q931mes_RELEASE_COMPLETE, i, Q931ProcReleaseCompleteTE, Q931Umes_ReleaseComplete, Q931Pmes_ReleaseComplete);
+ Q931SetMesProc(Q931mes_RESTART, i, Q931ProcRestartTE, Q931Umes_Restart, Q931Pmes_Restart);
+ Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE, i, Q931ProcRestartAckTE, Q931Umes_RestartAck, Q931Pmes_RestartAck);
+ Q931SetMesProc(Q931mes_CONGESTION_CONTROL, i, Q931ProcCongestionControlTE, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+ Q931SetMesProc(Q931mes_INFORMATION, i, Q931ProcInformationTE, Q931Umes_Information, Q931Pmes_Information);
+ Q931SetMesProc(Q931mes_NOTIFY, i, Q931ProcNotifyTE, Q931Umes_Notify, Q931Pmes_Notify);
+ Q931SetMesProc(Q931mes_STATUS, i, Q931ProcStatusTE, Q931Umes_Status, Q931Pmes_Status);
+ Q931SetMesProc(Q931mes_STATUS_ENQUIRY, i, Q931ProcStatusEnquiryTE, Q931Umes_StatusEnquiry, Q931Pmes_StatusEnquiry);
+ Q931SetMesProc(Q931mes_SEGMENT, i, Q931ProcSegmentTE, Q931Umes_Segment, Q931Pmes_Segment);
+
+ Q931SetMesProc(Q932mes_FACILITY, i, Q932ProcFacilityTE, Q932Umes_Facility, Q932Pmes_Facility);
+ Q931SetMesProc(Q932mes_HOLD, i, Q932ProcHoldTE, Q932Umes_Hold, Q932Pmes_Hold);
+ Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE, i, Q932ProcHoldAckTE, Q932Umes_HoldAck, Q932Pmes_HoldAck);
+ Q931SetMesProc(Q932mes_HOLD_REJECT, i, Q932ProcHoldRejectTE, Q932Umes_HoldReject, Q932Pmes_HoldReject);
+ Q931SetMesProc(Q932mes_REGISTER, i, Q932ProcRegisterTE, Q932Umes_Register, Q932Pmes_Register);
+ Q931SetMesProc(Q932mes_RETRIEVE, i, Q932ProcRetrieveTE, Q932Umes_Retrieve, Q932Pmes_Retrieve);
+ Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckTE, Q932Umes_RetrieveAck, Q932Pmes_RetrieveAck);
+ Q931SetMesProc(Q932mes_RETRIEVE_REJECT, i, Q932ProcRetrieveRejectTE, Q932Umes_RetrieveReject, Q932Pmes_RetrieveReject);
+
+ /* Set up the IE encoder/decoder handle table.*/
+ Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE, i, Q931Pie_Segment, Q931Uie_Segment);
+ Q931SetIEProc(Q931ie_BEARER_CAPABILITY, i, Q931Pie_BearerCap, Q931Uie_BearerCap);
+ Q931SetIEProc(Q931ie_CAUSE, i, Q931Pie_Cause, Q931Uie_Cause);
+ Q931SetIEProc(Q931ie_CALL_IDENTITY, i, Q931Pie_CallID, Q931Uie_CallID);
+ Q931SetIEProc(Q931ie_CALL_STATE, i, Q931Pie_CallState, Q931Uie_CallState);
+ Q931SetIEProc(Q931ie_CHANGE_STATUS, i, Q931Pie_ChangeStatus, Q931Uie_ChangeStatus);
+ Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION, i, Q931Pie_ChanID, Q931Uie_ChanID);
+ Q931SetIEProc(Q931ie_PROGRESS_INDICATOR, i, Q931Pie_ProgInd, Q931Uie_ProgInd);
+ Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES, i, Q931Pie_NetFac, Q931Uie_NetFac);
+ Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR, i, Q931Pie_NotifInd, Q931Uie_NotifInd);
+ Q931SetIEProc(Q931ie_DISPLAY, i, Q931Pie_Display, Q931Uie_Display);
+ Q931SetIEProc(Q931ie_DATETIME, i, Q931Pie_DateTime, Q931Uie_DateTime);
+ Q931SetIEProc(Q931ie_KEYPAD_FACILITY, i, Q931Pie_KeypadFac, Q931Uie_KeypadFac);
+ Q931SetIEProc(Q931ie_SIGNAL, i, Q931Pie_Signal, Q931Uie_Signal);
+ Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER, i, Q931Pie_CallingNum, Q931Uie_CallingNum);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS, i, Q931Pie_CallingSub, Q931Uie_CallingSub);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER, i, Q931Pie_CalledNum, Q931Uie_CalledNum);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS, i, Q931Pie_CalledSub, Q931Uie_CalledSub);
+ Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_RESTART_INDICATOR, i, Q931Pie_RestartInd, Q931Uie_RestartInd);
+ Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY, i, Q931Pie_LLComp, Q931Uie_LLComp);
+ Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY, i, Q931Pie_HLComp, Q931Uie_HLComp);
+ Q931SetIEProc(Q931ie_USER_USER, i, Q931Pie_UserUser, Q931Uie_UserUser);
+ Q931SetIEProc(Q931ie_GENERIC_DIGITS, i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+ /* The following define a state machine. The point is that the Message */
+ /* procs can when search this to find out if the message/state */
+ /* combination is legale. If not, the proc for unexpected message apply.*/
+
+ /* State 0 Idle */
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RESUME, 2);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP, 2);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_STATUS, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE_COMPLETE, 4);
+
+ /* State 1 Call Initiating */
+ Q931AddStateEntry(i, Q931_U1, Q931mes_DISCONNECT, 2);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_SETUP_ACKNOWLEDGE, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_RELEASE_COMPLETE, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_CALL_PROCEEDING, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_CONNECT, 4);
+
+ /* State 2 Overlap Sending */
+ Q931AddStateEntry(i, Q931_U2, Q931mes_INFORMATION, 2);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_CALL_PROCEEDING, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_PROGRESS, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_CONNECT, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_RELEASE, 2);
+
+ /* State 3 Outgoing Call Proceeding */
+ Q931AddStateEntry(i, Q931_U3, Q931mes_PROGRESS, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_CONNECT, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_RELEASE, 2);
+
+ /* State 4 Call Delivered */
+ Q931AddStateEntry(i, Q931_U4, Q931mes_CONNECT, 4);
+
+ /* State 6 Call Precent */
+ Q931AddStateEntry(i, Q931_U6, Q931mes_INFORMATION, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_ALERTING, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_CALL_PROCEEDING, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_CONNECT, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE_COMPLETE, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_DISCONNECT, 4);
+
+ /* State 7 Call Received */
+ Q931AddStateEntry(i, Q931_U7, Q931mes_CONNECT, 2);
+
+ /* State 8 Connect request */
+ Q931AddStateEntry(i, Q931_U8, Q931mes_CONNECT_ACKNOWLEDGE, 4);
+
+ /* State 9 Incoming Call Proceeding */
+ Q931AddStateEntry(i, Q931_U9, Q931mes_CONNECT, 2);
+ Q931AddStateEntry(i, Q931_U9, Q931mes_ALERTING, 2);
+ Q931AddStateEntry(i, Q931_U9, Q931mes_PROGRESS, 2);
+
+ /* State 10 Active */
+ Q931AddStateEntry(i, Q931_U10, Q931mes_SUSPEND, 2);
+ Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY, 4);
+ Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY, 2);
+
+ /* State 11 Disconnect Request */
+ Q931AddStateEntry(i, Q931_U11, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U11, Q931mes_DISCONNECT, 4);
+ Q931AddStateEntry(i, Q931_U11, Q931mes_NOTIFY, 4);
+
+ /* State 12 Disconnect Ind */
+ Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 2);
+
+ /* State 15 Suspend Request */
+ Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_ACKNOWLEDGE, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_REJECT, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_DISCONNECT, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_RELEASE, 4);
+
+/* TODO
+ Q931AddStateEntry(i, Q931_U17,
+ Q931AddStateEntry(i, Q931_U19,
+ Q931AddStateEntry(i, Q931_U25,
+*/
+}
+
+/*****************************************************************************
+
+ Function: DMSProc0x0fTE
+
+*****************************************************************************/
+L3INT DMSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ if (pMes->ProtDisc == 8) {
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ }
+ if (iFrom == 4) {
+ /* TODO Add proc here*/
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here*/
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+
+ if (pMes->ProtDisc == 3 && pTrunk->autoServiceAck) {
+ Q931AckService(pTrunk, buf);
+ }
+ }
+ return ret;
+
+}
+
+/*****************************************************************************
+
+ Function: DMSProc0x07TE
+
+*****************************************************************************/
+L3INT DMSProc0x07TE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ if (pMes->ProtDisc == 8) {
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ }
+ if (iFrom == 4) {
+ /* TODO Add proc here*/
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here*/
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+
+}
Added: freeswitch/trunk/libs/freetdm/src/isdn/DMSmes.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/DMSmes.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/DMSmes.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,344 @@
+/*****************************************************************************
+
+ FileName: DMSmes.c
+
+ Contents: Pack/Unpack functions. These functions will unpack a DMS-100 ISDN
+ message from the bit packed original format into structs
+ that contains variables sized by the user. It will also pack
+ the struct back into a Q.931 message as required.
+
+ See national.h for description.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ 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 Case Labs, Ltd 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.
+
+*****************************************************************************/
+
+#include "DMS.h"
+
+/*****************************************************************************
+
+ Function: DMSUmes_Setup
+
+*****************************************************************************/
+L3INT DMSUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT ir = 0;
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+ L3UCHAR last_codeset = 0, codeset = 0;
+ L3UCHAR shift_lock = 1;
+
+ while (IOff < Size) {
+ if (!shift_lock) {
+ codeset = last_codeset;
+ }
+
+ if ((IBuf[IOff] & 0xF0) == Q931ie_SHIFT ) {
+ shift_lock = (IBuf[IOff] & 0x08);
+ if (shift_lock) {
+ last_codeset = codeset;
+ }
+ codeset = ((IBuf[IOff] & 0x07));
+ IOff++;
+ }
+
+ if (codeset == 0) {
+ switch (IBuf[IOff]) {
+ case Q931ie_SENDING_COMPLETE:
+ case Q931ie_BEARER_CAPABILITY:
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_NETWORK_SPECIFIC_FACILITIES:
+ case Q931ie_DISPLAY:
+ case Q931ie_DATETIME:
+ case Q931ie_KEYPAD_FACILITY:
+ case Q931ie_SIGNAL:
+ case Q931ie_CALLING_PARTY_NUMBER:
+ case Q931ie_CALLING_PARTY_SUBADDRESS:
+ case Q931ie_CALLED_PARTY_NUMBER:
+ case Q931ie_CALLED_PARTY_SUBADDRESS:
+ case Q931ie_TRANSIT_NETWORK_SELECTION:
+ case Q931ie_LOW_LAYER_COMPATIBILITY:
+ case Q931ie_HIGH_LAYER_COMPATIBILITY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ case Q931ie_REPEAT_INDICATOR:
+ if (ir < 2) {
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ ir++;
+ } else {
+ return Q931E_ILLEGAL_IE;
+ }
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ } else if (codeset == 6) {
+ switch (IBuf[IOff]) {
+ case Q931ie_GENERIC_DIGITS:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+
+ } else {
+ return Q931E_ILLEGAL_IE;
+ }
+ }
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: DMSPmes_Setup
+
+ Decription: Pack a Q931mes_Generic into a real Q.931 message. The user will
+ set up a SETUP message and issue this to the stack where it
+ is processed by Q931ProcSetup that processes and validates
+ it before it actually sends it out. This function is called
+ to compute the real Q.931 message.
+
+ Parameters: IBuf[IN] Ptr to un-packed struct
+ ISize[IN] Size of input buffer (unpacked message).
+ OBuf[OUT] Ptr to packed 'octet' wise message.
+ OSize[OUT] Size of packed message.
+
+ Called By: Q931ProcSetup
+
+*****************************************************************************/
+L3INT DMSPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3INT rc = Q931E_NO_ERROR;
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Sending Complete */
+ if (Q931IsIEPresent(pMes->SendComplete)) {
+ OBuf[Octet++] = (L3UCHAR)(pMes->SendComplete & 0x00ff);
+ }
+
+ /* Repeat Indicator */
+ if (Q931IsIEPresent(pMes->RepeatInd)) {
+ OBuf[Octet++] = (L3UCHAR)(pMes->RepeatInd & 0x00ff);
+ }
+
+ /* Bearer capability */
+ if (Q931IsIEPresent(pMes->BearerCap)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ } else {
+ rc = Q931E_BEARERCAP;
+ }
+
+ /* Channel Identification */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Network spesific facilities */
+ if (Q931IsIEPresent(pMes->NetFac)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_NETWORK_SPECIFIC_FACILITIES](pTrunk, Q931GetIEPtr(pMes->NetFac,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Date/Time */
+ if (Q931IsIEPresent(pMes->DateTime)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Keypad Facility */
+ if (Q931IsIEPresent(pMes->KeypadFac)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Calling Party Number */
+ if (Q931IsIEPresent(pMes->CallingNum)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CallingNum,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Calling Party Subaddress */
+ if (Q931IsIEPresent(pMes->CallingSub)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CallingSub,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Called Party number */
+ if (Q931IsIEPresent(pMes->CalledNum)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+
+ /* Called party subaddress */
+ if (Q931IsIEPresent(pMes->CalledSub)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CalledSub,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Transit network selection */
+ if (Q931IsIEPresent(pMes->TransNetSel)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_TRANSIT_NETWORK_SELECTION](pTrunk, Q931GetIEPtr(pMes->TransNetSel,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Repeat Indicator */
+ if (Q931IsIEPresent(pMes->LLRepeatInd)) {
+ rc = Q931E_UNKNOWN_IE;/* TODO */
+ }
+
+ /* Low Layer Compatibility */
+ if (Q931IsIEPresent(pMes->LLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* High Layer Compatibility */
+ if (Q931IsIEPresent(pMes->HLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+
+/*****************************************************************************
+
+ Function: DMSUmes_0x0f
+
+*****************************************************************************/
+L3INT DMSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ if (mes->ProtDisc == 8) {
+ return Q931Umes_ConnectAck(pTrunk, IBuf, mes, IOff, Size);
+ }
+
+ if (mes->ProtDisc == 3) {
+ return Q931Umes_Service(pTrunk, IBuf, mes, IOff, Size);
+ }
+
+ return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+ Function: DMSPmes_0x0f
+
+*****************************************************************************/
+L3INT DMSPmes_0x0f(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *mes = (Q931mes_Generic *)IBuf;
+
+ if (mes->ProtDisc == 8) {
+ return Q931Pmes_ConnectAck(pTrunk, IBuf, ISize, OBuf, OSize);
+ }
+
+ if (mes->ProtDisc == 3) {
+ return Q931Pmes_Service(pTrunk, IBuf, ISize, OBuf, OSize);
+ }
+
+ return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+ Function: DMSUmes_0x07
+
+*****************************************************************************/
+L3INT DMSUmes_0x07(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ if (mes->ProtDisc == 8) {
+ return Q931Umes_Connect(pTrunk, IBuf, mes, IOff, Size);
+ }
+
+ if (mes->ProtDisc == 3) {
+ return Q931Umes_ServiceAck(pTrunk, IBuf, mes, IOff, Size);
+ }
+
+ return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+ Function: DMSPmes_0x07
+
+*****************************************************************************/
+L3INT DMSPmes_0x07(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *mes = (Q931mes_Generic *)IBuf;
+
+ if (mes->ProtDisc == 8) {
+ return Q931Pmes_Connect(pTrunk, IBuf, ISize, OBuf, OSize);
+ }
+
+ if (mes->ProtDisc == 3) {
+ return Q931Pmes_ServiceAck(pTrunk, IBuf, ISize, OBuf, OSize);
+ }
+
+ return Q931E_UNKNOWN_MESSAGE;
+}
Added: freeswitch/trunk/libs/freetdm/src/isdn/EuroISDNStateNT.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/EuroISDNStateNT.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/EuroISDNStateNT.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,44 @@
+/*****************************************************************************
+
+ FileName: EuroISDNStateNT.c
+
+ Contents: EuroISDN State Engine for NT (Network Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "Q931.h"
Added: freeswitch/trunk/libs/freetdm/src/isdn/EuroISDNStateTE.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/EuroISDNStateTE.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/EuroISDNStateTE.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,58 @@
+/*****************************************************************************
+
+ FileName: EuroISDNStateTE.c
+
+ Contents: EuroISDN State Engine for TE (User Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "Q931.h"
+
+/*
+ EuroISDN is a sub-set of Q.931. Q.931 is very generic as it embrase a lot,
+ while EuroISDN is more exact and make decitions on some of the
+ 'implementation options' in the original standard. EuroISDN will
+ however run smoothly under the generic space, so these functions are more
+ for show
+*/
+#if 0
+static void EuroISDNCreateTE(L3UCHAR i)
+{
+ Q931CreateTE(i);
+}
+#endif
Added: freeswitch/trunk/libs/freetdm/src/isdn/Q921.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/Q921.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/Q921.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3518 @@
+/*****************************************************************************
+
+ FileName: q921.c
+
+ Description: Contains the implementation of a Q.921 protocol
+
+ Created: 27.dec.2000/JVB
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+
+*****************************************************************************/
+
+/****************************************************************************
+ * Changes:
+ *
+ * - June-August 2008: Stefan Knoblich <s.knoblich@axsentis.de>:
+ * Add PTMP TEI management (NT + TE mode)
+ * Add timers
+ * Add retransmit counters
+ * Add logging
+ * Various cleanups
+ * Queues, retransmission of I frames
+ * PTMP NT mode
+ *
+ *
+ * TODO:
+ *
+ * - Cleanup queueing, test retransmission
+ *
+ * - Q921Start() /-Stop() TEI acquire + release
+ * (move everything related into these functions)
+ *
+ * - Q.921 '97 Appendix I (and maybe III, IV)
+ *
+ * - More complete Appendix II
+ *
+ * - Test PTP mode
+ *
+ * - PTMP NT mode (in progress)
+ *
+ * - NT mode TEI management: (ab)use T202 for TEI Check Request retransmission
+ *
+ * - General cleanup (move all non-public declarations into private header file)
+ *
+ * - Statistics, per-Frame type debug message filter
+ *
+ ****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "freetdm.h"
+#include "Q921.h"
+#include "Q921priv.h"
+#include "mfifo.h"
+
+#ifdef WIN32
+#pragma warning(disable:4100 4244)
+#endif
+
+/******************************************************************************************************
+ * Actual code below this line
+ ******************************************************************************************************/
+
+
+/**
+ * Q921StateNames
+ * \brief Static array of state name / value mappings
+ */
+static struct Q921StateName {
+ Q921State_t value;
+ const char *name;
+} Q921StateNames[10] = {
+ { Q921_STATE_STOPPED, "Stopped" },
+ { Q921_STATE_TEI_UNASSIGNED, "TEI Unassigned" },
+ { Q921_STATE_TEI_AWAITING, "TEI Awaiting Assignment" },
+ { Q921_STATE_TEI_ESTABLISH, "TEI Awaiting Establishment" },
+ { Q921_STATE_TEI_ASSIGNED, "TEI Assigned" },
+ { Q921_STATE_AWAITING_ESTABLISHMENT, "Awaiting Establishment" },
+ { Q921_STATE_AWAITING_RELEASE, "Awaiting Release" },
+ { Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, "Multiple Frame Mode Established" },
+ { Q921_STATE_TIMER_RECOVERY, "Timer Recovery" },
+ { 0, 0 }
+};
+
+/**
+ * Q921State2Name
+ * \brief Convert state value to name
+ * \param[in] state the state value
+ * \return the state name or "Unknown"
+ *
+ * \author Stefan Knoblich
+ */
+static const char *Q921State2Name(Q921State_t state)
+{
+ struct Q921StateName *p = Q921StateNames;
+
+ while(p->name) {
+ if(p->value == state)
+ return p->name;
+ p++;
+ }
+
+ return "Unknown";
+}
+
+
+/**
+ * Q921SendEnquiry
+ */
+static int Q921SendEnquiry(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ /* send enquiry: begin */
+ if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+
+ Q921SendRNR(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
+ }
+ else {
+ Q921SendRR(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
+ }
+
+ /* clear acknowledge pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+ /* "Start" T200 */
+ Q921T200TimerReset(trunk, tei);
+
+ /* send enquiry: end */
+ return 1;
+}
+
+/**
+ * Q921SendEnquiryResponse
+ */
+static int Q921SendEnquiryResponse(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ /* send enquiry: begin */
+ if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+
+ Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+ }
+ else {
+ Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+
+ /* clear acknowledge pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+ }
+ /* send enquiry: end */
+ return 1;
+}
+
+/**
+ * Q921ResetExceptionConditions
+ * \brief Reset Q.921 Exception conditions procedure
+ * \param trunk Q.921 data structure
+ * \param tei TEI
+ * \todo Do something
+ */
+static void Q921ResetExceptionConditions(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ /* Clear peer receiver busy */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+ /* Clear reject exception */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_REJECT);
+
+ /* Clear own receiver busy */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_RECV_BUSY);
+
+ /* Clear acknowledge pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+ return;
+}
+
+/**
+ * Q921EstablishDataLink
+ * \brief Q.921 Establish data link procedure
+ * \param trunk Q.921 data structure
+ * \param tei TEI
+ * \return always 1 (success)
+ */
+static int Q921EstablishDataLink(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ /* reset exception conditions */
+ Q921ResetExceptionConditions(trunk, tei);
+
+ /* RC = 0 */
+ link->N200 = 0;
+
+ /* Send SABME */
+ Q921SendSABME(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
+
+ /* Restart T200, stop T203 */
+ Q921T200TimerReset(trunk, tei);
+ Q921T203TimerStop(trunk, tei);
+
+ return 1;
+}
+
+/**
+ * Q921NrErrorRecovery
+ * \brief NR(R) Error recovery procedure
+ * \param trunk Q.921 data structure
+ * \param tei TEI
+ * \return always 1 (success)
+ */
+static int Q921NrErrorRecovery(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ /* MDL Error indication (J) */
+
+ /* Establish datalink */
+ Q921EstablishDataLink(trunk, tei);
+
+ /* Clear L3 initiated */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+ return 1;
+}
+
+
+/**
+ * Q921InvokeRetransmission
+ * \brief I Frame retransmission procedure
+ * \param trunk Q.921 data structure
+ * \param tei TEI
+ * \param nr N(R) for retransmission
+ * \return always 1 (success)
+ */
+static int Q921InvokeRetransmission(L2TRUNK trunk, L2UCHAR tei, L2UCHAR nr)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+ L2UCHAR *mes;
+ L2INT qpos, qnum, size = 0;
+
+ qnum = MFIFOGetMesCount(link->IFrameResendQueue);
+ qpos = qnum - 1;
+
+ /*
+ * slightly different than what is shown in the spec
+ * (Q.921 '97 Annex B, Figure B.9, page 104)
+ *
+ * what the above mentioned figure probably means is:
+ * "as long as V(S) != N(R), move the pointer marking
+ * the first frame to start resending at to the previous
+ * frame"
+ *
+ * if we actually implemented it as shown in the figure, we'd be
+ * resending frames in the wrong order (moving backwards in time)
+ * meaning we'd have to add an incoming queue to reorder the frames
+ *
+ */
+ /*
+ * TODO: There's a "traditional" off-by-one error hidden in the original
+ * mfifo implementation + it's late, i'm tired and being lazy,
+ * so i'll probably have added another one :P
+ *
+ * wow, the first while loop sucks and can be removed
+ */
+ while(link->vs != nr && qpos > 0) { /* ???? */
+ /* V(S) = V(S) - 1 */
+ Q921_DEC_COUNTER(link->vs); /* huh? backwards? */
+
+ /* next frame in queue (backtrack along I queue) ??? */
+ qpos--;
+ }
+
+ /*
+ * being lazy and trying to avoid mod 128 math this way...
+ */
+ if(link->vs != nr && !qpos) {
+ /* fatal, we don't have enough history to resend all missing frames */
+ /* TODO: how to handle this? */
+ }
+
+ /*
+ * resend frames in correct order (oldest missing frame first,
+ * contrary to what the spec figure shows)
+ */
+ while(qpos < qnum) {
+ /* Grab frame's buffer ptr and size from queue */
+ mes = MFIFOGetMesPtrOffset(link->IFrameResendQueue, &size, qpos);
+ if(mes) {
+ /* requeue frame (TODO: check queue full condition) */
+ MFIFOWriteMes(link->IFrameQueue, mes, size);
+
+ /* set I frame queued */
+ }
+
+ qpos++;
+ }
+
+ return 1;
+}
+
+
+static int Q921AcknowledgePending(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ case Q921_STATE_TIMER_RECOVERY:
+ if(Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING)) {
+ /* clear acknowledge pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+ /* send RR */
+ Q921SendRR(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 0);
+
+ return 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+
+ Function: Q921_InitTrunk
+
+ Decription: Initialize a Q.921 trunk so it is ready for use. This
+ function MUST be called before you call any other functions.
+
+*****************************************************************************/
+int Q921_InitTrunk(L2TRUNK trunk,
+ L2UCHAR sapi,
+ L2UCHAR tei,
+ Q921NetUser_t NetUser,
+ Q921NetType_t NetType,
+ L2INT hsize,
+ Q921Tx21CB_t cb21,
+ Q921Tx23CB_t cb23,
+ void *priv21,
+ void *priv23)
+{
+ int numlinks = 0;
+
+ trunk->sapi = sapi;
+ trunk->tei = tei;
+ trunk->NetUser = NetUser;
+ trunk->NetType = NetType;
+ trunk->Q921Tx21Proc = cb21;
+ trunk->Q921Tx23Proc = cb23;
+ trunk->PrivateData21 = priv21;
+ trunk->PrivateData23 = priv23;
+ trunk->Q921HeaderSpace = hsize;
+
+ numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
+
+ if (trunk->initialized != INITIALIZED_MAGIC) {
+ MFIFOCreate(trunk->HDLCInQueue, Q921MAXHDLCSPACE, 10);
+
+ /*
+ * Allocate space for per-link context(s)
+ */
+ trunk->context = ftdm_malloc(numlinks * sizeof(struct Q921_Link));
+ if(!trunk->context)
+ return -1;
+
+ trunk->initialized = INITIALIZED_MAGIC;
+ }
+
+ /* timeout default values */
+ trunk->T200Timeout = 1000; /* 1 second */
+ trunk->T203Timeout = 10000; /* 10 seconds */
+ trunk->T202Timeout = 2000; /* 2 seconds */
+ trunk->T201Timeout = 200000; /* 200 seconds */
+ trunk->TM01Timeout = 10000; /* 10 seconds */
+
+ /* octet / retransmit counter default limits */
+ trunk->N200Limit = 3; /* 3 retransmits */
+ trunk->N201Limit = 260; /* 260 octets */
+ trunk->N202Limit = 3; /* 3 retransmits */
+ trunk->k = 7; /* 7 outstanding ACKs */
+
+ /* reset counters, timers, etc. */
+ trunk->T202 = 0;
+ trunk->N202 = 0;
+
+ /* Reset per-link contexts */
+ memset(trunk->context, 0, numlinks * sizeof(struct Q921_Link));
+
+ /* clear tei map */
+ memset(trunk->tei_map, 0, Q921_TEI_MAX + 1);
+
+ if(Q921_IS_PTMP(trunk)) {
+ /*
+ * We're either the Network side (NT, TEI = 0)
+ * or user-side equipment (TE) which will get it's TEI via
+ * dynamic assignment
+ */
+ trunk->tei = 0;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Q921Tx21Proc
+ * \brief Submit frame to layer 1 (for sending)
+ * \param[in] trunk Pointer to trunk struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success; <= 0 on error
+ */
+static int Q921Tx21Proc(L2TRUNK trunk, L2UCHAR *Msg, L2INT size)
+{
+ Q921LogMesg(trunk, Q921_LOG_DEBUG, 0, Msg, size, "Sending frame");
+
+ return trunk->Q921Tx21Proc(trunk->PrivateData21, Msg, size);
+}
+
+
+/**
+ * Q921Tx23Proc
+ * \brief Submit frame to layer 3
+ * \param[in] trunk Pointer to trunk struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success; <= 0 on error
+ */
+static int Q921Tx23Proc(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *Msg, L2INT size)
+{
+ return trunk->Q921Tx23Proc(trunk->PrivateData23, ind, tei, Msg, size);
+}
+
+
+/**
+ * Q921LogProc
+ * \brief Used for logging, converts to string and submits to higher level log function via callback
+ * \param[in] trunk Pointer to trunk struct
+ * \param[in] level Q921 Loglevel
+ * \param[in] fmt format of logmessage
+ * \return >= 0 on success, < 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921Log(L2TRUNK trunk, Q921LogLevel_t level, const char *fmt, ...)
+{
+ char buf[Q921_LOGBUFSIZE];
+ L2INT len;
+ va_list ap;
+
+ if(!trunk->Q921LogProc)
+ return 0;
+
+ if(trunk->loglevel < level)
+ return 0;
+
+ va_start(ap, fmt);
+
+ len = vsnprintf(buf, sizeof(buf)-1, fmt, ap);
+ if(len <= 0) {
+ /* TODO: error handling */
+ return -1;
+ }
+ if(len >= sizeof(buf))
+ len = sizeof(buf) - 1;
+
+ buf[len] = '\0';
+
+ va_end(ap);
+
+ return trunk->Q921LogProc(trunk->PrivateDataLog, level, buf, len);
+}
+
+
+static int print_hex(char *buf, int bsize, const unsigned char *in, const int len)
+{
+ static const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+ int offset = 0;
+ int pos = 0;
+ int nr = 0;
+
+ buf[pos++] = '[';
+ bsize -= 3;
+
+ while((bsize - pos) > 0 && offset < len) {
+ buf[pos++] = hex[(in[offset] & 0xF0) >> 4];
+ buf[pos++] = hex[(in[offset++] & 0x0F)];
+
+ if(++nr == 32 && offset < len && (bsize - pos) > 3) {
+ nr = 0;
+ buf[pos++] = ']';
+ buf[pos++] = '\n';
+ buf[pos++] = '[';
+ }
+ else if(offset < len) {
+ buf[pos++] = ' ';
+ }
+ }
+
+ buf[pos++] = ']';
+ buf[pos++] = '\n';
+ buf[pos] = '\0';
+
+ return pos;
+}
+
+#define APPEND_MSG(buf, off, lef, fmt, ...) \
+ len = snprintf(buf + off, lef, fmt, ##__VA_ARGS__); \
+ if(len > 0) { \
+ off += len; \
+ lef -= len; \
+ } else { \
+ goto out; \
+ }
+
+/**
+ * Q921LogProcMesg
+ * \brief Used for logging, converts to string and submits to higher level log function via callback
+ * \param[in] trunk Pointer to trunk struct
+ * \param[in] level Q921 Loglevel
+ * \param[in] received direction of the message (received = 1, sending = 0)
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \param[in] fmt format of logmessage
+ * \return >= 0 on success, < 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921LogMesg(L2TRUNK trunk, Q921LogLevel_t level, L2UCHAR received, L2UCHAR *mes, L2INT size, const char *fmt, ...)
+{
+ char buf[Q921_LOGBUFSIZE];
+ size_t len, left;
+ va_list ap;
+
+ if(!trunk->Q921LogProc)
+ return 0;
+
+ if(trunk->loglevel < level)
+ return 0;
+
+ if(!mes)
+ return 0;
+
+ memset(buf, 0, sizeof(buf));
+
+ left = sizeof(buf) - 1;
+
+ va_start(ap, fmt);
+
+ len = vsnprintf(buf, left, fmt, ap);
+ if(len > 0)
+ left -= len;
+ else {
+ /* TODO: error handling */
+ return -1;
+ }
+
+ va_end(ap);
+
+ if(trunk->loglevel == Q921_LOG_DEBUG) {
+ char pbuf[1024];
+ size_t pleft, poffset;
+ L2UCHAR sapi, tei, cr;
+ L2UCHAR *pmes = mes + trunk->Q921HeaderSpace;
+ struct Q921_Link *link;
+
+ memset(pbuf, 0, sizeof(pbuf));
+
+ pleft = sizeof(pbuf);
+ poffset = 0;
+
+ /*
+ * Decode packet
+ */
+ sapi = (pmes[0] & 0xfc) >> 2;
+ cr = (pmes[0] & 0x02) >> 1;
+ tei = (pmes[1] & 0xfe) >> 1;
+ link = Q921_LINK_CONTEXT(trunk, tei);
+
+ /* make cr actually useful */
+ cr = (received) ? Q921_IS_COMMAND(trunk, cr) : Q921_IS_RESPONSE(trunk, cr);
+
+ /* filter */
+ if((pmes[2] & 0x01) == 0x00) {
+ ;
+ }
+ else if((pmes[2] & 0x03) == 0x01) {
+ ; //return 0;
+ }
+ else if((pmes[2] & 0x03) == 0x03) {
+ ;
+ }
+
+ APPEND_MSG(pbuf, poffset, pleft, "\n----------------- Q.921 Packet [%s%s] ---------------\n", received ? "Incoming" : "Outgoing",
+ (tei == link->tei || tei == Q921_TEI_BCAST) ? "" : ", Ignored" );
+
+ /* common header */
+ APPEND_MSG(pbuf, poffset, pleft, " SAPI: %u, TEI: %u, C/R: %s (%d)\n\n", sapi, tei, (cr) ? "Command" : "Response", (mes[0] & 0x02) >> 1 );
+
+ /*
+ * message specific
+ */
+ if((pmes[2] & 0x01) == 0x00) {
+ /*
+ * I frame
+ */
+ L2UCHAR pf = pmes[3] & 0x01; /* poll / final flag */
+ L2UCHAR nr = pmes[3] >> 1; /* receive sequence number */
+ L2UCHAR ns = pmes[2] >> 1; /* send sequence number */
+
+ APPEND_MSG(pbuf, poffset, pleft, " Type: I Frame\n P/F: %d, N(S): %d, N(R): %d [V(A): %d, V(R): %d, V(S): %d]\n", pf, ns, nr,
+ link->va, link->vr, link->vs);
+
+ /* Dump content of I Frames for foreign TEIs */
+ if(tei != link->tei) {
+ APPEND_MSG(pbuf, poffset, pleft, " CONTENT:\n");
+
+ len = print_hex(pbuf + poffset, (int)pleft, &pmes[4], size - (trunk->Q921HeaderSpace + 4));
+ poffset += len;
+ pleft -= len;
+ }
+ }
+ else if((pmes[2] & 0x03) == 0x01) {
+ /*
+ * S frame
+ */
+ L2UCHAR sv = (pmes[2] & 0x0c) >> 2; /* supervisory format id */
+ L2UCHAR pf = pmes[3] & 0x01; /* poll / final flag */
+ L2UCHAR nr = pmes[3] >> 1; /* receive sequence number */
+ const char *type;
+
+ switch(sv) {
+ case 0x00: /* RR : Receive Ready */
+ type = "RR (Receive Ready)";
+ break;
+
+ case 0x02: /* RNR : Receive Not Ready */
+ type = "RNR (Receiver Not Ready)";
+ break;
+
+ case 0x04: /* REJ : Reject */
+ type = "REJ (Reject)";
+ break;
+
+ default: /* Invalid / Unknown */
+ type = "Unknown";
+ break;
+ }
+
+ APPEND_MSG(pbuf, poffset, pleft, " Type: S Frame, SV: %s\n P/F: %d, N(R): %d [V(A): %d, V(R): %d, V(S): %d]\n", type, pf, nr,
+ link->va, link->vr, link->vs);
+ }
+ else if((pmes[2] & 0x03) == 0x03) {
+ /*
+ * U frame
+ */
+ L2UCHAR m = (pmes[2] & 0xe0) >> 3 | (pmes[2] & 0x0c) >> 2; /* modifier function id */
+ L2UCHAR pf = (pmes[2] & 0x10) >> 4; /* poll / final flag */
+ const char *type;
+
+ switch(m) {
+ case 0x00:
+ type = "UI (Unnumbered Information)";
+ break;
+
+ case 0x03:
+ type = "DM (Disconnected Mode)";
+ break;
+
+ case 0x08:
+ type = "DISC (Disconnect)";
+ break;
+
+ case 0x0c:
+ type = "UA (Unnumbered Acknowledgement)";
+ break;
+
+ case 0x0f:
+ type = "SABME";
+ break;
+
+ case 0x11:
+ type = "FRMR (Frame Reject)";
+ break;
+
+ case 0x17:
+ type = "XID (Exchange Identification)";
+ break;
+
+ default:
+ type = "Unknown";
+ }
+
+
+ APPEND_MSG(pbuf, poffset, pleft, " Type: U Frame (%s)\n P/F: %d\n", type, pf);
+
+ if(m == 0x00) {
+ switch(pmes[3]) {
+ case Q921_LAYER_ENT_ID_TEI:
+ type = "TEI Mgmt";
+ break;
+
+ case Q921_LAYER_ENT_ID_Q931:
+ type = "Q.931";
+ break;
+
+ default:
+ type = "Unknown";
+ }
+
+ if(pmes[3] == Q921_LAYER_ENT_ID_TEI) {
+ const char *command = "";
+
+ switch(pmes[6]) {
+ case Q921_TEI_ID_REQUEST:
+ command = "Request";
+ break;
+ case Q921_TEI_ID_VERIFY:
+ command = "Verify";
+ break;
+ case Q921_TEI_ID_CHECKREQ:
+ command = "Check req";
+ break;
+ case Q921_TEI_ID_CHECKRESP:
+ command = "Check resp";
+ break;
+ case Q921_TEI_ID_REMOVE:
+ command = "Remove";
+ break;
+ case Q921_TEI_ID_ASSIGNED:
+ command = "Assign";
+ break;
+ case Q921_TEI_ID_DENIED:
+ command = "Denied";
+ break;
+ }
+ APPEND_MSG(pbuf, poffset, pleft, " ENT ID: %d (%s), COMMAND: %d (%s), RI: %#x, AI: %d\n",
+ pmes[3], type, pmes[6], command, (int)((pmes[4] << 8) | pmes[5]), pmes[7] >> 1);
+ }
+ else {
+ APPEND_MSG(pbuf, poffset, pleft, " ENT ID: %d (%s), MESSAGE CONTENT:\n", pmes[3], type);
+
+ len = print_hex(pbuf + poffset, (int)pleft, &pmes[3], size - (trunk->Q921HeaderSpace + 3));
+ poffset += len;
+ pleft -= len;
+ }
+ }
+ }
+ else {
+ /*
+ * Unknown
+ */
+ strncat(pbuf + poffset, " -- unknown frame type --\n", pleft);
+
+ len = (sizeof(pbuf) - poffset) - strlen(pbuf + poffset);
+ if(len > 0) {
+ poffset += len;
+ pleft -= len;
+ } else
+ goto out;
+ }
+
+ APPEND_MSG(pbuf, poffset, pleft, "\n Q.921 state: \"%s\" (%d) [flags: %c%c%c%c]\n", Q921State2Name(link->state), link->state,
+ Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING) ? 'A' : '-',
+ Q921_CHECK_FLAG(link, Q921_FLAG_REJECT) ? 'R' : '-',
+ Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY) ? 'P' : '-',
+ Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY) ? 'B' : '-');
+
+ strncat(pbuf + poffset, "----------------------------------------------\n\n", pleft);
+
+ len = (sizeof(pbuf) - poffset) - strlen(pbuf + poffset);
+ if(len > 0) {
+ poffset += len;
+ pleft -= len;
+ } else
+ goto out;
+
+
+ /* concat buffers together */
+ len = strlen(pbuf);
+ if(len <= left)
+ strncat(buf, pbuf, left);
+ else
+ strncat(buf, "-- packet truncated --\n", left);
+ }
+
+out:
+ buf[sizeof(buf) - 1] = '\0';
+
+ return trunk->Q921LogProc(trunk->PrivateDataLog, level, buf, (int)strlen(buf));
+}
+
+/*****************************************************************************
+
+ Function: Q921TimeTick
+
+ Description: Called periodically from an external source to allow the
+ stack to process and maintain it's own timers.
+
+ Return Value: none
+
+*****************************************************************************/
+static L2ULONG (*Q921GetTimeProc) (void) = NULL; /* callback for func reading time in ms */
+static L2ULONG tLast = {0};
+
+static L2ULONG Q921GetTime(void)
+{
+ L2ULONG tNow = 0;
+
+ if(Q921GetTimeProc)
+ {
+ tNow = Q921GetTimeProc();
+ if(tNow < tLast) /* wrapped */
+ {
+ /* TODO */
+ }
+ tLast = tNow;
+ }
+ return tNow;
+}
+
+/*
+ * T200 handling (per-TEI in PTMP NT mode, tei=0 otherwise)
+ */
+static void Q921T200TimerStart(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ if (!link->T200) {
+ link->T200 = Q921GetTime() + trunk->T200Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T200 (timeout: %d msecs) started for TEI %d\n", trunk->T200Timeout, tei);
+ }
+}
+
+static void Q921T200TimerStop(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ link->T200 = 0;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T200 stopped for TEI %d\n", tei);
+}
+
+static void Q921T200TimerReset(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ link->T200 = Q921GetTime() + trunk->T200Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T200 (timeout: %d msecs) restarted for TEI %d\n", trunk->T200Timeout, tei);
+}
+
+/*
+ * T203 handling (per-TEI in PTMP NT mode, tei=0 otherwise)
+ */
+static void Q921T203TimerStart(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ if (!link->T203) {
+ link->T203 = Q921GetTime() + trunk->T203Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T203 (timeout: %d msecs) started for TEI %d\n", trunk->T203Timeout, tei);
+ }
+}
+
+static void Q921T203TimerStop(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ link->T203 = 0;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T203 stopped for TEI %d\n", tei);
+}
+
+static void Q921T203TimerReset(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ link->T203 = Q921GetTime() + trunk->T203Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T203 (timeout: %d msecs) restarted for TEI %d\n", trunk->T203Timeout, tei);
+}
+
+/*
+ * T202 handling (TEI message timeout, TE mode only)
+ */
+static void Q921T202TimerStart(L2TRUNK trunk)
+{
+ if (!trunk->T202) {
+ trunk->T202 = Q921GetTime() + trunk->T202Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T202 (timeout: %d msecs) started\n", trunk->T202Timeout);
+ }
+}
+
+static void Q921T202TimerStop(L2TRUNK trunk)
+{
+ trunk->T202 = 0;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T202 stopped\n");
+}
+
+static void Q921T202TimerReset(L2TRUNK trunk)
+{
+ trunk->T202 = Q921GetTime() + trunk->T202Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T202 (timeout: %d msecs) restarted\n", trunk->T202Timeout);
+}
+
+/*
+ * T201 handling (TEI management (NT side), per-TEI)
+ */
+static void Q921T201TimerStart(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ if (!link->T201) {
+ link->T201 = Q921GetTime() + trunk->T201Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T201 (timeout: %d msecs) started for TEI %d\n", trunk->T201Timeout, tei);
+ }
+}
+
+static void Q921T201TimerStop(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ link->T201 = 0;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T201 stopped for TEI %d\n", tei);
+}
+
+#ifdef __UNUSED_FOR_NOW__
+static void Q921T201TimerReset(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ link->T201 = Q921GetTime() + trunk->T201Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T201 (timeout: %d msecs) restarted for TEI %d\n", trunk->T201Timeout, tei);
+}
+#endif
+
+/*
+ * TM01 handling (Datalink inactivity shutdown timer)
+ */
+static void Q921TM01TimerStart(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ if (!link->TM01) {
+ link->TM01 = Q921GetTime() + trunk->TM01Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "TM01 (timeout: %d msecs) started for TEI %d\n", trunk->TM01Timeout, tei);
+ }
+}
+
+#ifdef __UNUSED_FOR_NOW__
+static void Q921TM01TimerStop(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ link->TM01 = 0;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "TM01 stopped for TEI %d\n", tei);
+}
+#endif
+
+static void Q921TM01TimerReset(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ link->TM01 = Q921GetTime() + trunk->TM01Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "TM01 (timeout: %d msecs) restarted for TEI %d\n", trunk->TM01Timeout, tei);
+}
+
+/*
+ * Expiry callbacks
+ */
+static void Q921T200TimerExpire(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+ struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T200 expired for TEI %d (trunk TEI %d)\n", tei, trlink->tei);
+
+ /* Stop timer first */
+ Q921T200TimerStop(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_AWAITING_ESTABLISHMENT:
+ if(link->N200 >= trunk->N200Limit) {
+ /* Discard I queue */
+ MFIFOClear(link->IFrameQueue);
+
+ /* MDL-Error indication (G) */
+ Q921Log(trunk, Q921_LOG_ERROR, "Failed to establish Q.921 link in %d retries\n", link->N200);
+
+ /* DL-Release indication */
+ Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+ } else {
+ /* Increment retry counter */
+ link->N200++;
+
+ /* Send SABME */
+ Q921SendSABME(trunk,
+ trunk->sapi,
+ Q921_COMMAND(trunk),
+ tei,
+ 1);
+
+ /* Start T200 */
+ Q921T200TimerStart(trunk, tei);
+ }
+ break;
+
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ link->N200 = 0;
+
+ if(!Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
+ /* get last transmitted I frame */
+
+ /* V(S) = V(S) - 1 */
+ Q921_DEC_COUNTER(link->vs);
+
+ /* retransmit I frame */
+
+ /* V(S) = V(S) + 1 (done by Q921SendI() ) */
+ //Q921_INC_COUNTER(link->vs);
+
+ /* clear acknowledge pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+ /* Start T200 */
+ Q921T200TimerStart(trunk, tei);
+ } else {
+ /* transmit enquiry */
+ Q921SendEnquiry(trunk, tei);
+ }
+
+ /* increment counter */
+ link->N200++;
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_TIMER_RECOVERY, tei);
+ break;
+
+ case Q921_STATE_TIMER_RECOVERY:
+ if(link->N200 == trunk->N200Limit) {
+ /* MDL Error indication (I) */
+
+ /* Establish data link */
+ Q921EstablishDataLink(trunk, tei);
+
+ /* Clear L3 initiated */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ } else {
+ if(link->vs == link->va) {
+ /* transmit enquiry */
+ Q921SendEnquiry(trunk, tei);
+
+ } else if(!Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
+ /* get last transmitted frame */
+
+ /* V(S) = V(S) - 1 */
+ Q921_DEC_COUNTER(link->vs);
+
+ /* retrans frame */
+
+ /* V(S) = V(S) + 1 (done by Q921SendI() ) */
+ //Q921_INC_COUNTER(link->vs);
+
+ /* clear acknowledge pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+ /* Start T200 */
+ Q921T200TimerStart(trunk, tei);
+ }
+
+ /* increment counter */
+ link->N200++;
+
+ /* no state change */
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void Q921T203TimerExpire(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+ struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T203 expired for TEI %d (trunk TEI %d)\n", tei, trlink->tei);
+
+ /* Stop Timer first */
+ Q921T203TimerStop(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ /* Send Enquiry */
+ Q921SendEnquiry(trunk, tei);
+
+ /* RC = 0 */
+ link->N200 = 0;
+
+ /* no state change */
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void Q921T202TimerExpire(L2TRUNK trunk)
+{
+ struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+
+ Q921T202TimerReset(trunk);
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T202 expired for Q.921 trunk with TEI %d\n", link->tei);
+
+ /* todo: implement resend counter */
+
+ switch(link->state) {
+ case Q921_STATE_TEI_ASSIGNED: /* Tei identity verify timeout */
+ Q921TeiSendVerifyRequest(trunk);
+ break;
+
+ default: /* Tei assignment request timeout (TODO: refine) */
+
+ if(trunk->N202 >= trunk->N202Limit) {
+ /* Too many retransmits, reset counter, stop timer and handle case (TODO) */
+ trunk->N202 = 0;
+
+ Q921T202TimerStop(trunk);
+
+ return;
+ }
+ Q921TeiSendAssignRequest(trunk);
+
+ trunk->N202++;
+ }
+}
+
+static void Q921T201TimerExpire(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+ struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T201 expired for TEI %d (trunk TEI: %d)\n", tei, trlink->tei);
+
+ Q921T201TimerStop(trunk, tei);
+
+ /* NOTE: abusing N202 for this */
+ if(link->N202 < trunk->N202Limit) {
+ /* send check request */
+ Q921TeiSendCheckRequest(trunk, tei);
+
+ /* increment counter */
+ link->N202++;
+ } else {
+ /* put context in STOPPED state */
+ Q921ChangeState(trunk, Q921_STATE_STOPPED, tei);
+
+ /* NOTE: should we clear the link too? */
+ memset(link, 0, sizeof(struct Q921_Link));
+
+ /* mark TEI free */
+ trunk->tei_map[tei] = 0;
+ }
+}
+
+#ifdef __UNUSED_FOR_NOW__
+static void Q921TM01TimerExpire(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+ struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "TM01 expired for TEI %d (trunk TEI: %d)\n", tei, trlink->tei);
+
+ /* Restart TM01 */
+ Q921TM01TimerReset(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ case Q921_STATE_TIMER_RECOVERY:
+/*
+ * NT-only, needs more support from L3
+ */
+#if 0
+ /* No activity, shutdown link */
+ Q921SendDISC(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
+
+ /* clear I queue */
+ MFIFOClear(link->IFrameQueue);
+
+ /* change state */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_RELEASE, tei);
+#endif
+ break;
+
+ default:
+ break;
+ }
+}
+#endif
+
+/*
+ * Timer Tick function
+ */
+void Q921TimerTick(L2TRUNK trunk)
+{
+ struct Q921_Link *link;
+ L2ULONG tNow = Q921GetTime();
+ int numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
+ int x;
+
+ for(x = 0; x <= numlinks; x++) {
+ link = Q921_LINK_CONTEXT(trunk, x);
+
+ /* TODO: check if TEI is assigned and skip check if not (speedup!) */
+ if(link->state == Q921_STATE_STOPPED)
+ continue;
+
+ if (link->T200 && tNow > link->T200) {
+ Q921T200TimerExpire(trunk, link->tei);
+ }
+ if (link->T203 && tNow > link->T203) {
+ Q921T203TimerExpire(trunk, link->tei);
+ }
+
+ if(Q921_IS_PTMP_NT(trunk) && link->tei) {
+ if (link->T201 && tNow > link->T201) {
+ Q921T201TimerExpire(trunk, link->tei);
+ }
+ }
+
+ if(!Q921_IS_PTMP_NT(trunk)) {
+ if (trunk->T202 && tNow > trunk->T202) {
+ Q921T202TimerExpire(trunk);
+ }
+ }
+
+ /* Send enqueued I frame, if available */
+ Q921SendQueuedIFrame(trunk, link->tei);
+
+ /* Send ack if pending */
+ Q921AcknowledgePending(trunk, link->tei);
+ }
+
+}
+
+void Q921SetGetTimeCB(L2ULONG (*callback)(void))
+{
+ Q921GetTimeProc = callback;
+}
+
+/*****************************************************************************
+
+ Function: Q921QueueHDLCFrame
+
+ Description: Called to receive and queue an incoming HDLC frame. Will
+ queue this in Q921HDLCInQueue. The called must either call
+ Q921Rx12 directly afterwards or signal Q921Rx12 to be called
+ later. Q921Rx12 will read from the same queue and process
+ the frame.
+
+ This function assumes that the message contains header
+ space. This is removed for internal Q921 processing, but
+ must be keept for I frames.
+
+ Parameters: trunk trunk #
+ b ptr to frame;
+ size size of frame in bytes
+
+*****************************************************************************/
+int Q921QueueHDLCFrame(L2TRUNK trunk, L2UCHAR *b, L2INT size)
+{
+ return MFIFOWriteMes(trunk->HDLCInQueue, b, size);
+}
+
+/**
+ * Q921EnqueueI
+ * \brief Put I frame into transmit queue
+ *
+ */
+static int Q921EnqueueI(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR *mes, L2INT size)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
+
+ /* I frame header */
+ mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
+ mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
+ mes[trunk->Q921HeaderSpace+2] = 0x00;
+ mes[trunk->Q921HeaderSpace+3] = (pf & 0x01);
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Enqueueing I frame for TEI %d [%d]\n", link->tei, Tei);
+
+ /* transmit queue, (TODO: check for full condition!) */
+ MFIFOWriteMes(link->IFrameQueue, mes, size);
+
+ /* try to send queued frame */
+ Q921SendQueuedIFrame(trunk, link->tei);
+
+ return 1;
+}
+
+/**
+ * Q921SendQueuedIFrame
+ * \brief Try to transmit queued I frame (if available)
+ */
+static int Q921SendQueuedIFrame(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ L2INT size = 0;
+ L2UCHAR *mes;
+
+ if(MFIFOGetMesCount(link->IFrameQueue) == 0) {
+ return 0;
+ }
+
+ /* Link ready? */
+ if(link->state != Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+ return 0;
+ }
+
+ /* peer receiver busy? */
+ if(Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
+ return 0;
+ }
+
+ /* V(S) = V(A) + k? */
+ if(link->vs == ((link->va + trunk->k) % 128)) {
+ Q921Log(trunk, Q921_LOG_WARNING, "Maximum number (%d) of outstanding I frames reached for TEI %d\n", trunk->k, tei);
+ return 0;
+ }
+
+ mes = MFIFOGetMesPtr(link->IFrameQueue, &size);
+ if(mes) {
+ /* Fill in + update counter values */
+ mes[trunk->Q921HeaderSpace+2] = link->vs << 1;
+ mes[trunk->Q921HeaderSpace+3] |= link->vr << 1;
+
+ if(MFIFOGetMesCount(link->IFrameQueue) == 0) {
+ /* clear I frame queued */
+ }
+
+ /* Send I frame */
+ Q921Tx21Proc(trunk, mes, size);
+
+ /* V(S) = V(S) + 1 */
+ Q921_INC_COUNTER(link->vs);
+
+ /* clear acknowledge pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+ /* T200 running? */
+ if(!link->T200) {
+ /* Stop T203, Start T200 */
+ Q921T200TimerStart(trunk, tei);
+ Q921T203TimerStop(trunk, tei);
+ }
+
+ /* put frame into resend queue */
+ MFIFOWriteMesOverwrite(link->IFrameResendQueue, mes, size);
+
+ /* dequeue frame */
+ MFIFOKillNext(link->IFrameQueue);
+
+ /* Restart TM01 */
+ if(Q921_IS_NT(trunk)) {
+ Q921TM01TimerReset(trunk, tei);
+ }
+
+ /* no state change */
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Q921SendS
+ * \brief Prepare and send S frame
+ */
+static int Q921SendS(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR sv, L2UCHAR *mes, L2INT size)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
+
+ if(!Q921_IS_READY(link)) {
+ /* don't even bother trying */
+ Q921Log(trunk, Q921_LOG_DEBUG, "Link not ready, discarding S frame for TEI %d\n", Tei);
+ return 0;
+ }
+
+ /* S frame header */
+ mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
+ mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
+ mes[trunk->Q921HeaderSpace+2] = ((sv << 2) & 0x0c) | 0x01;
+ mes[trunk->Q921HeaderSpace+3] = (link->vr << 1) | (pf & 0x01);
+
+ return Q921Tx21Proc(trunk, mes, size);
+}
+
+
+/**
+ * Q921SendU
+ * \brief Prepare and send U frame
+ */
+static int Q921SendU(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR m, L2UCHAR *mes, L2INT size)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
+
+ /* U frame header */
+ mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
+ mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
+ mes[trunk->Q921HeaderSpace+2] = ((m << 3) & 0xe0) | ((pf << 4) & 0x10) | ((m << 2) & 0x0c) | 0x03;
+
+ /* link not ready? enqueue non-TEI-mgmt UI (DL-UNIT DATA) frames */
+ if(m == 0x00 && Sapi != Q921_SAPI_TEI && link->state < Q921_STATE_TEI_ASSIGNED) {
+
+ /* write frame to queue */
+ MFIFOWriteMes(link->UIFrameQueue, mes, size);
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Link not ready, UI Frame of size %d bytes queued for TEI %d\n", size, Tei);
+ return 1;
+ }
+
+ return Q921Tx21Proc(trunk, mes, size);
+}
+
+/**
+ * TODO: NT mode handling? Need a way to get Link context from Q.931
+ */
+int Q921Rx32(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR * Mes, L2INT Size)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei); /* TODO: need real link tei for NT mode */
+ L2INT res = 0;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Got frame from Q.931, type: %d, tei: %d, size: %d\n", ind, tei, Size);
+
+ switch(ind) {
+ case Q921_DL_ESTABLISH:
+ /*
+ * Hmm...
+ */
+ switch(link->state) {
+ case Q921_STATE_TEI_ASSIGNED:
+ if(!Q921_IS_NT(trunk)) {
+ /* establish data link */
+ Q921EstablishDataLink(trunk, link->tei);
+
+ /* Set layer 3 initiated */
+ Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
+ }
+ break;
+
+ case Q921_STATE_AWAITING_ESTABLISHMENT:
+ if(!Q921_IS_NT(trunk)) {
+ /* Discard I queue */
+ MFIFOClear(link->IFrameQueue);
+
+ /* Set layer 3 initiated */
+ Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
+ }
+ break;
+
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ case Q921_STATE_TIMER_RECOVERY:
+ if(!Q921_IS_NT(trunk)) {
+ /* Discard I queue */
+ MFIFOClear(link->IFrameQueue);
+
+ /* establish data link */
+ Q921EstablishDataLink(trunk, link->tei);
+
+ /* Set layer 3 initiated */
+ Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case Q921_DL_RELEASE:
+ switch(link->state) {
+ case Q921_STATE_TEI_ASSIGNED:
+ /* send DL-RELEASE confirm */
+ Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
+ break;
+
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ case Q921_STATE_TIMER_RECOVERY:
+ if(!Q921_IS_NT(trunk)) {
+ /* Discard I queue */
+ MFIFOClear(link->IFrameQueue);
+
+ /* RC = 0 */
+ link->N200 = 0;
+
+ /* send DISC command */
+ Q921SendDISC(trunk, trunk->sapi, Q921_COMMAND(trunk), link->tei, 1);
+
+ /* Stop T203, restart T200 */
+ if(link->state == Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+ Q921T203TimerStop(trunk, link->tei);
+ }
+ Q921T200TimerReset(trunk, link->tei);
+
+ /* change state */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_RELEASE, link->tei);
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case Q921_DL_DATA: /* DL-DATA request */
+ res = Q921EnqueueI(trunk,
+ trunk->sapi,
+ Q921_COMMAND(trunk),
+ link->tei,
+ 0,
+ Mes,
+ Size);
+
+ if(link->state < Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+ /* Treat as implicit DL-ESTABLISH request */
+
+ /* establish data link */
+ Q921EstablishDataLink(trunk, link->tei);
+
+ /* Set layer 3 initiated */
+ Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
+ }
+ break;
+
+ case Q921_DL_UNIT_DATA: /* DL-UNIT DATA request */
+ res = Q921SendUN(trunk,
+ trunk->sapi,
+ Q921_COMMAND(trunk),
+ Q921_TEI_BCAST,
+ 0,
+ Mes,
+ Size);
+ /* NOTE: Let the other side initiate link establishment */
+ break;
+
+ default:
+ break;
+ }
+
+ return res;
+}
+/*****************************************************************************
+
+ Function: Q921SendRR
+
+ Description: Compose and send Receive Ready.
+
+ Parameters: trunk trunk #
+ Sapi Sapi
+ cr C/R field.
+ Tei Tei.
+ pf P/F fiels octet 5
+
+ Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+
+static int Q921SendRR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+ L2UCHAR mes[25];
+
+ return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x00, mes, trunk->Q921HeaderSpace+4);
+}
+
+/*****************************************************************************
+
+ Function: Q921SendRNR
+
+ Description: Compose and send Receive Nor Ready
+
+ Parameters: trunk trunk #
+ Sapi Sapi
+ cr C/R field.
+ Tei Tei.
+ pf P/F fiels octet 5
+
+ Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendRNR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+ L2UCHAR mes[25];
+
+ return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x01, mes, trunk->Q921HeaderSpace+4);
+}
+
+/*****************************************************************************
+
+ Function: Q921SendREJ
+
+ Description: Compose and Send Reject.
+
+ Parameters: trunk trunk #
+ Sapi Sapi
+ cr C/R field.
+ Tei Tei.
+ pf P/F fiels octet 5
+
+ Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendREJ(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+ L2UCHAR mes[25];
+
+ return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x03, mes, trunk->Q921HeaderSpace+4);
+}
+
+/*****************************************************************************
+
+ Function: Q921SendSABME
+
+ Description: Compose and send SABME
+
+ Parameters: trunk trunk #
+ Sapi Sapi
+ cr C/R field.
+ Tei Tei.
+ pf P fiels octet 4
+
+ Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendSABME(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+ L2UCHAR mes[25];
+
+ return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x0f, mes, trunk->Q921HeaderSpace+3);
+}
+
+
+/**
+ * Q921Start
+ * \brief Start trunk
+ * \param[in] trunk pointer to Q921 data struct
+ * \return > 0 on success; <= 0 on error
+ */
+int Q921Start(L2TRUNK trunk)
+{
+ int x, numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
+ struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+
+ if(trunk->initialized != INITIALIZED_MAGIC)
+ return 0;
+
+ memset(trunk->context, 0, numlinks * sizeof(struct Q921_Link));
+
+ /* Common init part */
+ for(x = 0; x <= numlinks; x++) {
+ link = Q921_LINK_CONTEXT(trunk, x);
+
+ link->state = Q921_STATE_TEI_UNASSIGNED;
+ link->tei = 0;
+
+ /* Initialize per-TEI I + UI queues */
+ MFIFOCreate(link->UIFrameQueue, Q921MAXHDLCSPACE, 10);
+ MFIFOCreate(link->IFrameQueue, Q921MAXHDLCSPACE, 10);
+ MFIFOCreate(link->IFrameResendQueue, Q921MAXHDLCSPACE, 10);
+ }
+
+ if(Q921_IS_PTMP_TE(trunk)) {
+ link->state = Q921_STATE_TEI_UNASSIGNED;
+ link->tei = 0;
+ }
+ else if(Q921_IS_PTMP_NT(trunk)) {
+ link = Q921_TRUNK_CONTEXT(trunk);
+
+ link->state = Q921_STATE_TEI_ASSIGNED;
+ link->tei = trunk->tei;
+
+ /* clear tei map */
+ memset(trunk->tei_map, 0, Q921_TEI_MAX + 1);
+ }
+ else {
+ link->state = Q921_STATE_TEI_ASSIGNED;
+ link->tei = trunk->tei;
+ }
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Starting trunk %p (sapi: %d, tei: %d, mode: %s %s)\n",
+ trunk,
+ trunk->sapi,
+ link->tei,
+ Q921_IS_PTMP(trunk) ? "PTMP" : "PTP",
+ Q921_IS_TE(trunk) ? "TE" : "NT");
+
+ if(Q921_IS_PTP(trunk)) {
+ Q921Log(trunk, Q921_LOG_DEBUG, "Sending SABME\n");
+
+ return Q921SendSABME(trunk,
+ trunk->sapi,
+ Q921_COMMAND(trunk),
+ link->tei,
+ 1);
+
+ } else if(Q921_IS_PTMP_NT(trunk)) {
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Revoking all TEIs\n");
+
+ return Q921TeiSendRemoveRequest(trunk, Q921_TEI_BCAST); /* Revoke all TEIs in use */
+ } else {
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Requesting TEI\n");
+
+ return Q921TeiSendAssignRequest(trunk);
+ }
+}
+
+
+/**
+ * Q921Stop
+ * \brief Stop trunk
+ * \param[in] trunk pointer to Q921 data struct
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+int Q921Stop(L2TRUNK trunk)
+{
+ struct Q921_Link *link;
+ int x, numlinks;
+
+ if(!trunk)
+ return -1;
+
+ link = Q921_TRUNK_CONTEXT(trunk);
+ numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
+
+ if(Q921_IS_STOPPED(link))
+ return 0;
+
+ /* Release TEI */
+ if(Q921_IS_PTMP_TE(trunk)) {
+ /* send verify request */
+ Q921TeiSendVerifyRequest(trunk);
+
+ /* drop TEI */
+ link->tei = 0;
+ }
+
+ /* Stop timers, stop link, flush queues */
+ for(x = 0; x <= numlinks; x++) {
+ Q921T200TimerStop(trunk, x);
+ Q921T203TimerStop(trunk, x);
+ Q921T201TimerStop(trunk, x);
+
+ /* Change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_STOPPED, x);
+
+ /* Flush per-tei I/UI queues */
+ MFIFOClear(link->UIFrameQueue);
+ MFIFOClear(link->IFrameQueue);
+ MFIFOClear(link->IFrameResendQueue);
+ }
+ Q921T202TimerStop(trunk);
+
+ /* Flush HDLC queue */
+ MFIFOClear(trunk->HDLCInQueue);
+
+ return 0;
+}
+
+
+/*****************************************************************************
+
+ Function: Q921SendDM
+
+ Description: Compose and Send DM (Disconnected Mode)
+
+ Parameters: trunk trunk #
+ Sapi Sapi
+ cr C/R field.
+ Tei Tei.
+ pf F fiels octet 4
+
+ Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendDM(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+ L2UCHAR mes[25];
+
+ return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x03, mes, trunk->Q921HeaderSpace+3);
+}
+
+/*****************************************************************************
+
+ Function: Q921SendDISC
+
+ Description: Compose and Send Disconnect
+
+ Parameters: trunk trunk #
+ Sapi Sapi
+ cr C/R field.
+ Tei Tei.
+ pf P fiels octet 4
+
+ Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendDISC(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+ L2UCHAR mes[25];
+
+ return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x08, mes, trunk->Q921HeaderSpace+3);
+}
+
+/*****************************************************************************
+
+ Function: Q921SendUA
+
+ Description: Compose and Send UA
+
+ Parameters: trunk trunk #
+ Sapi Sapi
+ cr C/R field.
+ Tei Tei.
+ pf F fiels octet 4
+
+ Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendUA(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+ L2UCHAR mes[25];
+
+ return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x0c, mes, trunk->Q921HeaderSpace+3);
+}
+
+static int Q921SendUN(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf, L2UCHAR *mes, L2INT size)
+{
+ return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x00, mes, size+trunk->Q921HeaderSpace+3);
+}
+
+
+/**
+ * Q921ProcSABME
+ * \brief Handle incoming SABME
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success, <= 0 on error
+ */
+static int Q921ProcSABME(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR pf = (mes[2] & 0x10) >> 4; /* poll / final flag */
+ L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_TEI_ASSIGNED:
+ /* send UA */
+ Q921SendUA(trunk,
+ trunk->sapi,
+ Q921_RESPONSE(trunk), /* or command? */
+ tei, pf);
+
+ /* clear counters */
+ link->vr=0;
+ link->vs=0;
+ link->va=0;
+
+ /* TODO: send DL-Establish indication to Q.931 */
+ Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
+
+ /* start T203 */
+ Q921T203TimerStart(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+ break;
+
+ case Q921_STATE_AWAITING_ESTABLISHMENT:
+ /* send UA */
+ Q921SendUA(trunk,
+ trunk->sapi,
+ Q921_RESPONSE(trunk),
+ tei, pf);
+
+ /* no state change */
+ break;
+
+ case Q921_STATE_AWAITING_RELEASE:
+ /* send DM */
+ Q921SendDM(trunk,
+ trunk->sapi,
+ Q921_RESPONSE(trunk),
+ tei, pf);
+
+ /* no state change */
+ break;
+
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ case Q921_STATE_TIMER_RECOVERY:
+ /* send UA */
+ Q921SendUA(trunk,
+ trunk->sapi,
+ Q921_RESPONSE(trunk),
+ tei, pf);
+
+ /* clear exception conditions */
+ Q921ResetExceptionConditions(trunk, tei);
+
+ /* send MDL-Error indication */
+
+ /* V(S) == V(A) ? */
+ if(link->vs != link->va) {
+ /* clear I queue */
+ MFIFOClear(link->IFrameQueue);
+
+ /* DL-Establish indication */
+ Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
+ }
+
+ /* clear counters */
+ link->vr=0;
+ link->vs=0;
+ link->va=0;
+
+ /* Stop T200, start T203 */
+ Q921T200TimerStop(trunk, tei);
+ Q921T203TimerStart(trunk, tei);
+
+ /* state change only if in TIMER_RECOVERY state */
+ if(link->state == Q921_STATE_TIMER_RECOVERY)
+ Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+ break;
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+
+/**
+ * Q921ProcDM
+ * \brief Handle incoming DM
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success, <= 0 on error
+ */
+static int Q921ProcDM(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR pf = (mes[2] & 0x10) >> 4; /* poll / final flag */
+ L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_TEI_ASSIGNED:
+ if(!pf) {
+ /* to next state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ case Q921_STATE_AWAITING_ESTABLISHMENT:
+ case Q921_STATE_AWAITING_RELEASE:
+ if(pf) {
+ if(link->state == Q921_STATE_AWAITING_ESTABLISHMENT) {
+ /* Discard I queue */
+ MFIFOClear(link->IFrameQueue);
+ }
+
+ /* Send DL-Release indication to Q.931 */
+ Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
+
+ /* Stop T200 */
+ Q921T200TimerStop(trunk, tei);
+
+ /* Change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+ }
+ break;
+
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ if(pf) {
+ /* MDL-Error indication (B) */
+
+ /* no state change */
+ } else {
+ /* MDL-Error indication (E) */
+
+ /* establish data link */
+ Q921EstablishDataLink(trunk, tei);
+
+ /* clear L3 initiated */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+ /* change state (no action?) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ case Q921_STATE_TIMER_RECOVERY:
+ if(pf) {
+ /* MDL Error indication (B) */
+ } else {
+ /* MDL Error indication (E) */
+ }
+
+ /* establish data link */
+ Q921EstablishDataLink(trunk, tei);
+
+ /* clear layer 3 initiated */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+ /* change state */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ break;
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+/**
+ * Q921ProcUA
+ * \brief Handle incoming UA
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success, <= 0 on error
+ */
+static int Q921ProcUA(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR pf = (mes[2] & 0x10) >> 4; /* poll / final flag */
+ L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_TEI_ASSIGNED:
+ case Q921_STATE_TIMER_RECOVERY:
+ /* MDL Error indication (C, D) */
+ Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame in invalid state\n");
+ break;
+
+ case Q921_STATE_AWAITING_ESTABLISHMENT:
+ if(pf) {
+ /* TODO: other fancy stuff (see docs) */
+ if(Q921_CHECK_FLAG(link, Q921_FLAG_L3_INITIATED)) { /* layer3 initiated */
+ link->vr = 0;
+
+ /* DL-Establish confirm */
+ Q921Tx23Proc(trunk, Q921_DL_ESTABLISH_CONFIRM, tei, NULL, 0);
+
+ } else if(link->vs != link->va) {
+
+ /* discard I queue */
+ MFIFOClear(link->IFrameQueue);
+
+ /* DL-Establish indication */
+ Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
+ }
+
+ /* Stop T200, start T203 */
+ Q921T200TimerStop(trunk, tei);
+ Q921T203TimerStart(trunk, tei);
+
+ link->vs = 0;
+ link->va = 0;
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+ } else {
+ /* MDL Error indication (C, D) */
+ Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame is not a response to a request\n");
+
+ /* no state change */
+ }
+ break;
+
+ case Q921_STATE_AWAITING_RELEASE:
+ if(pf) {
+ /* DL Release confirm */
+ Q921Tx23Proc(trunk, Q921_DL_RELEASE_CONFIRM, tei, NULL, 0);
+
+ /* Stop T200 */
+ Q921T200TimerStop(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+ } else {
+ /* MDL Error indication (D) */
+ Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame is not a response to a request\n");
+
+ /* no state change */
+ }
+ break;
+
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ /* MDL Error indication (C, D) */
+ Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame in invalid state\n");
+
+ /* no state change */
+ break;
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+
+/**
+ * Q921ProcDISC
+ * \brief Handle incoming DISC
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success, <= 0 on error
+ */
+static int Q921ProcDISC(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR pf = (mes[2] & 0x10) >> 4; /* poll / final flag */
+ L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_TEI_ASSIGNED:
+ case Q921_STATE_AWAITING_ESTABLISHMENT:
+ /* Send DM */
+ Q921SendDM(trunk,
+ trunk->sapi,
+ Q921_RESPONSE(trunk),
+ tei, pf);
+
+ /* no state change */
+ break;
+
+ case Q921_STATE_AWAITING_RELEASE:
+ Q921SendUA(trunk,
+ trunk->sapi,
+ Q921_RESPONSE(trunk),
+ tei, pf);
+
+ /* no state change */
+ break;
+
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ case Q921_STATE_TIMER_RECOVERY:
+ /* Discard I queue */
+ MFIFOClear(link->IFrameQueue);
+
+ /* send UA */
+ Q921SendUA(trunk,
+ trunk->sapi,
+ Q921_RESPONSE(trunk),
+ tei, pf);
+
+ /* DL Release indication */
+ Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
+
+ /* Stop T200 */
+ Q921T200TimerStop(trunk, tei);
+
+ if(link->state == Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+ /* Stop T203 */
+ Q921T203TimerStop(trunk, tei);
+ }
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+ break;
+
+ default:
+ Q921Log(trunk, Q921_LOG_ERROR, "Invalid DISC received in state \"%s\" (%d)", Q921State2Name(link->state), link->state);
+ break;
+ }
+
+ return 1;
+}
+
+
+/**
+ * Q921ProcRR
+ * \brief Handle incoming RR
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success, <= 0 on error
+ */
+static int Q921ProcRR(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR cr = (mes[0] & 0x02) >> 1;
+ L2UCHAR pf = mes[3] & 0x01; /* poll / final flag */
+ L2UCHAR nr = (mes[3] >> 1);
+// L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
+ L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ /* clear receiver peer busy */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+ if (Q921_IS_COMMAND(trunk, cr)) { /* if this is a command */
+ if(pf) {
+ /* Enquiry response */
+ Q921SendEnquiryResponse(trunk, tei);
+ }
+ } else {
+ if(pf) {
+ /* MDL Error indication */
+ }
+ }
+
+ /* */
+ if(link->va <= nr && nr <= link->vs) {
+
+ if(nr == link->vs) {
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ /* Stop T200, restart T203 */
+ Q921T200TimerStop(trunk, tei);
+ Q921T203TimerReset(trunk, tei);
+
+ } else if(nr == link->va) {
+
+ /* do nothing */
+
+ } else {
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ /* Restart T200 */
+ Q921T200TimerReset(trunk, tei);
+ }
+ /* no state change */
+
+ } else {
+ /* N(R) Error recovery */
+ Q921NrErrorRecovery(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ case Q921_STATE_TIMER_RECOVERY:
+ /* clear receiver peer busy */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+ /* command + P? */
+ if(Q921_IS_COMMAND(trunk, cr) && pf) {
+ /* Enquiry response */
+ Q921SendEnquiryResponse(trunk, tei);
+ }
+
+ /* */
+ if(link->va <= nr && nr <= link->vs) {
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ if(!Q921_IS_COMMAND(trunk, cr) && pf) {
+ /* Stop T200, start T203 */
+ Q921T200TimerStop(trunk, tei);
+ Q921T203TimerStart(trunk, tei);
+
+ /* Invoke retransmission */
+ Q921InvokeRetransmission(trunk, tei, nr);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+ }
+ /* no state change otherwise */
+ } else {
+ /* N(R) Error recovery */
+ Q921NrErrorRecovery(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return 1;
+}
+
+
+/**
+ * Q921ProcREJ
+ * \brief Handle incoming REJ
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success, <= 0 on error
+ */
+static int Q921ProcREJ(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR cr = (mes[0] & 0x02) >> 1;
+ L2UCHAR pf = mes[3] & 0x01; /* poll / final flag */
+ L2UCHAR nr = (mes[3] >> 1);
+// L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
+ L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ /* clear receiver peer busy */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+ /* command? */
+ if(Q921_IS_COMMAND(trunk, cr)) {
+ if(pf) {
+ /* Enquiry response */
+ Q921SendEnquiryResponse(trunk, tei);
+ }
+ } else {
+ if(pf) {
+ /* MDL Error indication (A) */
+ }
+ }
+
+ /* */
+ if(link->va <= nr && nr <= link->vs) {
+
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ /* Stop T200, start T203 */
+ Q921T200TimerStop(trunk, tei);
+ Q921T203TimerStart(trunk, tei);
+
+ /* Invoke retransmission of frame >N(R) (?) */
+ Q921InvokeRetransmission(trunk, tei, nr);
+
+ /* no state change */
+ } else {
+ /* N(R) Error recovery */
+ Q921NrErrorRecovery(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ case Q921_STATE_TIMER_RECOVERY:
+ /* clear receiver peer busy */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+ /* command + P ? */
+ if(Q921_IS_COMMAND(trunk, cr) && pf) {
+ /* Enquiry response */
+ Q921SendEnquiryResponse(trunk, tei);
+ }
+
+ /* */
+ if(link->va <= nr && nr <= link->vs) {
+
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ if(!Q921_IS_COMMAND(trunk, cr) && pf) {
+ /* Stop T200, start T203 */
+ Q921T200TimerStop(trunk, tei);
+ Q921T203TimerStart(trunk, tei);
+
+ /* Invoke retransmission */
+ Q921InvokeRetransmission(trunk, tei, nr);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+ }
+ /* no state change otherwise */
+ } else {
+ /* N(R) Error recovery */
+ Q921NrErrorRecovery(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+
+/**
+ * Q921ProcRNR
+ * \brief Handle incoming RNR
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success, <= 0 on error
+ */
+static int Q921ProcRNR(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR cr = (mes[0] & 0x02) >> 1;
+ L2UCHAR pf = mes[3] & 0x01; /* poll / final flag */
+ L2UCHAR nr = (mes[3] >> 1);
+// L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
+ L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ /* set peer receiver busy */
+ Q921_SET_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+ /* command? */
+ if(Q921_IS_COMMAND(trunk, cr)) {
+ if(pf) {
+ /* Enquiry response */
+ Q921SendEnquiryResponse(trunk, tei);
+ }
+ } else {
+ if(pf) {
+ /* MDL Error indication (A) */
+ }
+ }
+
+ /* */
+ if(link->va <= nr && nr <= link->vs) {
+
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ /* Stop T203, restart T200 */
+ Q921T200TimerReset(trunk, tei);
+ Q921T203TimerStop(trunk, tei);
+
+ /* no state change */
+ } else {
+ /* N(R) Error recovery */
+ Q921NrErrorRecovery(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ case Q921_STATE_TIMER_RECOVERY:
+ /* set peer receiver busy */
+ Q921_SET_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+ /* command + P? */
+ if(Q921_IS_COMMAND(trunk, cr) && pf) {
+ /* Enquiry response */
+ Q921SendEnquiryResponse(trunk, tei);
+ }
+
+ /* */
+ if(link->va <= nr && nr <= link->vs) {
+
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ if(!Q921_IS_COMMAND(trunk, cr) && pf) {
+ /* Restart T200 */
+ Q921T200TimerReset(trunk, tei);
+
+ /* Invoke retransmission */
+ Q921InvokeRetransmission(trunk, tei, nr);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+ }
+ /* no state change otherwise */
+ } else {
+ /* N(R) Error recovery */
+ Q921NrErrorRecovery(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+#if 0
+static int Q921SetReceiverBusy(L2TRUNK trunk)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ if(!Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+ /* set own receiver busy */
+ Q921_SET_FLAG(link, Q921_FLAG_RECV_BUSY);
+
+ /* send RR response */
+ Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
+
+ /* clear ack pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+ }
+ break;
+
+ case Q921_STATE_TIMER_RECOVERY:
+ if(!Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+ /* set own receiver busy */
+ Q921_SET_FLAG(link, Q921_FLAG_RECV_BUSY);
+
+ /* send RNR response */
+ Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
+
+ /* clear ack pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int Q921ClearReceiverBusy(L2TRUNK trunk)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ case Q921_STATE_TIMER_RECOVERY:
+ if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+ /* clear own receiver busy */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_RECV_BUSY);
+
+ /* send RNR response */
+ Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
+
+ /* clear ack pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+#endif
+
+static int Q921ProcIFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ /* common fields: get sapi, tei and cr */
+// L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
+// L2UCHAR cr = (mes[0] & 0x02) >> 1;
+ L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+ L2UCHAR pf = mes[3] & 0x01; /* poll / final flag */
+ L2UCHAR nr = mes[3] >> 1; /* receive sequence number */
+ L2UCHAR ns = mes[2] >> 1; /* send sequence number */
+ L2UCHAR discard = 0;
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ /* Ignore I frames in earlier states */
+ if(link->state < Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+ Q921Log(trunk, Q921_LOG_NOTICE, "I frame in invalid state ignored\n");
+ return 0;
+ }
+
+ /* Receiver busy? */
+ if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+ /* discard information */
+ discard = 1;
+
+ if(pf) {
+ /* send RNR Response */
+ Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+
+ /* Clear ack pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+ }
+ }
+ else {
+ if(ns != link->vr) {
+ /* discard information */
+ discard = 1;
+
+ if(Q921_CHECK_FLAG(link, Q921_FLAG_REJECT) && pf) {
+
+ /* Send RR response */
+ Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+
+ /* clear ack pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+ }
+ else if(!Q921_CHECK_FLAG(link, Q921_FLAG_REJECT)){
+
+ /* set reject exception */
+ Q921_SET_FLAG(link, Q921_FLAG_REJECT);
+
+ /* Send REJ response */
+ Q921SendREJ(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, pf);
+
+ /* clear ack pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+ }
+ }
+ else {
+ /* V(R) = V(R) + 1 */
+ Q921_INC_COUNTER(link->vr);
+
+ /* clear reject exception */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_REJECT);
+
+ /* DL-Data indication */
+ Q921Tx23Proc(trunk, Q921_DL_DATA, tei, mes, size);
+
+ if(pf) {
+ /* Send RR response */
+ Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+
+ /* clear ack pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+ }
+ else if(!Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING)) {
+ /* ack pending */
+
+ /* Send RR response */
+ Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 0);
+
+ /* set ack pending*/
+ Q921_SET_FLAG(link, Q921_FLAG_ACK_PENDING);
+ }
+ }
+ }
+
+
+ switch(link->state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ if(link->va <= nr && nr <= link->vs) {
+ if(Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
+ link->va = nr;
+ }
+ else if(nr == link->vs) {
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ /* stop t200, restart t203 */
+ Q921T200TimerStop(trunk, tei);
+ Q921T203TimerReset(trunk, tei);
+ }
+ else if(nr != link->va) {
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ /* restart T200 */
+ Q921T200TimerReset(trunk, tei);
+ }
+
+ /* Restart TM01 */
+ if(Q921_IS_NT(trunk)) {
+ Q921TM01TimerReset(trunk, tei);
+ }
+ }
+ else {
+ /* N(R) error recovery */
+ Q921NrErrorRecovery(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ case Q921_STATE_TIMER_RECOVERY:
+ if(link->va <= nr && nr <= link->vs) {
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ /* Restart TM01 */
+ if(Q921_IS_NT(trunk)) {
+ Q921TM01TimerReset(trunk, tei);
+ }
+ }
+ else {
+ /* N(R) error recovery */
+ Q921NrErrorRecovery(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+static int Q921ProcSFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR sv = (mes[2] & 0x0c) >> 2; /* supervisory format id */
+ //L2UCHAR pf = mes[3] & 0x01; /* poll / final flag */
+ //L2UCHAR nr = mes[3] >> 1; /* receive sequence number */
+ L2INT res = -1;
+
+ switch(sv) {
+ case 0x00: /* RR : Receive Ready */
+ res = Q921ProcRR(trunk, mes, size);
+ break;
+
+ case 0x02: /* RNR : Receive Not Ready */
+ res = Q921ProcRNR(trunk, mes, size);
+ break;
+
+ case 0x04: /* REJ : Reject */
+ res = Q921ProcREJ(trunk, mes, size);
+ break;
+
+ default: /* Invalid / Unknown */
+ Q921Log(trunk, Q921_LOG_ERROR, "Invalid S frame type %d\n", sv);
+ break;
+ }
+
+ return res;
+}
+
+
+
+static int Q921ProcUFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR m = (mes[2] & 0xe0) >> 3 | (mes[2] & 0x0c) >> 2; /* modifier function id */
+// L2UCHAR pf = (mes[2] & 0x10) >> 4; /* poll / final flag */
+ L2INT res = -1;
+
+ switch(m) {
+ case 0x00: /* UN : Unnumbered Information */
+ if(mes[3] == Q921_LAYER_ENT_ID_TEI)
+ {
+ if(!Q921_IS_PTMP(trunk)) {
+ /* wtf? nice try */
+ return res;
+ }
+
+ switch(mes[6]) {
+ case Q921_TEI_ID_REQUEST: /* (TE ->) NT */
+ res = Q921TeiProcAssignRequest(trunk, mes, size);
+ break;
+
+ case Q921_TEI_ID_ASSIGNED: /* (NT ->) TE */
+ case Q921_TEI_ID_DENIED:
+ res = Q921TeiProcAssignResponse(trunk, mes, size);
+ break;
+
+ case Q921_TEI_ID_CHECKREQ: /* (NT ->) TE */
+ res = Q921TeiProcCheckRequest(trunk, mes, size);
+ break;
+
+ case Q921_TEI_ID_CHECKRESP: /* (TE ->) NT */
+ res = Q921TeiProcCheckResponse(trunk, mes, size);
+ break;
+
+ case Q921_TEI_ID_REMOVE: /* (NT ->) TE */
+ res = Q921TeiProcRemoveRequest(trunk, mes, size);
+ break;
+
+ case Q921_TEI_ID_VERIFY: /* (TE ->) NT */
+ res = Q921TeiProcVerifyRequest(trunk, mes, size);
+ break;
+
+ default: /* Invalid / Unknown */
+ Q921Log(trunk, Q921_LOG_ERROR, "Invalid UN message from TEI management/endpoint\n");
+ break;
+ }
+ }
+ else if(mes[3] == Q921_LAYER_ENT_ID_Q931) {
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "UI Frame for Layer 3 received\n");
+
+ res = Q921Tx23Proc(trunk, Q921_DL_UNIT_DATA, 0, mes, size);
+ }
+ break;
+
+ case 0x03: /* DM : Disconnect Mode */
+ res = Q921ProcDM(trunk, mes, size);
+ break;
+
+ case 0x08: /* DISC : Disconnect */
+ res = Q921ProcDISC(trunk, mes, size);
+ break;
+
+ case 0x0c: /* UA : Unnumbered Acknowledgement */
+ res = Q921ProcUA(trunk, mes, size);
+ break;
+
+ case 0x0f: /* SABME : Set Asynchronous Balanced Mode Extend */
+ res = Q921ProcSABME(trunk, mes, size);
+ break;
+
+ case 0x11: /* FRMR : Frame Reject */
+ case 0x17: /* XID : Exchange Identification */
+ res = 0;
+ break;
+
+ default: /* Unknown / Invalid */
+ Q921Log(trunk, Q921_LOG_ERROR, "Invalid U frame type: %d\n", m);
+ break;
+ }
+
+ return res;
+}
+
+
+/*****************************************************************************
+
+ Function: Q921Rx12
+
+ Description: Called to process a message frame from layer 1. Will
+ identify the message and call the proper 'processor' for
+ layer 2 messages and forward I frames to the layer 3 entity.
+
+ Q921Rx12 will check the input fifo for a message, and if a
+ message exist process one message before it exits. The caller
+ must either call Q921Rx12 polling or keep track on #
+ messages in the queue.
+
+ Parameters: trunk trunk #.
+
+ Return Value: # messages processed (always 1 or 0).
+
+*****************************************************************************/
+int Q921Rx12(L2TRUNK trunk)
+{
+ L2INT size; /* receive size & Q921 frame size*/
+ L2UCHAR *smes = MFIFOGetMesPtr(trunk->HDLCInQueue, &size);
+
+ if(smes)
+ {
+ struct Q921_Link *link;
+ L2UCHAR sapi, tei;
+ L2UCHAR *mes;
+ L2INT rs;
+
+ rs = size - trunk->Q921HeaderSpace;
+ mes = &smes[trunk->Q921HeaderSpace];
+
+ Q921LogMesg(trunk, Q921_LOG_DEBUG, 1, mes, rs, "New packet received (%d bytes)", rs);
+
+ /* common fields: get sapi, tei and cr */
+ sapi = (mes[0] & 0xfc) >> 2;
+ tei = (mes[1] & 0xfe) >> 1;
+ link = Q921_LINK_CONTEXT(trunk, tei);
+
+ if(Q921_IS_PTMP_TE(trunk) && (
+ (link->state >= Q921_STATE_TEI_ASSIGNED && tei != link->tei && tei != Q921_TEI_BCAST) || /* Assigned TEI: Only BCAST and directed */
+ (link->state == Q921_STATE_TEI_UNASSIGNED && tei != Q921_TEI_BCAST))) /* No assigned TEI: Only BCAST */
+ {
+ /* Ignore Messages with foreign TEIs */
+ goto out;
+ }
+
+ if((mes[2] & 0x01) == 0x00) { /* I frame */
+ Q921ProcIFrame(trunk, mes, rs);
+ }
+ else if((mes[2] & 0x03) == 0x01) { /* S frame */
+ Q921ProcSFrame(trunk, mes, rs);
+ }
+ else if((mes[2] & 0x03) == 0x03) { /* U frame */
+ Q921ProcUFrame(trunk, mes, rs);
+ }
+ else {
+ Q921Log(trunk, Q921_LOG_ERROR, "Invalid frame type: %d\n", (int)(mes[2] & 0x03));
+ /* TODO: send FRMR or REJ */
+ }
+
+out:
+ MFIFOKillNext(trunk->HDLCInQueue);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Misc
+ */
+/**
+ * Q921SetLogCB
+ * \brief Set logging callback
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] func pointer to logging callback function
+ * \param[in] priv pointer to private data
+ *
+ * \author Stefan Knoblich
+ */
+void Q921SetLogCB(L2TRUNK trunk, Q921LogCB_t func, void *priv)
+{
+ if(!trunk)
+ return;
+
+ trunk->Q921LogProc = func;
+ trunk->PrivateDataLog = priv;
+}
+
+/**
+ * Q921SetLogLevel
+ * \brief Set loglevel of Q.921 logging functions
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] level new loglevel
+ *
+ * \author Stefan Knoblich
+ */
+void Q921SetLogLevel(L2TRUNK trunk, Q921LogLevel_t level)
+{
+ if(!trunk)
+ return;
+
+ if (level < Q921_LOG_NONE) {
+ level = Q921_LOG_NONE;
+ } else if (level > Q921_LOG_DEBUG) {
+ level = Q921_LOG_DEBUG;
+ }
+
+ trunk->loglevel = level;
+}
+
+
+/**
+ * Q921ChangeState
+ * \brief Change state, invoke neccessary actions
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] state state to change to
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921ChangeState(L2TRUNK trunk, Q921State_t state, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+ Q921State_t oldstate = link->state;
+ int res = 0;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Changing state from \"%s\" (%d) to \"%s\" (%d) for TEI %d\n",
+ Q921State2Name(oldstate), oldstate,
+ Q921State2Name(state), state,
+ tei);
+
+ /*
+ * generic actions (depending on the target state only)
+ */
+ switch(state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ /* Start TM01 */
+ if(Q921_IS_NT(trunk)) {
+ Q921TM01TimerStart(trunk, tei);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * actions that depend on type of the old -> new state transition
+ */
+ switch(oldstate) {
+ case Q921_STATE_STOPPED:
+
+ switch(state) {
+ case Q921_STATE_TEI_UNASSIGNED:
+ if(Q921_IS_PTMP_TE(trunk)) {
+ res = Q921TeiSendAssignRequest(trunk);
+ }
+ break;
+
+ case Q921_STATE_TEI_ASSIGNED:
+ if(Q921_IS_PTMP_NT(trunk)) {
+ res = Q921TeiSendRemoveRequest(trunk, Q921_TEI_BCAST);
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ link->state = state;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Q921ChangeState() returns %d, new state is \"%s\" (%d) for TEI %d\n", res, Q921State2Name(state), state, tei);
+
+ return res;
+}
+
+/*
+ * TEI Management functions
+ * \note All TEI-mgmt UN frames are sent with cr = command!
+ */
+static int Q921TeiSend(L2TRUNK trunk, L2UCHAR type, L2USHORT ri, L2UCHAR ai)
+{
+ L2UCHAR mes[10];
+ L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+
+ mes[offset++] = Q921_LAYER_ENT_ID_TEI; /* layer management entity identifier */
+ mes[offset++] = (ri & 0xff00) >> 8; /* reference number upper part */
+ mes[offset++] = ri & 0xff; /* reference number lower part */
+ mes[offset++] = type; /* message type: Identity Request */
+ mes[offset++] = ai << 1 | 0x01; /* action indicator: TEI */
+
+ return Q921SendU(trunk, Q921_SAPI_TEI, Q921_COMMAND(trunk), Q921_TEI_BCAST, 0, 0x00, mes, offset);
+}
+
+
+/**
+ * Q921TeiSendAssignRequest
+ * \brief Ask for new TEI (TE mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \return > 0 on success, <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiSendAssignRequest(L2TRUNK trunk)
+{
+ struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+ L2INT res;
+
+ if (!Q921_IS_PTMP_TE(trunk)) /* only ptmp te mode*/
+ return 0;
+
+#ifndef WIN32
+ link->ri = (L2USHORT)(random() % 0xffff);
+#else
+ link->ri = (L2USHORT)(rand() % 0xffff); //todo
+#endif
+
+ /* send TEI assign request */
+ res = Q921TeiSend(trunk, Q921_TEI_ID_REQUEST, link->ri, Q921_TEI_BCAST);
+
+ /* start T202 */
+ Q921T202TimerStart(trunk);
+
+ return res;
+}
+
+
+/**
+ * Q921TeiProcessAssignResponse
+ * \brief Process assign response (TE mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiProcAssignResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+ L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+ L2USHORT ri = 0;
+
+ if (!Q921_IS_PTMP_TE(trunk)) /* PTMP TE only */
+ return 0;
+
+ ri = (mes[offset + 1] << 8) | mes[offset + 2];
+
+ if(ri != link->ri) {
+ /* hmmm ..., not our response i guess */
+ return 0;
+ }
+
+ switch(mes[offset + 3]) {
+ case Q921_TEI_ID_ASSIGNED:
+ /* Yay, use the new TEI and change state to assigned */
+ link->tei = mes[offset + 4] >> 1;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Assigned TEI %d, setting state to TEI_ASSIGNED\n", link->tei);
+
+ Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, link->tei);
+ break;
+
+ case Q921_TEI_ID_DENIED:
+ /* oops, what to do now? */
+ if ((mes[offset + 4] >> 1) == Q921_TEI_BCAST) {
+ /* No more free TEIs? this is bad */
+
+ //Q921TeiSendVerifyRequest(trunk, Q921_TEI_BCAST); /* TODO: does this work ?? */
+ } else {
+ /* other reason, this is fatal, shutdown link */
+ }
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "TEI assignment has been denied, reason: %s\n",
+ ((mes[offset +4] >> 1) == Q921_TEI_BCAST) ? "No free TEIs available" : "Unknown");
+
+ Q921ChangeState(trunk, Q921_STATE_TEI_UNASSIGNED, link->tei);
+ break;
+
+ default:
+ return 0;
+ }
+
+ /* stop T202 */
+ Q921T202TimerStop(trunk);
+
+ return 1;
+}
+
+
+/**
+ * Q921TeiSendVerifyRequest
+ * \brief Verify TEI (TE mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiSendVerifyRequest(L2TRUNK trunk)
+{
+ struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+ L2INT res;
+
+ if (!Q921_IS_PTMP_TE(trunk)) /* only ptmp te mode*/
+ return 0;
+
+ /* Request running? */
+ if (trunk->T202)
+ return 0;
+
+ /* Send TEI verify request */
+ res = Q921TeiSend(trunk, Q921_TEI_ID_VERIFY, link->ri, link->tei);
+
+ /* start T202 */
+ Q921T202TimerStart(trunk);
+
+ return res;
+}
+
+
+/**
+ * Q921TeiProcCheckRequest
+ * \brief Process Check Request (TE mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiProcCheckRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+ L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+ L2UCHAR tei = (mes[offset + 4] >> 1); /* action indicator => tei */
+ L2INT res = 0;
+
+ if (!Q921_IS_PTMP_TE(trunk)) /* ptmp te mode only */
+ return 0;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Received TEI Check request for TEI %d\n", tei);
+
+ if (tei == Q921_TEI_BCAST || tei == link->tei) {
+ /*
+ * Broadcast TEI check or for our assigned TEI
+ */
+
+ /* send TEI check reponse */
+ res = Q921TeiSend(trunk, Q921_TEI_ID_CHECKRESP, link->ri, link->tei);
+
+ Q921T202TimerStop(trunk);
+ }
+
+ return res;
+}
+
+
+/**
+ * Q921TeiProcRemoveRequest
+ * \brief Process remove Request (TE mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiProcRemoveRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+ L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+ L2UCHAR tei = (mes[offset + 4] >> 1); /* action indicator => tei */
+ L2INT res = 0;
+
+ if (!Q921_IS_PTMP_TE(trunk)) /* ptmp te mode only */
+ return 0;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Received TEI Remove request for TEI %d\n", tei);
+
+ if (tei == Q921_TEI_BCAST || tei == link->tei) {
+ /*
+ * Broadcast TEI remove or for our assigned TEI
+ */
+
+ /* reset tei */
+ link->tei = 0;
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_TEI_UNASSIGNED, link->tei);
+
+ /* TODO: hmm, request new one ? */
+ res = Q921TeiSendAssignRequest(trunk);
+ }
+ return res;
+}
+
+
+/**
+ * Q921TeiProcAssignRequest
+ * \brief Process assign request from peer (NT mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiProcAssignRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+ L2USHORT ri = 0;
+ L2UCHAR tei = 0;
+
+ if (!Q921_IS_PTMP_NT(trunk)) /* PTMP NT only */
+ return 0;
+
+ ri = (mes[offset + 1] << 8) | mes[offset + 2];
+ tei = mes[offset + 4] >> 1;
+
+ if(tei == Q921_TEI_BCAST) {
+ int x;
+
+ /* dynamically allocate TEI */
+ for(x = Q921_TEI_DYN_MIN, tei = 0; x <= Q921_TEI_MAX; x++) {
+ if(!trunk->tei_map[x]) {
+ tei = x;
+ break;
+ }
+ }
+ }
+ else if(!(tei > 0 && tei < Q921_TEI_DYN_MIN)) {
+ /* reject TEIs that are not in the static area */
+ Q921TeiSendDenyResponse(trunk, 0, ri);
+
+ return 0;
+ }
+
+ if(!tei) {
+ /* no free TEI found */
+ Q921TeiSendDenyResponse(trunk, Q921_TEI_BCAST, ri);
+ }
+ else {
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ /* mark used */
+ trunk->tei_map[tei] = 1;
+
+ /* assign tei */
+ link->tei = tei;
+
+ /* put context in TEI ASSIGNED state */
+ Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+
+ /* send assign response */
+ Q921TeiSendAssignedResponse(trunk, tei, ri);
+
+ /* Start T201 */
+ Q921T201TimerStart(trunk, tei);
+ }
+ return 0;
+}
+
+/**
+ * Q921TeiSendCheckRequest
+ * \brief Send check request (NT mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] tei TEI to check
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiSendCheckRequest(L2TRUNK trunk, L2UCHAR tei)
+{
+ L2INT res = 0;
+
+ if (!Q921_IS_PTMP_NT(trunk)) /* PTMP NT only */
+ return 0;
+
+ /* send TEI check request */
+ res = Q921TeiSend(trunk, Q921_TEI_ID_CHECKREQ, 0, tei);
+
+ /* (Re-)Start T201 timer */
+ Q921T201TimerStart(trunk, tei);
+
+ return res;
+}
+
+/**
+ * Q921TeiProcCheckResponse
+ * \brief Process Check Response (NT mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiProcCheckResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ struct Q921_Link *link;
+ L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+ L2USHORT ri = 0;
+ L2UCHAR tei = 0;
+
+ if (!Q921_IS_PTMP_NT(trunk)) /* PTMP NT mode only */
+ return 0;
+
+ ri = (mes[offset + 1] << 8) | mes[offset + 2];
+ tei = mes[offset + 4] >> 1;
+
+ /* restart T201 */
+ Q921T201TimerStop(trunk, tei);
+
+ /* reset counter */
+ link = Q921_LINK_CONTEXT(trunk, tei);
+ link->N202 = 0;
+
+ if(!(tei > 0 && tei < Q921_TEI_MAX) || !trunk->tei_map[tei]) {
+ /* TODO: Should we send a DISC first? */
+
+ /* TEI not assigned? Invalid TEI? */
+ Q921TeiSendRemoveRequest(trunk, tei);
+
+ /* change state */
+ Q921ChangeState(trunk, Q921_STATE_STOPPED, tei);
+
+ /* clear */
+ memset(link, 0, sizeof(struct Q921_Link));
+ } else {
+ /* Start T201 */
+ Q921T201TimerStart(trunk, tei);
+ }
+
+ return 0;
+}
+
+
+/**
+ * Q921TeiProcVerifyRequest
+ * \brief Process Verify Request (NT mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiProcVerifyRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR resp[25];
+ L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+ L2UCHAR tei = 0;
+
+ if (!Q921_IS_PTMP_NT(trunk)) /* PTMP NT mode only */
+ return 0;
+
+ tei = mes[offset + 4] >> 1;
+
+ /* todo: handle response... verify assigned TEI */
+ resp[offset + 0] = 0;
+
+ return 0;
+}
+
+/**
+ * Q921TeiSendDenyResponse
+ * \brief Send Deny Response (NT mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiSendDenyResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri)
+{
+ if (!Q921_IS_PTMP_NT(trunk)) /* PTMP NT only */
+ return 0;
+
+ return Q921TeiSend(trunk, Q921_TEI_ID_DENIED, ri, tei);
+}
+
+
+/**
+ * Q921TeiSendAssignedResponse
+ * \brief Send Assigned Response (NT mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] tei TEI to assign
+ * \param[in] ri RI of request
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiSendAssignedResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri)
+{
+ if (!Q921_IS_PTMP_NT(trunk)) /* PTMP NT only */
+ return 0;
+
+ return Q921TeiSend(trunk, Q921_TEI_ID_ASSIGNED, ri, tei);
+}
+
+/**
+ * Q921TeiSendRemoveRequest
+ * \brief Send Remove Request (NT mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] tei TEI to remove
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiSendRemoveRequest(L2TRUNK trunk, L2UCHAR tei)
+{
+ if (!Q921_IS_PTMP_NT(trunk)) /* PTMP NT only */
+ return 0;
+
+ return Q921TeiSend(trunk, Q921_TEI_ID_REMOVE, 0, tei);
+}
Added: freeswitch/trunk/libs/freetdm/src/isdn/Q931.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/Q931.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/Q931.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,888 @@
+/*****************************************************************************
+
+ FileName: Q931.c
+
+ Contents: Implementation of Q.931 stack main interface functions.
+ See q931.h for description.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "Q921.h"
+#include "Q931.h"
+#include "national.h"
+#include "DMS.h"
+#include "5ESS.h"
+
+
+/*****************************************************************************
+
+ Dialect function pointers tables.
+
+ The following function pointer arrays define pack/unpack functions and
+ processing furnctions for the different Q.931 based dialects.
+
+ The arrays are initialized with pointers to dummy functions and later
+ overrided with pointers to actual functions as new dialects are added.
+
+ The initial Q.931 will as an example define 2 dialects as it treats User
+ and Network mode as separate ISDN dialects.
+
+ The API messages Q931AddProc, Q931AddMes, Q931AddIE are used to initialize
+ these table entries during system inititialization of a stack.
+
+*****************************************************************************/
+q931proc_func_t *Q931Proc[Q931MAXDLCT][Q931MAXMES];
+
+q931umes_func_t *Q931Umes[Q931MAXDLCT][Q931MAXMES];
+q931pmes_func_t *Q931Pmes[Q931MAXDLCT][Q931MAXMES];
+
+q931uie_func_t *Q931Uie[Q931MAXDLCT][Q931MAXIE];
+q931pie_func_t *Q931Pie[Q931MAXDLCT][Q931MAXIE];
+
+q931timeout_func_t *Q931Timeout[Q931MAXDLCT][Q931MAXTIMER];
+q931timer_t Q931Timer[Q931MAXDLCT][Q931MAXTIMER];
+
+void (*Q931CreateDialectCB[Q931MAXDLCT])(L3UCHAR iDialect) = { NULL, NULL };
+
+Q931State Q931st[Q931MAXSTATE];
+
+/*****************************************************************************
+
+ Core system tables and variables.
+
+*****************************************************************************/
+
+L3INT Q931L4HeaderSpace = {0}; /* header space to be ignoder/inserted */
+ /* at head of each message. */
+
+L3INT Q931L2HeaderSpace = {4}; /* Q921 header space, sapi, tei etc */
+
+/*****************************************************************************
+
+ Main interface callback functions.
+
+*****************************************************************************/
+
+Q931ErrorCB_t Q931ErrorProc; /* callback for error messages. */
+L3ULONG (*Q931GetTimeProc) (void) = NULL; /* callback for func reading time in ms */
+
+/*****************************************************************************
+
+ Function: Q931SetL4HeaderSpace
+
+ Description: Set the # of bytes to be inserted/ignored at the head of
+ each message. Q931 will issue a message with space for header
+ and the user will use this to fill in whatever header info
+ is required to support the architecture used.
+
+*****************************************************************************/
+void Q931SetL4HeaderSpace(L3INT space)
+{
+ Q931L4HeaderSpace = space;
+}
+
+/*****************************************************************************
+
+ Function: Q931SetL2HeaderSpace
+
+ Description: Set the # of bytes to be inserted/ignored at the head of
+ each message. Q931 will issue a message with space for header
+ and the user will use this to fill in whatever header info
+ is required to support the architecture used.
+
+*****************************************************************************/
+void Q931SetL2HeaderSpace(L3INT space)
+{
+ Q931L2HeaderSpace = space;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcDummy
+
+ Description: Dummy function for message processing.
+
+*****************************************************************************/
+L3INT Q931ProcDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b,L3INT c)
+{
+ return Q931E_INTERNAL;
+}
+
+/*****************************************************************************
+
+ Function: Q931UmesDummy
+
+ Description: Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931UmesDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size)
+{
+ return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+ Function: Q931UieDummy
+
+ Description: Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931UieDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ return Q931E_UNKNOWN_IE;
+}
+
+/*****************************************************************************
+
+ Function: Q931PmesDummy
+
+ Description: Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931PmesDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+ Function: Q931PieDummy
+
+ Description: Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931PieDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ return Q931E_UNKNOWN_IE;
+}
+
+/*****************************************************************************
+
+ Function: Q931TxDummy
+
+ Description: Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931TxDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT n)
+{
+ return Q931E_MISSING_CB;
+}
+
+/*****************************************************************************
+
+ Function: Q931ErrorDummy
+
+ Description: Dummy function for error processing
+
+*****************************************************************************/
+L3INT Q931ErrorDummy(void *priv, L3INT a, L3INT b, L3INT c)
+{
+ return 0;
+}
+
+/*****************************************************************************
+
+ Function: Q931Initialize
+
+ Description: This function Initialize the stack.
+
+ Will set up the trunk array, channel
+ arrays and initialize Q931 function arrays before it finally
+ set up EuroISDN processing with User as dialect 0 and
+ Network as dialect 1.
+
+ Note: Initialization of other stacks should be inserted after
+ the initialization of EuroISDN.
+
+*****************************************************************************/
+void Q931Initialize()
+{
+ L3INT x,y;
+
+ /* Secure the callbacks to default procs */
+ Q931ErrorProc = Q931ErrorDummy;
+
+ /* The user will only add the message handlers and IE handlers he need,
+ * so we need to initialize every single entry to a default function
+ * that will throw an appropriate error if they are ever called.
+ */
+ for (x = 0; x < Q931MAXDLCT; x++) {
+ for (y = 0; y < Q931MAXMES; y++) {
+ Q931Proc[x][y] = Q931ProcDummy;
+ Q931Umes[x][y] = Q931UmesDummy;
+ Q931Pmes[x][y] = Q931PmesDummy;
+ }
+ for (y = 0; y < Q931MAXIE; y++) {
+ Q931Pie[x][y] = Q931PieDummy;
+ Q931Uie[x][y] = Q931UieDummy;
+ }
+ for (y = 0; y < Q931MAXTIMER; y++) {
+ Q931Timeout[x][y] = Q931TimeoutDummy;
+ Q931Timer[x][y] = 0;
+ }
+ }
+
+ if (Q931CreateDialectCB[Q931_Dialect_Q931 + Q931_TE] == NULL)
+ Q931AddDialect(Q931_Dialect_Q931 + Q931_TE, Q931CreateTE);
+
+ if (Q931CreateDialectCB[Q931_Dialect_Q931 + Q931_NT] == NULL)
+ Q931AddDialect(Q931_Dialect_Q931 + Q931_NT, Q931CreateNT);
+
+ if (Q931CreateDialectCB[Q931_Dialect_National + Q931_TE] == NULL)
+ Q931AddDialect(Q931_Dialect_National + Q931_TE, nationalCreateTE);
+
+ if (Q931CreateDialectCB[Q931_Dialect_National + Q931_NT] == NULL)
+ Q931AddDialect(Q931_Dialect_National + Q931_NT, nationalCreateNT);
+
+ if (Q931CreateDialectCB[Q931_Dialect_DMS + Q931_TE] == NULL)
+ Q931AddDialect(Q931_Dialect_DMS + Q931_TE, DMSCreateTE);
+
+ if (Q931CreateDialectCB[Q931_Dialect_DMS + Q931_NT] == NULL)
+ Q931AddDialect(Q931_Dialect_DMS + Q931_NT, DMSCreateNT);
+
+ if (Q931CreateDialectCB[Q931_Dialect_5ESS + Q931_TE] == NULL)
+ Q931AddDialect(Q931_Dialect_5ESS + Q931_TE, ATT5ESSCreateTE);
+
+ if (Q931CreateDialectCB[Q931_Dialect_5ESS + Q931_NT] == NULL)
+ Q931AddDialect(Q931_Dialect_5ESS + Q931_NT, ATT5ESSCreateNT);
+
+ /* The last step we do is to call the callbacks to create the dialects */
+ for (x = 0; x < Q931MAXDLCT; x++) {
+ if (Q931CreateDialectCB[x] != NULL) {
+ Q931CreateDialectCB[x]((L3UCHAR)x);
+ }
+ }
+}
+
+/**
+ * Q931TimerTick
+ * \brief Periodically called to update and check for expired timers
+ * \param pTrunk Q.931 trunk
+ */
+void Q931TimerTick(Q931_TrunkInfo_t *pTrunk)
+{
+ struct Q931_Call *call = NULL;
+ L3ULONG now = 0;
+ L3INT x;
+
+ /* TODO: Loop through all active calls, check timers and call timout procs
+ * if timers are expired.
+ * Implement a function array so each dialect can deal with their own
+ * timeouts.
+ */
+ now = Q931GetTime();
+
+ for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
+ call = &pTrunk->call[x];
+
+ if (!call->InUse || !call->Timer || !call->TimerID)
+ continue;
+
+ if (call->Timer <= now) {
+ /* Stop Timer */
+ Q931StopTimer(pTrunk, x, call->TimerID);
+
+ /* Invoke dialect timeout callback */
+ Q931Timeout[pTrunk->Dialect][call->TimerID](pTrunk, x);
+ }
+ }
+}
+
+/*****************************************************************************
+
+ Function: Q931Rx23
+
+ Description: Receive message from layer 2 (LAPD). Receiving a message
+ is always done in 2 steps. First the message must be
+ interpreted and translated to a static struct. Secondly
+ the message is processed and responded to.
+
+ The Q.931 message contains a static header that is
+ interpreted in this function. The rest is interpreted
+ in a sub function according to mestype.
+
+ Parameters: pTrunk [IN] Ptr to trunk info.
+ buf [IN] Ptr to buffer containing message.
+ Size [IN] Size of message.
+
+ Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+ see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931Rx23(Q931_TrunkInfo_t *pTrunk, L3INT ind, L3UCHAR tei, L3UCHAR * buf, L3INT Size)
+{
+ L3UCHAR *Mes = NULL;
+ L3INT RetCode = Q931E_NO_ERROR;
+ Q931mes_Generic *m = (Q931mes_Generic *) pTrunk->L3Buf;
+ L3INT ISize;
+ L3INT IOff = 0;
+ L3INT L2HSize = Q931L2HeaderSpace;
+
+ switch (ind) {
+ case Q921_DL_UNIT_DATA: /* DL-UNITDATA indication (UI frame, 3 byte header) */
+ L2HSize = 3;
+
+ case Q921_DL_DATA: /* DL-DATA indication (I frame, 4 byte header) */
+ /* Reset our decode buffer */
+ memset(pTrunk->L3Buf, 0, sizeof(pTrunk->L3Buf));
+
+ /* L2 Header Offset */
+ Mes = &buf[L2HSize];
+
+ /* Protocol Discriminator */
+ m->ProtDisc = Mes[IOff++];
+
+ /* CRV */
+ m->CRVFlag = (Mes[IOff + 1] >> 7) & 0x01;
+ m->CRV = Q931Uie_CRV(pTrunk, Mes, m->buf, &IOff, &ISize);
+
+ /* Message Type */
+ m->MesType = Mes[IOff++];
+
+ /* Store tei */
+ m->Tei = tei;
+
+ /* d'oh a little ugly but this saves us from:
+ * a) doing Q.921 work in the lower levels (extracting the TEI ourselves)
+ * b) adding a tei parameter to _all_ Proc functions
+ */
+ if (tei) {
+ L3INT callIndex = 0;
+
+ /* Find the call using CRV */
+ RetCode = Q931FindCRV(pTrunk, m->CRV, &callIndex);
+ if (RetCode == Q931E_NO_ERROR && !pTrunk->call[callIndex].Tei) {
+ pTrunk->call[callIndex].Tei = tei;
+ }
+ }
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Received message from Q.921 (ind %d, tei %d, size %d)\nMesType: %d, CRVFlag %d (%s), CRV %d (Dialect: %d)\n", ind, m->Tei, Size,
+ m->MesType, m->CRVFlag, m->CRVFlag ? "Terminator" : "Originator", m->CRV, pTrunk->Dialect);
+
+ RetCode = Q931Umes[pTrunk->Dialect][m->MesType](pTrunk, Mes, (Q931mes_Generic *)pTrunk->L3Buf, IOff, Size - L2HSize);
+ if (RetCode >= Q931E_NO_ERROR) {
+ RetCode = Q931Proc[pTrunk->Dialect][m->MesType](pTrunk, pTrunk->L3Buf, 2);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q931Tx34
+
+ Description: Called from the stack to send a message to layer 4.
+
+ Parameters: Mes[IN] Ptr to message buffer.
+ Size[IN] Message size in bytes.
+
+ Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+ see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931Tx34(Q931_TrunkInfo_t *pTrunk, L3UCHAR * Mes, L3INT Size)
+{
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Sending message to Layer4 (size: %d)\n", Size);
+
+ if (pTrunk->Q931Tx34CBProc) {
+ return pTrunk->Q931Tx34CBProc(pTrunk->PrivateData34, Mes, Size);
+ }
+ return Q931E_MISSING_CB;
+}
+
+/*****************************************************************************
+
+ Function: Q931Rx43
+
+ Description: Receive message from Layer 4 (application).
+
+ Parameters: pTrunk[IN] Trunk #.
+ buf[IN] Message Pointer.
+ Size[IN] Message size in bytes.
+
+ Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+ see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931Rx43(Q931_TrunkInfo_t *pTrunk,L3UCHAR * buf, L3INT Size)
+{
+ Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+ L3INT RetCode = Q931E_NO_ERROR;
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Receiving message from Layer4 (size: %d, type: %d)\n", Size, ptr->MesType);
+
+ RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Q931Rx43 return code: %d\n", RetCode);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q931Tx32
+
+ Description: Called from the stack to send a message to L2. The input is
+ always a non-packed message so it will first make a proper
+ call to create a packed message before it transmits that
+ message to layer 2.
+
+ Parameters: pTrunk[IN] Trunk #
+ buf[IN] Ptr to message buffer.
+ Size[IN] Message size in bytes.
+
+ Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+ see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931Tx32Data(Q931_TrunkInfo_t *pTrunk, L3UCHAR bcast, L3UCHAR * Mes, L3INT Size)
+{
+ Q931mes_Generic *ptr = (Q931mes_Generic*)Mes;
+ L3INT RetCode = Q931E_NO_ERROR;
+ L3INT iDialect = pTrunk->Dialect;
+ L3INT Offset = bcast ? (Q931L2HeaderSpace - 1) : Q931L2HeaderSpace;
+ L3INT OSize;
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Sending message to Q.921 (size: %d)\n", Size);
+
+ memset(pTrunk->L2Buf, 0, sizeof(pTrunk->L2Buf));
+
+ /* Call pack function through table. */
+ RetCode = Q931Pmes[iDialect][ptr->MesType](pTrunk, (Q931mes_Generic *)Mes, Size, &pTrunk->L2Buf[Offset], &OSize);
+ if (RetCode >= Q931E_NO_ERROR) {
+ L3INT callIndex;
+ L3UCHAR tei = 0;
+
+ if (ptr->CRV) {
+ /* Find the call using CRV */
+ RetCode = Q931FindCRV(pTrunk, ptr->CRV, &callIndex);
+ if (RetCode != Q931E_NO_ERROR)
+ return RetCode;
+
+ tei = pTrunk->call[callIndex].Tei;
+ }
+
+ if (pTrunk->Q931Tx32CBProc) {
+ RetCode = pTrunk->Q931Tx32CBProc(pTrunk->PrivateData32, bcast ? Q921_DL_UNIT_DATA : Q921_DL_DATA, tei, pTrunk->L2Buf, OSize + Offset);
+ } else {
+ RetCode = Q931E_MISSING_CB;
+ }
+ }
+
+ return RetCode;
+}
+
+
+/*****************************************************************************
+
+ Function: Q931SetError
+
+ Description: Called from the stack to indicate an error.
+
+ Parameters: ErrID ID of ie or message causing error.
+ ErrPar1 Error parameter 1
+ ErrPar2 Error parameter 2.
+
+
+*****************************************************************************/
+void Q931SetError(Q931_TrunkInfo_t *pTrunk,L3INT ErrID, L3INT ErrPar1, L3INT ErrPar2)
+{
+ if (pTrunk->Q931ErrorCBProc) {
+ pTrunk->Q931ErrorCBProc(pTrunk->PrivateData34, ErrID, ErrPar1, ErrPar2);
+ } else {
+ Q931ErrorProc(pTrunk->PrivateData34, ErrID, ErrPar1, ErrPar2);
+ }
+}
+
+void Q931SetDefaultErrorCB(Q931ErrorCB_t Q931ErrorPar)
+{
+ Q931ErrorProc = Q931ErrorPar;
+}
+
+/*****************************************************************************
+
+ Function: Q931CreateCRV
+
+ Description: Create a CRV entry and return it's index. The function will
+ locate a free entry in the call tables allocate it and
+ allocate a unique CRV value attached to it.
+
+ Parameters: pTrunk [IN] Trunk number
+ callindex [OUT] return call table index.
+
+ Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+ see q931errors.h for details.
+****************************************************************************/
+L3INT Q931CreateCRV(Q931_TrunkInfo_t *pTrunk, L3INT * callIndex)
+{
+ L3INT CRV = Q931GetUniqueCRV(pTrunk);
+
+ return Q931AllocateCRV(pTrunk, CRV, callIndex);
+}
+
+
+L3INT Q931ReleaseCRV(Q931_TrunkInfo_t *pTrunk, L3INT CRV)
+{
+ int callIndex;
+
+ if ((Q931FindCRV(pTrunk, CRV, &callIndex)) == Q931E_NO_ERROR) {
+ pTrunk->call[callIndex].InUse = 0;
+ return Q931E_NO_ERROR;
+ }
+
+ return Q931E_INVALID_CRV;
+}
+
+/*****************************************************************************
+
+ Function: Q931AllocateCRV
+
+ Description: Allocate a call table entry and assigns the given CRV value
+ to it.
+
+ Parameters: pTrunk [IN] Trunk number
+ iCRV [IN] Call Reference Value.
+ callindex [OUT] return call table index.
+
+ Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+ see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931AllocateCRV(Q931_TrunkInfo_t *pTrunk, L3INT iCRV, L3INT * callIndex)
+{
+ L3INT x;
+ for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
+ if (!pTrunk->call[x].InUse) {
+ pTrunk->call[x].CRV = iCRV;
+ pTrunk->call[x].BChan = 255;
+ pTrunk->call[x].State = 0; /* null state - idle */
+ pTrunk->call[x].TimerID = 0; /* no timer running */
+ pTrunk->call[x].Timer = 0;
+ pTrunk->call[x].InUse = 1; /* mark as used */
+ *callIndex = x;
+ return Q931E_NO_ERROR;
+ }
+ }
+ return Q931E_TOMANYCALLS;
+}
+
+/*****************************************************************************
+
+ Function: Q931GetCallState
+
+ Description: Look up CRV and return current call state. A non existing
+ CRV is the same as state zero (0).
+
+ Parameters: pTrunk [IN] Trunk number.
+ iCRV [IN] CRV
+
+ Return Value: Call State.
+
+*****************************************************************************/
+L3INT Q931GetCallState(Q931_TrunkInfo_t *pTrunk, L3INT iCRV)
+{
+ L3INT x;
+ for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
+ if (pTrunk->call[x].InUse) {
+ if (pTrunk->call[x].CRV == iCRV) {
+ return pTrunk->call[x].State;
+ }
+ }
+ }
+ return 0; /* assume state zero for non existing CRV's */
+}
+
+/**
+ * Q931StartTimer
+ * \brief Start a timer
+ * \param pTrunk Q.931 trunk
+ * \param callindex Index of the call
+ * \param iTimerID ID of timer
+ * \return always 0
+ */
+L3INT Q931StartTimer(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3USHORT iTimerID)
+{
+#if 0
+ L3ULONG duration = Q931Timer[pTrunk->Dialect][iTimerID];
+
+ if (duration) {
+ pTrunk->call[callIndex].Timer = Q931GetTime() + duration;
+ pTrunk->call[callIndex].TimerID = iTimerID;
+ }
+#endif
+ return 0;
+}
+
+/**
+ * Q931StopTimer
+ * \brief Stop a timer
+ * \param pTrunk Q.931 trunk
+ * \param callindex Index of the call
+ * \param iTimerID ID of timer
+ * \return always 0
+ */
+L3INT Q931StopTimer(Q931_TrunkInfo_t *pTrunk, L3INT callindex, L3USHORT iTimerID)
+{
+ if (pTrunk->call[callindex].TimerID == iTimerID)
+ pTrunk->call[callindex].TimerID = 0;
+
+ return 0;
+}
+
+L3INT Q931SetState(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3INT iState)
+{
+ pTrunk->call[callIndex].State = iState;
+
+ return 0;
+}
+
+L3ULONG Q931GetTime()
+{
+ L3ULONG tNow = 0;
+ static L3ULONG tLast = 0;
+
+ if (Q931GetTimeProc != NULL) {
+ tNow = Q931GetTimeProc();
+ if (tNow < tLast) { /* wrapped */
+ /* TODO */
+ }
+ tLast = tNow;
+ }
+ return tNow;
+}
+
+void Q931SetGetTimeCB(L3ULONG (*callback)(void))
+{
+ Q931GetTimeProc = callback;
+}
+
+L3INT Q931FindCRV(Q931_TrunkInfo_t *pTrunk, L3INT crv, L3INT *callindex)
+{
+ L3INT x;
+ for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
+ if (pTrunk->call[x].InUse) {
+ if (pTrunk->call[x].CRV == crv) {
+ *callindex = x;
+ return Q931E_NO_ERROR;
+ }
+ }
+ }
+ return Q931E_INVALID_CRV;
+}
+
+
+void Q931AddDialect(L3UCHAR i, void (*callback)(L3UCHAR iD ))
+{
+ if (i < Q931MAXDLCT) {
+ Q931CreateDialectCB[i] = callback;
+ }
+}
+
+/*****************************************************************************
+ Function: Q931AddStateEntry
+
+ Description: Find an empty entry in the dialects state table and add this
+ entry.
+*****************************************************************************/
+void Q931AddStateEntry(L3UCHAR iD, L3INT iState, L3INT iMes, L3UCHAR cDir)
+{
+ int x;
+ for (x = 0; x < Q931MAXSTATE; x++) {
+ if (Q931st[x].Message == 0) {
+ Q931st[x].State = iState;
+ Q931st[x].Message = iMes;
+ Q931st[x].Direction = cDir;
+ /* TODO Sort table and use bsearch */
+ return;
+ }
+ }
+}
+
+/*****************************************************************************
+ Function: Q931IsEventLegal
+
+ Description: Check state table for matching criteria to indicate if this
+ Message is legal in this state or not.
+
+ Note: Someone write a bsearch or invent something smart here
+ please - sequential is ok for now.
+*****************************************************************************/
+L3BOOL Q931IsEventLegal(L3UCHAR iD, L3INT iState, L3INT iMes, L3UCHAR cDir)
+{
+ int x;
+ /* TODO Sort table and use bsearch */
+ for (x = 0; x < Q931MAXSTATE; x++) {
+ if (Q931st[x].State == iState && Q931st[x].Message == iMes &&
+ Q931st[x].Direction == cDir) {
+ return L3TRUE;
+ }
+ }
+ return L3FALSE;
+}
+
+/*****************************************************************************
+ Function: q931_error_to_name()
+
+ Description: Check state table for matching criteria to indicate if this
+ Message is legal in this state or not.
+
+ Note: Someone write a bsearch or invent something smart here
+ please - sequential is ok for now.
+*****************************************************************************/
+static const char *q931_error_names[] = {
+ "Q931E_NO_ERROR", /* 0 */
+
+ "Q931E_UNKNOWN_MESSAGE", /* -3001 */
+ "Q931E_ILLEGAL_IE", /* -3002 */
+ "Q931E_UNKNOWN_IE", /* -3003 */
+ "Q931E_BEARERCAP", /* -3004 */
+ "Q931E_HLCOMP", /* -3005 */
+ "Q931E_LLCOMP", /* -3006 */
+ "Q931E_INTERNAL", /* -3007 */
+ "Q931E_MISSING_CB", /* -3008 */
+ "Q931E_UNEXPECTED_MESSAGE", /* -3009 */
+ "Q931E_ILLEGAL_MESSAGE", /* -3010 */
+ "Q931E_TOMANYCALLS", /* -3011 */
+ "Q931E_INVALID_CRV", /* -3012 */
+ "Q931E_CALLID", /* -3013 */
+ "Q931E_CALLSTATE", /* -3014 */
+ "Q931E_CALLEDSUB", /* -3015 */
+ "Q931E_CALLEDNUM", /* -3016 */
+ "Q931E_CALLINGNUM", /* -3017 */
+ "Q931E_CALLINGSUB", /* -3018 */
+ "Q931E_CAUSE", /* -3019 */
+ "Q931E_CHANID", /* -3020 */
+ "Q931E_DATETIME", /* -3021 */
+ "Q931E_DISPLAY", /* -3022 */
+ "Q931E_KEYPADFAC", /* -3023 */
+ "Q931E_NETFAC", /* -3024 */
+ "Q931E_NOTIFIND", /* -3025 */
+ "Q931E_PROGIND", /* -3026 */
+ "Q931E_RESTARTIND", /* -3027 */
+ "Q931E_SEGMENT", /* -3028 */
+ "Q931E_SIGNAL", /* -3029 */
+ "Q931E_GENERIC_DIGITS" /* -3030 */
+
+};
+
+#define Q931_MAX_ERROR 30
+
+const char *q931_error_to_name(q931_error_t error)
+{
+ int index = 0;
+ if ((int)error < 0) {
+ index = (((int)error * -1) -3000);
+ }
+ if (index < 0 || index > Q931_MAX_ERROR) {
+ return "";
+ }
+ return q931_error_names[index];
+}
+/*
+ * Logging
+ */
+#include <stdarg.h>
+
+L3INT Q931Log(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level, const char *fmt, ...)
+{
+ char buf[Q931_LOGBUFSIZE];
+ L3INT len;
+ va_list ap;
+
+ if (!trunk->Q931LogCBProc)
+ return 0;
+
+ if (trunk->loglevel < level)
+ return 0;
+
+ va_start(ap, fmt);
+
+ len = vsnprintf(buf, sizeof(buf)-1, fmt, ap);
+ if (len <= 0) {
+ /* TODO: error handling */
+ return -1;
+ }
+ if (len >= sizeof(buf))
+ len = sizeof(buf) - 1;
+
+ buf[len] = '\0';
+
+ va_end(ap);
+
+ return trunk->Q931LogCBProc(trunk->PrivateDataLog, level, buf, len);
+}
+
+/**
+ * Q921SetLogCB
+ * \brief Set Logging callback function and private data
+ */
+void Q931SetLogCB(Q931_TrunkInfo_t *trunk, Q931LogCB_t func, void *priv)
+{
+ trunk->Q931LogCBProc = func;
+ trunk->PrivateDataLog = priv;
+}
+
+/**
+ * Q921SetLogLevel
+ * \brief Set Loglevel
+ */
+void Q931SetLogLevel(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level)
+{
+ if(!trunk)
+ return;
+
+ if (level < Q931_LOG_NONE) {
+ level = Q931_LOG_NONE;
+ } else if (level > Q931_LOG_DEBUG) {
+ level = Q931_LOG_DEBUG;
+ }
+
+ trunk->loglevel = level;
+}
+
+/**
+ * Q931TimeoutDummy
+ * \brief Dummy handler for timeouts
+ * \param pTrunk Q.931 trunk
+ * \param callIndex Index of call
+ */
+L3INT Q931TimeoutDummy(Q931_TrunkInfo_t *pTrunk, L3INT callIndex)
+{
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Timer %d of call %d (CRV: %d) timed out\n", pTrunk->call[callIndex].TimerID, callIndex, pTrunk->call[callIndex].CRV);
+
+ return 0;
+}
Added: freeswitch/trunk/libs/freetdm/src/isdn/Q931StateNT.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/Q931StateNT.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/Q931StateNT.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1218 @@
+/*****************************************************************************
+
+ FileName: q931StateNT.c
+
+ Contents: Q.931 State Engine for NT (Network Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "Q931.h"
+
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+ Function: Q931CreateNT
+
+ Description: Will create the Q931 NT as a Dialect in the stack. The first
+ bulk set up the message handlers, the second bulk the IE
+ encoders/coders, and the last bulk set up the state table.
+
+ Parameters: i Dialect index
+*****************************************************************************/
+void Q931CreateNT(L3UCHAR i)
+{
+ Q931SetMesProc(Q931mes_ALERTING, i, Q931ProcAlertingNT, Q931Umes_Alerting, Q931Pmes_Alerting);
+ Q931SetMesProc(Q931mes_CALL_PROCEEDING, i, Q931ProcCallProceedingNT, Q931Umes_CallProceeding, Q931Pmes_CallProceeding);
+ Q931SetMesProc(Q931mes_CONNECT, i, Q931ProcConnectNT, Q931Umes_Connect, Q931Pmes_Connect);
+ Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i, Q931ProcConnectAckNT, Q931Umes_ConnectAck, Q931Pmes_ConnectAck);
+ Q931SetMesProc(Q931mes_PROGRESS, i, Q931ProcProgressNT, Q931Umes_Progress, Q931Pmes_Progress);
+ Q931SetMesProc(Q931mes_SETUP, i, Q931ProcSetupNT, Q931Umes_Setup, Q931Pmes_Setup);
+ Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE, i, Q931ProcSetupAckNT, Q931Umes_SetupAck, Q931Pmes_SetupAck);
+ Q931SetMesProc(Q931mes_RESUME, i, Q931ProcResumeNT, Q931Umes_Resume, Q931Pmes_Resume);
+ Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE, i, Q931ProcResumeAckNT, Q931Umes_ResumeAck, Q931Pmes_ResumeAck);
+ Q931SetMesProc(Q931mes_RESUME_REJECT, i, Q931ProcResumeRejectNT, Q931Umes_ResumeReject, Q931Pmes_ResumeReject);
+ Q931SetMesProc(Q931mes_SUSPEND, i, Q931ProcSuspendNT, Q931Umes_Suspend, Q931Pmes_Suspend);
+ Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE, i, Q931ProcSuspendAckNT, Q931Umes_SuspendAck, Q931Pmes_SuspendAck);
+ Q931SetMesProc(Q931mes_SUSPEND_REJECT, i, Q931ProcSuspendRejectNT, Q931Umes_SuspendReject, Q931Pmes_SuspendReject);
+ Q931SetMesProc(Q931mes_USER_INFORMATION, i, Q931ProcUserInformationNT, Q931Umes_UserInformation, Q931Pmes_UserInformation);
+ Q931SetMesProc(Q931mes_DISCONNECT, i, Q931ProcDisconnectNT, Q931Umes_Disconnect, Q931Pmes_Disconnect);
+ Q931SetMesProc(Q931mes_RELEASE, i, Q931ProcReleaseNT, Q931Umes_Release, Q931Pmes_Release);
+ Q931SetMesProc(Q931mes_RELEASE_COMPLETE, i, Q931ProcReleaseCompleteNT, Q931Umes_ReleaseComplete, Q931Pmes_ReleaseComplete);
+ Q931SetMesProc(Q931mes_RESTART, i, Q931ProcRestartNT, Q931Umes_Restart, Q931Pmes_Restart);
+ Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE, i, Q931ProcRestartAckNT, Q931Umes_RestartAck, Q931Pmes_RestartAck);
+ Q931SetMesProc(Q931mes_CONGESTION_CONTROL, i, Q931ProcCongestionControlNT, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+ Q931SetMesProc(Q931mes_INFORMATION, i, Q931ProcInformationNT, Q931Umes_Information, Q931Pmes_Information);
+ Q931SetMesProc(Q931mes_NOTIFY, i, Q931ProcNotifyNT, Q931Umes_Notify, Q931Pmes_Notify);
+ Q931SetMesProc(Q931mes_STATUS, i, Q931ProcStatusNT, Q931Umes_Status, Q931Pmes_Status);
+ Q931SetMesProc(Q931mes_STATUS_ENQUIRY, i, Q931ProcStatusEnquiryNT, Q931Umes_StatusEnquiry, Q931Pmes_StatusEnquiry);
+ Q931SetMesProc(Q931mes_SEGMENT, i, Q931ProcSegmentNT, Q931Umes_Segment, Q931Pmes_Segment);
+
+ Q931SetMesProc(Q932mes_FACILITY, i, Q932ProcFacilityNT, Q932Umes_Facility, Q932Pmes_Facility);
+ Q931SetMesProc(Q932mes_HOLD, i, Q932ProcHoldNT, Q932Umes_Hold, Q932Pmes_Hold);
+ Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE, i, Q932ProcHoldAckNT, Q932Umes_HoldAck, Q932Pmes_HoldAck);
+ Q931SetMesProc(Q932mes_HOLD_REJECT, i, Q932ProcHoldRejectNT, Q932Umes_HoldReject, Q932Pmes_HoldReject);
+ Q931SetMesProc(Q932mes_REGISTER, i, Q932ProcRegisterNT, Q932Umes_Register, Q932Pmes_Register);
+ Q931SetMesProc(Q932mes_RETRIEVE, i, Q932ProcRetrieveNT, Q932Umes_Retrieve, Q932Pmes_Retrieve);
+ Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckNT, Q932Umes_RetrieveAck, Q932Pmes_RetrieveAck);
+ Q931SetMesProc(Q932mes_RETRIEVE_REJECT, i, Q932ProcRetrieveRejectNT, Q932Umes_RetrieveReject, Q932Pmes_RetrieveReject);
+
+ /* Set up the IE encoder/decoder handle table.*/
+ Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE, i, Q931Pie_Segment, Q931Uie_Segment);
+ Q931SetIEProc(Q931ie_BEARER_CAPABILITY, i, Q931Pie_BearerCap, Q931Uie_BearerCap);
+ Q931SetIEProc(Q931ie_CAUSE, i, Q931Pie_Cause, Q931Uie_Cause);
+ Q931SetIEProc(Q931ie_CALL_IDENTITY, i, Q931Pie_CallID, Q931Uie_CallID);
+ Q931SetIEProc(Q931ie_CALL_STATE, i, Q931Pie_CallState, Q931Uie_CallState);
+ Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION, i, Q931Pie_ChanID, Q931Uie_ChanID);
+ Q931SetIEProc(Q931ie_PROGRESS_INDICATOR, i, Q931Pie_ProgInd, Q931Uie_ProgInd);
+ Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES, i, Q931Pie_NetFac, Q931Uie_NetFac);
+ Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR, i, Q931Pie_NotifInd, Q931Uie_NotifInd);
+ Q931SetIEProc(Q931ie_DISPLAY, i, Q931Pie_Display, Q931Uie_Display);
+ Q931SetIEProc(Q931ie_DATETIME, i, Q931Pie_DateTime, Q931Uie_DateTime);
+ Q931SetIEProc(Q931ie_KEYPAD_FACILITY, i, Q931Pie_KeypadFac, Q931Uie_KeypadFac);
+ Q931SetIEProc(Q931ie_SIGNAL, i, Q931Pie_Signal, Q931Uie_Signal);
+ Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER, i, Q931Pie_CallingNum, Q931Uie_CallingNum);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS, i, Q931Pie_CallingSub, Q931Uie_CallingSub);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER, i, Q931Pie_CalledNum, Q931Uie_CalledNum);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS, i, Q931Pie_CalledSub, Q931Uie_CalledSub);
+ Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_RESTART_INDICATOR, i, Q931Pie_RestartInd, Q931Uie_RestartInd);
+ Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY, i, Q931Pie_LLComp, Q931Uie_LLComp);
+ Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY, i, Q931Pie_HLComp, Q931Uie_HLComp);
+ Q931SetIEProc(Q931ie_USER_USER, i, Q931Pie_UserUser, Q931Uie_UserUser);
+
+ Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_FACILITY, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_REDIRECTING_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+
+ /* The following define a state machine. The point is that the Message
+ * procs can when search this to find out if the message/state
+ * combination is legale. If not, the proc for unexpected message apply.
+ */
+
+ /* TODO define state table here */
+
+ /* Timer default values */
+ Q931SetTimerDefault(i, Q931_TIMER_T301, 180000); /* T301: 180s */
+ Q931SetTimerDefault(i, Q931_TIMER_T302, 15000); /* T302: 15s */
+ Q931SetTimerDefault(i, Q931_TIMER_T303, 4000); /* T303: 4s */
+ Q931SetTimerDefault(i, Q931_TIMER_T304, 20000); /* T304: 20s */
+ Q931SetTimerDefault(i, Q931_TIMER_T305, 30000); /* T305: 30s */
+ Q931SetTimerDefault(i, Q931_TIMER_T306, 30000); /* T306: 30s */
+ Q931SetTimerDefault(i, Q931_TIMER_T307, 180000); /* T307: 180s */
+ Q931SetTimerDefault(i, Q931_TIMER_T308, 4000); /* T308: 4s */
+ Q931SetTimerDefault(i, Q931_TIMER_T309, 60000); /* T309: 60s */
+ Q931SetTimerDefault(i, Q931_TIMER_T310, 10000); /* T310: 10s */
+ Q931SetTimerDefault(i, Q931_TIMER_T312, 12000); /* T312: 12s */
+ Q931SetTimerDefault(i, Q931_TIMER_T314, 4000); /* T314: 4s */
+ Q931SetTimerDefault(i, Q931_TIMER_T316, 120000); /* T316: 120s */
+ Q931SetTimerDefault(i, Q931_TIMER_T317, 90000); /* T317: 90s */
+ Q931SetTimerDefault(i, Q931_TIMER_T320, 30000); /* T320: 30s */
+ Q931SetTimerDefault(i, Q931_TIMER_T321, 30000); /* T321: 30s */
+ Q931SetTimerDefault(i, Q931_TIMER_T322, 4000); /* T322: 4s */
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcAlertingNT
+
+*****************************************************************************/
+L3INT Q931ProcAlertingNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* Reset 4 sec timer. */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcCallProceedingNT
+
+*****************************************************************************/
+L3INT Q931ProcCallProceedingNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcConnectNT
+
+*****************************************************************************/
+L3INT Q931ProcConnectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcConnectAckNT
+
+*****************************************************************************/
+L3INT Q931ProcConnectAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcProgressNT
+
+*****************************************************************************/
+L3INT Q931ProcProgressNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSetupNT
+
+ Description: Process a SETUP message.
+
+ *****************************************************************************/
+L3INT Q931ProcSetupNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+ L3INT rc = 0;
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Reject SETUP on existing calls */
+ if (Q931GetCallState(pTrunk, pMes->CRV) != Q931_U0) {
+ Q931Disconnect(pTrunk, iFrom, pMes->CRV, 81);
+ return Q931E_UNEXPECTED_MESSAGE;
+ }
+
+ /* outgoing call */
+ if (iFrom == 4) {
+ ret = Q931CreateCRV(pTrunk, &callIndex);
+ if (ret)
+ return ret;
+
+ pMes->CRV = pTrunk->call[callIndex].CRV;
+
+ /*
+ * Outgoing SETUP message will be broadcasted in PTMP mode
+ */
+ ret = Q931Tx32Data(pTrunk, Q931_IS_PTP(pTrunk) ? 0 : 1, buf, pMes->Size);
+ if (ret)
+ return ret;
+
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ Q931SetState(pTrunk, callIndex, Q931_U1);
+ }
+ /* incoming call */
+ else {
+ /* Locate free CRV entry and store info */
+ ret = Q931AllocateCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR) {
+ /* Not possible to allocate CRV entry, so must reject call */
+ Q931Disconnect(pTrunk, iFrom, pMes->CRV, 42);
+ return ret;
+ }
+
+ /* store TEI in call */
+ pTrunk->call[callIndex].Tei = pMes->Tei;
+
+ /* Send setup indication to user */
+ ret = Q931Tx34(pTrunk, (L3UCHAR*)pMes, pMes->Size);
+ if (ret != Q931E_NO_ERROR) {
+ return ret;
+ } else {
+ /* Must be full queue, meaning we can't process the call */
+ /* so we must disconnect */
+ Q931Disconnect(pTrunk, iFrom, pMes->CRV, 81);
+ return ret;
+ }
+#if 0
+ /* TODO: Unreachable code??? */
+ /* Set state U6 */
+ Q931SetState(pTrunk, callIndex, Q931_U6);
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+#endif
+ }
+
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSetupAckNT
+
+ Description: Used to acknowedge a SETUP. Usually the first initial
+ response recevide back used to buy some time.
+
+ Note that ChanID (B Channel Assignment) might come here from
+ NT side.
+
+*****************************************************************************/
+L3INT Q931ProcSetupAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcResumeNT
+
+*****************************************************************************/
+L3INT Q931ProcResumeNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcResumeAckNT
+
+*****************************************************************************/
+L3INT Q931ProcResumeAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcResumeRejectNT
+
+*****************************************************************************/
+L3INT Q931ProcResumeRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSuspendNT
+
+*****************************************************************************/
+L3INT Q931ProcSuspendNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSuspendAckNT
+
+*****************************************************************************/
+L3INT Q931ProcSuspendAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSuspendRejectNT
+
+*****************************************************************************/
+L3INT Q931ProcSuspendRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcInformationNT
+
+*****************************************************************************/
+L3INT Q931ProcUserInformationNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcDisconnectNT
+
+*****************************************************************************/
+L3INT Q931ProcDisconnectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcReleaseNT
+
+*****************************************************************************/
+L3INT Q931ProcReleaseNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcReleaseCompleteNT
+
+*****************************************************************************/
+L3INT Q931ProcReleaseCompleteNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcRestartNT
+
+*****************************************************************************/
+L3INT Q931ProcRestartNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcRestartAckNT
+
+*****************************************************************************/
+L3INT Q931ProcRestartAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcCongestionControlNT
+
+*****************************************************************************/
+L3INT Q931ProcCongestionControlNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcInformationNT
+
+*****************************************************************************/
+L3INT Q931ProcInformationNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcNotifyNT
+
+*****************************************************************************/
+L3INT Q931ProcNotifyNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcStatusNT
+
+*****************************************************************************/
+L3INT Q931ProcStatusNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcStatusEnquiryNT
+
+*****************************************************************************/
+L3INT Q931ProcStatusEnquiryNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSegmentNT
+
+*****************************************************************************/
+L3INT Q931ProcSegmentNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/****************************************************************************/
+/******************* Q.932 - Supplementary Services *************************/
+/****************************************************************************/
+
+/*****************************************************************************
+
+ Function: Q932ProcFacilityNT
+
+*****************************************************************************/
+L3INT Q932ProcFacilityNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcHoldNT
+
+*****************************************************************************/
+L3INT Q932ProcHoldNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcHoldAckNT
+
+*****************************************************************************/
+L3INT Q932ProcHoldAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcHoldRejectNT
+
+*****************************************************************************/
+L3INT Q932ProcHoldRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcRegisterTE
+
+*****************************************************************************/
+L3INT Q932ProcRegisterNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcRetrieveNT
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcRetrieveAckNT
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcRetrieveRejectNT
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
Added: freeswitch/trunk/libs/freetdm/src/isdn/Q931StateTE.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/Q931StateTE.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/Q931StateTE.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1310 @@
+/*****************************************************************************
+
+ FileName: q931StateTE.c
+
+ Contents: Q.931 State Engine for TE (User Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ This reference implementation uses a process per message,
+ meaning that each message must check call states. This
+ is easier for dialect maintenance as each message proc
+ can be replaced individually. A new TE variant only
+ need to copy the Q931CreateTE and replace those procs or
+ need to override.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "Q931.h"
+
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+ Function: Q931CreateTE
+
+ Description: Will create the Q931 TE as a Dialect in the stack. The first
+ bulk set up the message handlers, the second bulk the IE
+ encoders/coders, and the last bulk set up the state table.
+
+ Parameters: i Dialect index
+*****************************************************************************/
+void Q931CreateTE(L3UCHAR i)
+{
+ Q931SetMesProc(Q931mes_ALERTING, i, Q931ProcAlertingTE, Q931Umes_Alerting, Q931Pmes_Alerting);
+ Q931SetMesProc(Q931mes_CALL_PROCEEDING, i, Q931ProcCallProceedingTE, Q931Umes_CallProceeding, Q931Pmes_CallProceeding);
+ Q931SetMesProc(Q931mes_CONNECT, i, Q931ProcConnectTE, Q931Umes_Connect, Q931Pmes_Connect);
+ Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i, Q931ProcConnectAckTE, Q931Umes_ConnectAck, Q931Pmes_ConnectAck);
+ Q931SetMesProc(Q931mes_PROGRESS, i, Q931ProcProgressTE, Q931Umes_Progress, Q931Pmes_Progress);
+ Q931SetMesProc(Q931mes_SETUP, i, Q931ProcSetupTE, Q931Umes_Setup, Q931Pmes_Setup);
+ Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE, i, Q931ProcSetupAckTE, Q931Umes_SetupAck, Q931Pmes_SetupAck);
+ Q931SetMesProc(Q931mes_RESUME, i, Q931ProcResumeTE, Q931Umes_Resume, Q931Pmes_Resume);
+ Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE, i, Q931ProcResumeAckTE, Q931Umes_ResumeAck, Q931Pmes_ResumeAck);
+ Q931SetMesProc(Q931mes_RESUME_REJECT, i, Q931ProcResumeRejectTE, Q931Umes_ResumeReject, Q931Pmes_ResumeReject);
+ Q931SetMesProc(Q931mes_SUSPEND, i, Q931ProcSuspendTE, Q931Umes_Suspend, Q931Pmes_Suspend);
+ Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE, i, Q931ProcSuspendAckTE, Q931Umes_SuspendAck, Q931Pmes_SuspendAck);
+ Q931SetMesProc(Q931mes_SUSPEND_REJECT, i, Q931ProcSuspendRejectTE, Q931Umes_SuspendReject, Q931Pmes_SuspendReject);
+ Q931SetMesProc(Q931mes_USER_INFORMATION, i, Q931ProcUserInformationTE, Q931Umes_UserInformation, Q931Pmes_UserInformation);
+ Q931SetMesProc(Q931mes_DISCONNECT, i, Q931ProcDisconnectTE, Q931Umes_Disconnect, Q931Pmes_Disconnect);
+ Q931SetMesProc(Q931mes_RELEASE, i, Q931ProcReleaseTE, Q931Umes_Release, Q931Pmes_Release);
+ Q931SetMesProc(Q931mes_RELEASE_COMPLETE, i, Q931ProcReleaseCompleteTE, Q931Umes_ReleaseComplete, Q931Pmes_ReleaseComplete);
+ Q931SetMesProc(Q931mes_RESTART, i, Q931ProcRestartTE, Q931Umes_Restart, Q931Pmes_Restart);
+ Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE, i, Q931ProcRestartAckTE, Q931Umes_RestartAck, Q931Pmes_RestartAck);
+ Q931SetMesProc(Q931mes_CONGESTION_CONTROL, i, Q931ProcCongestionControlTE, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+ Q931SetMesProc(Q931mes_INFORMATION, i, Q931ProcInformationTE, Q931Umes_Information, Q931Pmes_Information);
+ Q931SetMesProc(Q931mes_NOTIFY, i, Q931ProcNotifyTE, Q931Umes_Notify, Q931Pmes_Notify);
+ Q931SetMesProc(Q931mes_STATUS, i, Q931ProcStatusTE, Q931Umes_Status, Q931Pmes_Status);
+ Q931SetMesProc(Q931mes_STATUS_ENQUIRY, i, Q931ProcStatusEnquiryTE, Q931Umes_StatusEnquiry, Q931Pmes_StatusEnquiry);
+ Q931SetMesProc(Q931mes_SEGMENT, i, Q931ProcSegmentTE, Q931Umes_Segment, Q931Pmes_Segment);
+
+ Q931SetMesProc(Q932mes_FACILITY, i, Q932ProcFacilityTE, Q932Umes_Facility, Q932Pmes_Facility);
+ Q931SetMesProc(Q932mes_HOLD, i, Q932ProcHoldTE, Q932Umes_Hold, Q932Pmes_Hold);
+ Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE, i, Q932ProcHoldAckTE, Q932Umes_HoldAck, Q932Pmes_HoldAck);
+ Q931SetMesProc(Q932mes_HOLD_REJECT, i, Q932ProcHoldRejectTE, Q932Umes_HoldReject, Q932Pmes_HoldReject);
+ Q931SetMesProc(Q932mes_REGISTER, i, Q932ProcRegisterTE, Q932Umes_Register, Q932Pmes_Register);
+ Q931SetMesProc(Q932mes_RETRIEVE, i, Q932ProcRetrieveTE, Q932Umes_Retrieve, Q932Pmes_Retrieve);
+ Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckTE, Q932Umes_RetrieveAck, Q932Pmes_RetrieveAck);
+ Q931SetMesProc(Q932mes_RETRIEVE_REJECT, i, Q932ProcRetrieveRejectTE, Q932Umes_RetrieveReject, Q932Pmes_RetrieveReject);
+
+ /* Set up the IE encoder/decoder handle table.*/
+ Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE, i, Q931Pie_Segment, Q931Uie_Segment);
+ Q931SetIEProc(Q931ie_BEARER_CAPABILITY, i, Q931Pie_BearerCap, Q931Uie_BearerCap);
+ Q931SetIEProc(Q931ie_CAUSE, i, Q931Pie_Cause, Q931Uie_Cause);
+ Q931SetIEProc(Q931ie_CALL_IDENTITY, i, Q931Pie_CallID, Q931Uie_CallID);
+ Q931SetIEProc(Q931ie_CALL_STATE, i, Q931Pie_CallState, Q931Uie_CallState);
+ Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION, i, Q931Pie_ChanID, Q931Uie_ChanID);
+ Q931SetIEProc(Q931ie_PROGRESS_INDICATOR, i, Q931Pie_ProgInd, Q931Uie_ProgInd);
+ Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES, i, Q931Pie_NetFac, Q931Uie_NetFac);
+ Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR, i, Q931Pie_NotifInd, Q931Uie_NotifInd);
+ Q931SetIEProc(Q931ie_DISPLAY, i, Q931Pie_Display, Q931Uie_Display);
+ Q931SetIEProc(Q931ie_DATETIME, i, Q931Pie_DateTime, Q931Uie_DateTime);
+ Q931SetIEProc(Q931ie_KEYPAD_FACILITY, i, Q931Pie_KeypadFac, Q931Uie_KeypadFac);
+ Q931SetIEProc(Q931ie_SIGNAL, i, Q931Pie_Signal, Q931Uie_Signal);
+ Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER, i, Q931Pie_CallingNum, Q931Uie_CallingNum);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS, i, Q931Pie_CallingSub, Q931Uie_CallingSub);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER, i, Q931Pie_CalledNum, Q931Uie_CalledNum);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS, i, Q931Pie_CalledSub, Q931Uie_CalledSub);
+ Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_RESTART_INDICATOR, i, Q931Pie_RestartInd, Q931Uie_RestartInd);
+ Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY, i, Q931Pie_LLComp, Q931Uie_LLComp);
+ Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY, i, Q931Pie_HLComp, Q931Uie_HLComp);
+ Q931SetIEProc(Q931ie_USER_USER, i, Q931Pie_UserUser, Q931Uie_UserUser);
+
+ Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_FACILITY, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_REDIRECTING_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+
+ /* The following define a state machine. The point is that the Message
+ * procs can when search this to find out if the message/state
+ * combination is legale. If not, the proc for unexpected message apply.
+ */
+
+ /* State 0 Idle */
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RESUME, 2);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP, 2);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_STATUS, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE_COMPLETE, 4);
+
+ /* State 1 Call Initiating */
+ Q931AddStateEntry(i, Q931_U1, Q931mes_DISCONNECT, 2);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_SETUP_ACKNOWLEDGE, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_RELEASE_COMPLETE, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_CALL_PROCEEDING, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_CONNECT, 4);
+
+ /* State 2 Overlap Sending */
+ Q931AddStateEntry(i, Q931_U2, Q931mes_INFORMATION, 2);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_CALL_PROCEEDING, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_PROGRESS, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_CONNECT, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_RELEASE, 2);
+
+ /* State 3 Outgoing Call Proceeding */
+ Q931AddStateEntry(i, Q931_U3, Q931mes_PROGRESS, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_CONNECT, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_RELEASE, 2);
+
+ /* State 4 Call Delivered */
+ Q931AddStateEntry(i, Q931_U4, Q931mes_CONNECT, 4);
+
+ /* State 6 Call Precent */
+ Q931AddStateEntry(i, Q931_U6, Q931mes_INFORMATION, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_ALERTING, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_CALL_PROCEEDING, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_CONNECT, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE_COMPLETE, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_DISCONNECT, 4);
+
+ /* State 7 Call Received */
+ Q931AddStateEntry(i, Q931_U7, Q931mes_CONNECT, 2);
+
+ /* State 8 Connect request */
+ Q931AddStateEntry(i, Q931_U8, Q931mes_CONNECT_ACKNOWLEDGE, 4);
+
+ /* State 9 Incoming Call Proceeding */
+ Q931AddStateEntry(i, Q931_U9, Q931mes_CONNECT, 2);
+ Q931AddStateEntry(i, Q931_U9, Q931mes_ALERTING, 2);
+ Q931AddStateEntry(i, Q931_U9, Q931mes_PROGRESS, 2);
+
+ /* State 10 Active */
+ Q931AddStateEntry(i, Q931_U10, Q931mes_SUSPEND, 2);
+ Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY, 4);
+ Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY, 2);
+
+ /* State 11 Disconnect Request */
+ Q931AddStateEntry(i, Q931_U11, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U11, Q931mes_DISCONNECT, 4);
+ Q931AddStateEntry(i, Q931_U11, Q931mes_NOTIFY, 4);
+
+ /* State 12 Disconnect Ind */
+ Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 2);
+
+ /* State 15 Suspend Request */
+ Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_ACKNOWLEDGE, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_REJECT, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_DISCONNECT, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_RELEASE, 4);
+
+/* TODO
+ Q931AddStateEntry(i, Q931_U17,
+ Q931AddStateEntry(i, Q931_U19,
+ Q931AddStateEntry(i, Q931_U25,
+*/
+
+ /* Timer default values */
+ Q931SetTimerDefault(i, Q931_TIMER_T301, 180000); /* T301: 180s */
+ Q931SetTimerDefault(i, Q931_TIMER_T302, 15000); /* T302: 15s */
+ Q931SetTimerDefault(i, Q931_TIMER_T303, 4000); /* T303: 4s */
+ Q931SetTimerDefault(i, Q931_TIMER_T304, 30000); /* T304: 30s */
+ Q931SetTimerDefault(i, Q931_TIMER_T305, 30000); /* T305: 30s */
+ Q931SetTimerDefault(i, Q931_TIMER_T308, 4000); /* T308: 4s */
+ Q931SetTimerDefault(i, Q931_TIMER_T309, 60000); /* T309: 60s */
+ Q931SetTimerDefault(i, Q931_TIMER_T310, 60000); /* T310: 60s */
+ Q931SetTimerDefault(i, Q931_TIMER_T313, 4000); /* T313: 4s */
+ Q931SetTimerDefault(i, Q931_TIMER_T314, 4000); /* T314: 4s */
+ Q931SetTimerDefault(i, Q931_TIMER_T316, 120000); /* T316: 120s */
+ Q931SetTimerDefault(i, Q931_TIMER_T317, 90000); /* T317: 90s */
+ Q931SetTimerDefault(i, Q931_TIMER_T318, 4000); /* T318: 4s */
+ Q931SetTimerDefault(i, Q931_TIMER_T319, 4000); /* T319: 4s */
+ Q931SetTimerDefault(i, Q931_TIMER_T321, 30000); /* T321: 30s */
+ Q931SetTimerDefault(i, Q931_TIMER_T322, 4000); /* T322: 4s */
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcAlertingTE
+
+*****************************************************************************/
+L3INT Q931ProcAlertingTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* Reset 4 sec timer. */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcCallProceedingTE
+
+*****************************************************************************/
+L3INT Q931ProcCallProceedingTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcConnectTE
+
+*****************************************************************************/
+L3INT Q931ProcConnectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ if (pTrunk->autoConnectAck) {
+ Q931AckConnect(pTrunk, buf);
+ }
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcConnectAckTE
+
+*****************************************************************************/
+L3INT Q931ProcConnectAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcProgressTE
+
+*****************************************************************************/
+L3INT Q931ProcProgressTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSetupTE
+
+*****************************************************************************/
+L3INT Q931ProcSetupTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+ L3INT rc = 0;
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Reject SETUP on existing calls */
+ if (Q931GetCallState(pTrunk, pMes->CRV) != Q931_U0) {
+ Q931Disconnect(pTrunk, iFrom, pMes->CRV, 81);
+ return Q931E_UNEXPECTED_MESSAGE;
+ }
+
+ /* outgoing call */
+ if (iFrom == 4) {
+ ret = Q931CreateCRV(pTrunk, &callIndex);
+ if (ret)
+ return ret;
+ pMes->CRV = pTrunk->call[callIndex].CRV;
+
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ if (ret)
+ return ret;
+
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+
+ /* TODO: Add this back when we get the state stuff more filled out */
+ /*Q931SetState(pTrunk, callIndex, Q931_U1);*/
+ }
+ /* incoming call */
+ else {
+ /* Locate free CRV entry and store info */
+ ret = Q931AllocateCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR) {
+ /* Not possible to allocate CRV entry, so must reject call */
+ Q931Disconnect(pTrunk, iFrom, pMes->CRV, 42);
+ return ret;
+ }
+
+ /* Send setup indication to user */
+ ret = Q931Tx34(pTrunk, (L3UCHAR*)pMes, pMes->Size);
+ if (ret != Q931E_NO_ERROR) {
+ if (pTrunk->autoSetupAck) {
+ Q931AckSetup(pTrunk, buf);
+ }
+ return ret;
+ } else {
+ /* Must be full queue, meaning we can't process the call */
+ /* so we must disconnect */
+ Q931Disconnect(pTrunk, iFrom, pMes->CRV, 81);
+ return ret;
+ }
+#if 0
+ /* TODO: Unreachable code??? */
+ /* Set state U6 */
+ Q931SetState(pTrunk, callIndex, Q931_U6);
+
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+#endif
+ }
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSetupAckTE
+
+ Description: Used to acknowedge a SETUP. Usually the first initial
+ response recevide back used to buy some time. L4 sending this
+ should only be passed on. L2 sending this means that we set
+ a new timer (and pass it to L4).
+
+ Note that ChanID (B Channel Assignment) might come here from
+ NT side.
+
+*****************************************************************************/
+L3INT Q931ProcSetupAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcResumeTE
+
+*****************************************************************************/
+L3INT Q931ProcResumeTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Generic * pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ if (Q931GetCallState(pTrunk, pMes->CRV) == Q931_U0 && iFrom ==4) {
+ /* Call reference selection */
+ ret = Q931CreateCRV(pTrunk, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+ pMes->CRV = pTrunk->call[callIndex].CRV;
+
+ /* Send RESUME to network */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* Start timer T318 */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T318);
+
+ /* set state U17 */
+ Q931SetState(pTrunk, callIndex, Q931_U17);
+ } else {
+ return Q931E_ILLEGAL_MESSAGE;
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcResumeAckTE
+
+*****************************************************************************/
+L3INT Q931ProcResumeAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcResumeRejectTE
+
+*****************************************************************************/
+L3INT Q931ProcResumeRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSuspendTE
+
+*****************************************************************************/
+L3INT Q931ProcSuspendTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSuspendAckTE
+
+*****************************************************************************/
+L3INT Q931ProcSuspendAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSuspendRejectTE
+
+*****************************************************************************/
+L3INT Q931ProcSuspendRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcInformationTE
+
+*****************************************************************************/
+L3INT Q931ProcUserInformationTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcDisconnectTE
+
+*****************************************************************************/
+L3INT Q931ProcDisconnectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Processing DISCONNECT message from %s for CRV: %d (%#hx)\n",
+ iFrom == 4 ? "Local" : "Remote", pMes->CRV, pMes->CRV);
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcReleaseTE
+
+*****************************************************************************/
+L3INT Q931ProcReleaseTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT state = Q931GetCallState(pTrunk, pMes->CRV);
+ L3INT ret = Q931E_NO_ERROR;
+
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (state == Q931_U0 && iFrom == 2) {
+ Q931Tx34(pTrunk, buf, pMes->Size);
+ ret = Q931ReleaseComplete(pTrunk, buf);
+ } else {
+ ret = Q931ProcUnexpectedMessage(pTrunk, buf, iFrom);
+ }
+ if (pMes->CRV && iFrom == 2) {
+ /* Find the call using CRV */
+ if ((Q931FindCRV(pTrunk, pMes->CRV, &callIndex)) != Q931E_NO_ERROR)
+ return ret;
+ pTrunk->call[callIndex].InUse = 0;
+ }
+
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcReleaseCompleteTE
+
+*****************************************************************************/
+L3INT Q931ProcReleaseCompleteTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ } else {
+ if (pMes->CRV) {
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+ pTrunk->call[callIndex].InUse = 0;
+
+ /* TODO: experimental, send RELEASE_COMPLETE message */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcRestartTE
+
+*****************************************************************************/
+L3INT Q931ProcRestartTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ if (pMes->CRV) {
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ }
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+
+ if (pTrunk->autoRestartAck) {
+ Q931AckRestart(pTrunk, buf);
+ }
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcRestartAckTE
+
+*****************************************************************************/
+L3INT Q931ProcRestartAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ if (pMes->CRV) {
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ }
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcCongestionControlTE
+
+*****************************************************************************/
+L3INT Q931ProcCongestionControlTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcInformationTE
+
+*****************************************************************************/
+L3INT Q931ProcInformationTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcNotifyTE
+
+*****************************************************************************/
+L3INT Q931ProcNotifyTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcStatusTE
+
+*****************************************************************************/
+L3INT Q931ProcStatusTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcStatusEnquiryTE
+
+*****************************************************************************/
+L3INT Q931ProcStatusEnquiryTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSegmentTE
+
+*****************************************************************************/
+L3INT Q931ProcSegmentTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/****************************************************************************/
+/******************* Q.932 - Supplementary Services *************************/
+/****************************************************************************/
+
+/*****************************************************************************
+
+ Function: Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcFacilityTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcHoldTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcHoldAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcHoldRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcRegisterTE
+
+*****************************************************************************/
+L3INT Q932ProcRegisterTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcRetrieveAckTE
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcRetrieveRejectTE
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
Added: freeswitch/trunk/libs/freetdm/src/isdn/Q931api.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/Q931api.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/Q931api.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,598 @@
+/*****************************************************************************
+
+ FileName: Q931api.c
+
+ Contents: api (Application Programming Interface) functions.
+ See q931.h for description.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "Q931.h"
+#include "memory.h"
+
+extern L3INT Q931L4HeaderSpace;
+
+/*
+L3INT Q931CreateMesIndex(L3INT mc)
+{
+ if(mc < 0 || mc > 127 )
+ return Q931E_INTERNAL;
+
+ if(Q931MesCount >127)
+ return Q931E_INTERNAL;
+
+ Q931MesIndex[mc] = Q931MesCount ++;
+
+ return Q931E_NO_ERROR;
+}
+*/
+/*
+L3INT Q931CreateIEIndex(L3INT iec)
+{
+ if(iec < 0 || iec > 127 )
+ return Q931E_INTERNAL;
+
+ if(Q931IECount > 127)
+ return Q931E_INTERNAL;
+
+ Q931IEIndex[iec] = Q931IECount ++;
+
+ return Q931E_NO_ERROR;
+}
+*/
+
+L3INT Q931Api_InitTrunk(Q931_TrunkInfo_t *pTrunk,
+ Q931Dialect_t Dialect,
+ Q931NetUser_t NetUser,
+ Q931_TrunkType_t TrunkType,
+ Q931Tx34CB_t Q931Tx34CBProc,
+ Q931Tx32CB_t Q931Tx32CBProc,
+ Q931ErrorCB_t Q931ErrorCBProc,
+ void *PrivateData32,
+ void *PrivateData34)
+{
+ int y, dchannel, maxchans, has_sync = 0;
+
+ switch(TrunkType)
+ {
+ case Q931_TrType_E1:
+ dchannel = 16;
+ maxchans = 31;
+ has_sync = 1;
+ break;
+
+ case Q931_TrType_T1:
+ case Q931_TrType_J1:
+ dchannel = 24;
+ maxchans = 24;
+ break;
+
+ case Q931_TrType_BRI:
+ case Q931_TrType_BRI_PTMP:
+ dchannel = 3;
+ maxchans = 3;
+ break;
+
+ default:
+ return 0;
+ }
+
+ pTrunk->Q931Tx34CBProc = Q931Tx34CBProc;
+ pTrunk->Q931Tx32CBProc = Q931Tx32CBProc;
+ pTrunk->Q931ErrorCBProc = Q931ErrorCBProc;
+ pTrunk->PrivateData32 = PrivateData32;
+ pTrunk->PrivateData34 = PrivateData34;
+
+ pTrunk->LastCRV = 0;
+ pTrunk->Dialect = Dialect + NetUser;
+ pTrunk->Enabled = 0;
+ pTrunk->TrunkType = TrunkType;
+ pTrunk->NetUser = NetUser;
+ pTrunk->TrunkState = 0;
+ pTrunk->autoRestartAck = 0;
+ for(y=0; y < Q931MAXCHPERTRUNK; y++)
+ {
+ pTrunk->ch[y].Available = 1;
+
+ if(has_sync && y == 0)
+ {
+ pTrunk->ch[y].ChanType = Q931_ChType_Sync;
+ }
+ else if(y == dchannel)
+ {
+ pTrunk->ch[y].ChanType = Q931_ChType_D;
+ }
+ else if(y > maxchans)
+ {
+ pTrunk->ch[y].ChanType = Q931_ChType_NotUsed;
+ }
+ else
+ {
+ pTrunk->ch[y].ChanType = Q931_ChType_B;
+ }
+ }
+
+ for(y=0; y < Q931MAXCALLPERTRUNK; y++)
+ {
+ pTrunk->call[y].InUse = 0;
+
+ }
+ return 1;
+}
+
+void Q931SetMesProc(L3UCHAR mes, L3UCHAR dialect, q931proc_func_t *Q931ProcFunc, q931umes_func_t *Q931UmesFunc, q931pmes_func_t *Q931PmesFunc)
+{
+ if(Q931ProcFunc != NULL)
+ Q931Proc[dialect][mes] = Q931ProcFunc;
+ if(Q931UmesFunc != NULL)
+ Q931Umes[dialect][mes] = Q931UmesFunc;
+ if(Q931PmesFunc != NULL)
+ Q931Pmes[dialect][mes] = Q931PmesFunc;
+}
+
+void Q931SetIEProc(L3UCHAR iec, L3UCHAR dialect, q931pie_func_t *Q931PieProc, q931uie_func_t *Q931UieProc)
+{
+ if(Q931PieProc != NULL)
+ Q931Pie[dialect][iec] = Q931PieProc;
+ if(Q931UieProc != NULL)
+ Q931Uie[dialect][iec] = Q931UieProc;
+}
+
+void Q931SetTimeoutProc(L3UCHAR dialect, L3UCHAR timer, q931timeout_func_t *Q931TimeoutProc)
+{
+ if(Q931Timeout != NULL)
+ Q931Timeout[dialect][timer] = Q931TimeoutProc;
+}
+
+void Q931SetTimerDefault(L3UCHAR dialect, L3UCHAR timer, q931timer_t timeout)
+{
+ Q931Timer[dialect][timer] = timeout;
+}
+
+L3INT Q931GetMesSize(Q931mes_Generic *pMes)
+{
+
+ L3UCHAR *p = &pMes->buf[0];
+ L3INT Size = (L3INT)(p - (L3UCHAR *)pMes);
+ return Size;
+}
+
+/*****************************************************************************
+
+ Function: q931AppendIE
+
+ Description: Append IE to the message.
+
+ Parameters: pm Ptr to message.
+ pi Ptr to information element
+
+ Return Value ie setting
+
+*****************************************************************************/
+
+ie Q931AppendIE( L3UCHAR *pm, L3UCHAR *pi)
+{
+ ie IE = 0;
+ Q931mes_Generic * pMes= (Q931mes_Generic *)pm;
+ Q931ie_BearerCap * pIE= (Q931ie_BearerCap *)pi;
+ L3INT iISize = pIE->Size;
+
+ L3UCHAR *pBuf = &pMes->buf[0];
+ L3INT Off = (L3INT)(pMes->Size - (pBuf - pm));
+ IE = (ie)(Off | 0x8000);
+
+ memcpy(&pm[pMes->Size], pi, iISize);
+
+ pMes->Size += iISize;
+
+ return IE;
+}
+
+/*****************************************************************************
+*****************************************************************************/
+static L3INT crv={1};
+
+L3INT Q931GetUniqueCRV(Q931_TrunkInfo_t *pTrunk)
+{
+ L3INT max = (Q931_IS_BRI(pTrunk)) ? Q931_BRI_MAX_CRV : Q931_PRI_MAX_CRV;
+
+ crv++;
+ crv = (crv <= max) ? crv : 1;
+
+ return crv;
+}
+
+L3INT Q931InitMesGeneric(Q931mes_Generic *pMes)
+{
+ memset(pMes, 0, sizeof(*pMes));
+ pMes->ProtDisc = 0x08;
+ pMes->Size = Q931GetMesSize(pMes);
+
+ return 0;
+}
+
+L3INT Q931InitMesResume(Q931mes_Generic * pMes)
+{
+ pMes->ProtDisc = 0x08;
+ pMes->CRV = 0; /* CRV to be allocated, might be receive*/
+ pMes->MesType = Q931mes_RESUME;
+
+ pMes->Size = Q931GetMesSize(pMes);
+ pMes->CallID = 0; /* Channel Identification */
+ return 0;
+}
+
+L3INT Q931InitMesRestartAck(Q931mes_Generic * pMes)
+{
+ pMes->ProtDisc = 0x08;
+ pMes->CRV = 0; /* CRV to be allocated, might be receive*/
+ pMes->MesType = Q931mes_RESTART_ACKNOWLEDGE;
+
+ pMes->Size = Q931GetMesSize(pMes);
+ pMes->ChanID = 0; /* Channel Identification */
+ pMes->Display = 0;
+ pMes->RestartInd = 0;
+ pMes->RestartWin = 0;
+ return 0;
+}
+
+L3INT Q931InitIEBearerCap(Q931ie_BearerCap *pIE)
+{
+ pIE->IEId = Q931ie_BEARER_CAPABILITY;
+ pIE->Size = sizeof(Q931ie_BearerCap);
+ pIE->CodStand = 0;
+ pIE->ITC = 0;
+ pIE->TransMode = 0;
+ pIE->ITR = 0x10;
+ pIE->RateMul = 0;
+
+ pIE->Layer1Ident = 0;
+ pIE->UIL1Prot = 0; /* User Information Layer 1 Protocol */
+ pIE->SyncAsync = 0; /* Sync/Async */
+ pIE->Negot = 0;
+ pIE->UserRate = 0;
+ pIE->InterRate = 0; /* Intermediate Rate */
+ pIE->NIConTx = 0;
+ pIE->NIConRx = 0;
+ pIE->FlowCtlTx = 0; /* Flow control on Tx */
+ pIE->FlowCtlRx = 0; /* Flow control on Rx */
+ pIE->HDR = 0;
+ pIE->MultiFrame = 0; /* Multi frame support */
+ pIE->Mode = 0;
+ pIE->LLInegot = 0;
+ pIE->Assignor = 0; /* Assignor/assignee */
+ pIE->InBandNeg = 0; /* In-band/out-band negot. */
+ pIE->NumStopBits = 0; /* Number of stop bits */
+ pIE->NumDataBits = 0; /* Number of data bits. */
+ pIE->Parity = 0;
+ pIE->DuplexMode = 0;
+ pIE->ModemType = 0;
+ pIE->Layer2Ident = 0;
+ pIE->UIL2Prot = 0; /* User Information Layer 2 Protocol */
+ pIE->Layer3Ident = 0;
+ pIE->UIL3Prot = 0; /* User Information Layer 3 Protocol */
+ pIE->AL3Info1 = 0;
+ pIE->AL3Info2 = 0;
+
+ return 0;
+}
+
+L3INT Q931InitIEChanID(Q931ie_ChanID *pIE)
+{
+ pIE->IEId = Q931ie_CHANNEL_IDENTIFICATION;
+ pIE->Size = sizeof(Q931ie_ChanID);
+ pIE->IntIDPresent = 0; /* Int. id. present */
+ pIE->IntType = 0; /* Int. type */
+ pIE->PrefExcl = 0; /* Pref./Excl. */
+ pIE->DChanInd = 0; /* D-channel ind. */
+ pIE->InfoChanSel = 0; /* Info. channel selection */
+ pIE->InterfaceID = 0; /* Interface identifier */
+ pIE->CodStand = 0; /* Code standard */
+ pIE->NumMap = 0; /* Number/Map */
+ pIE->ChanMapType = 0; /* Channel type/Map element type */
+ pIE->ChanSlot = 0; /* Channel number/Slot map */
+
+ return 0;
+}
+
+L3INT Q931InitIEProgInd(Q931ie_ProgInd * pIE)
+{
+ pIE->IEId = Q931ie_PROGRESS_INDICATOR;
+ pIE->Size = sizeof(Q931ie_ProgInd);
+ pIE->CodStand = 0; /* Coding standard */
+ pIE->Location = 0; /* Location */
+ pIE->ProgDesc = 0; /* Progress description */
+
+ return 0;
+}
+
+L3INT Q931InitIENetFac(Q931ie_NetFac * pIE)
+{
+ pIE->IEId = Q931ie_NETWORK_SPECIFIC_FACILITIES;
+ pIE->Size = sizeof(Q931ie_NetFac);
+ pIE->LenNetID = 0; /* Length of network facilities id. */
+ pIE->TypeNetID = 0; /* Type of network identification */
+ pIE->NetIDPlan = 0; /* Network identification plan. */
+ pIE->NetFac = 0; /* Network specific facility spec. */
+ pIE->NetID[0] = 0;
+ return 0;
+}
+
+L3INT Q931InitIEDisplay(Q931ie_Display * pIE)
+{
+ pIE->IEId = Q931ie_DISPLAY;
+ pIE->Size = sizeof(Q931ie_Display);
+ pIE->Display[0] = 0;
+ return 0;
+}
+
+L3INT Q931InitIEDateTime(Q931ie_DateTime * pIE)
+{
+ pIE->IEId = Q931ie_DATETIME;
+ pIE->Size = sizeof(Q931ie_DateTime);
+ pIE->Year = 0; /* Year */
+ pIE->Month = 0; /* Month */
+ pIE->Day = 0; /* Day */
+ pIE->Hour = 0; /* Hour */
+ pIE->Minute = 0; /* Minute */
+ pIE->Second = 0; /* Second */
+
+ return 0;
+}
+
+L3INT Q931InitIEKeypadFac(Q931ie_KeypadFac * pIE)
+{
+ pIE->IEId = Q931ie_KEYPAD_FACILITY;
+ pIE->Size = sizeof(Q931ie_KeypadFac);
+ pIE->KeypadFac[0] = 0;
+ return 0;
+}
+
+L3INT Q931InitIESignal(Q931ie_Signal * pIE)
+{
+ pIE->IEId = Q931ie_SIGNAL;
+ pIE->Size = sizeof(Q931ie_Signal);
+ pIE->Signal = 0;
+ return 0;
+}
+
+L3INT Q931InitIECallingNum(Q931ie_CallingNum * pIE)
+{
+ pIE->IEId = Q931ie_CALLING_PARTY_NUMBER;
+ pIE->Size = sizeof(Q931ie_CallingNum);
+ pIE->TypNum = 0; /* Type of number */
+ pIE->NumPlanID = 0; /* Numbering plan identification */
+ pIE->PresInd = 0; /* Presentation indicator */
+ pIE->ScreenInd = 0; /* Screening indicator */
+ pIE->Digit[0] = 0; /* Number digits (IA5) */
+
+ return 0;
+}
+
+L3INT Q931InitIECallingSub(Q931ie_CallingSub * pIE)
+{
+ pIE->IEId = Q931ie_CALLING_PARTY_SUBADDRESS;
+ pIE->Size = sizeof(Q931ie_CallingSub);
+ pIE->TypNum = 0; /* Type of subaddress */
+ pIE->OddEvenInd = 0; /* Odd/Even indicator */
+ pIE->Digit[0] = 0; /* Digits */
+
+ return 0;
+}
+
+L3INT Q931InitIECalledNum(Q931ie_CalledNum * pIE)
+{
+ pIE->IEId = Q931ie_CALLED_PARTY_NUMBER;
+ pIE->Size = sizeof(Q931ie_CalledNum);
+ pIE->TypNum = 0; /* Type of Number */
+ pIE->NumPlanID = 0; /* Numbering plan identification */
+ pIE->Digit[0] = 0; /* Digit (IA5) */
+
+ return 0;
+}
+
+L3INT Q931InitIECalledSub(Q931ie_CalledSub * pIE)
+{
+ pIE->IEId = Q931ie_CALLED_PARTY_SUBADDRESS;
+ pIE->Size = sizeof(Q931ie_CalledSub);
+ pIE->TypNum = 0; /* Type of subaddress */
+ pIE->OddEvenInd = 0; /* Odd/Even indicator */
+ pIE->Digit[0] = 0; /* Digits */
+
+ return 0;
+}
+
+L3INT Q931InitIETransNetSel(Q931ie_TransNetSel * pIE)
+{
+ pIE->IEId = Q931ie_TRANSIT_NETWORK_SELECTION;
+ pIE->Size = sizeof(Q931ie_TransNetSel);
+ pIE->Type = 0; /* Type of network identifier */
+ pIE->NetIDPlan = 0; /* Network idetification plan */
+ pIE->NetID[0] = 0; /* Network identification(IA5) */
+
+ return 0;
+}
+
+L3INT Q931InitIELLComp(Q931ie_LLComp * pIE)
+{
+ pIE->IEId = Q931ie_LOW_LAYER_COMPATIBILITY;
+ pIE->Size = sizeof(Q931ie_LLComp);
+
+ pIE->CodStand = 0; /* Coding standard */
+ pIE->ITransCap = 0; /* Information transfer capability */
+ pIE->NegotInd = 0; /* Negot indic. */
+ pIE->TransMode = 0; /* Transfer Mode */
+ pIE->InfoRate = 0; /* Information transfer rate */
+ pIE->RateMul = 0; /* Rate multiplier */
+ pIE->Layer1Ident = 0; /* Layer 1 ident. */
+ pIE->UIL1Prot = 0; /* User information layer 1 protocol */
+ pIE->SyncAsync = 0; /* Synch/asynch */
+ pIE->Negot = 0; /* Negot */
+ pIE->UserRate = 0; /* User rate */
+ pIE->InterRate = 0; /* Intermediate rate */
+ pIE->NIConTx = 0; /* NIC on Tx */
+ pIE->NIConRx = 0; /* NIC on Rx */
+ pIE->FlowCtlTx = 0; /* Flow control on Tx */
+ pIE->FlowCtlRx = 0; /* Flow control on Rx */
+ pIE->HDR = 0; /* Hdr/no hdr */
+ pIE->MultiFrame = 0; /* Multiframe */
+ pIE->ModeL1 = 0; /* Mode L1 */
+ pIE->NegotLLI = 0; /* Negot. LLI */
+ pIE->Assignor = 0; /* Assignor/Assignor ee */
+ pIE->InBandNeg = 0; /* In-band negot. */
+ pIE->NumStopBits = 0; /* Number of stop bits */
+ pIE->NumDataBits = 0; /* Number of data bits */
+ pIE->Parity = 0; /* Parity */
+ pIE->DuplexMode = 0; /* Duplex Mode */
+ pIE->ModemType = 0; /* Modem type */
+ pIE->Layer2Ident = 0; /* Layer 2 ident. */
+ pIE->UIL2Prot = 0; /* User information layer 2 protocol */
+ pIE->ModeL2 = 0; /* ModeL2 */
+ pIE->Q933use = 0; /* Q.9333 use */
+ pIE->UsrSpcL2Prot = 0; /* User specified layer 2 protocol info */
+ pIE->WindowSize = 0; /* Window size (k) */
+ pIE->Layer3Ident = 0; /* Layer 3 ident */
+ pIE->OptL3Info = 0; /* Optional layer 3 protocol info. */
+ pIE->ModeL3 = 0; /* Mode of operation */
+#if 0
+ pIE->ModeX25op = 0; /* Mode of operation X.25 */
+#endif
+ pIE->DefPackSize = 0; /* Default packet size */
+ pIE->PackWinSize = 0; /* Packet window size */
+ pIE->AddL3Info = 0; /* Additional Layer 3 protocol info */
+
+ return 0;
+}
+
+L3INT Q931InitIEHLComp(Q931ie_HLComp * pIE)
+{
+ pIE->IEId = Q931ie_HIGH_LAYER_COMPATIBILITY;
+ pIE->Size = sizeof(Q931ie_HLComp);
+
+ return 0;
+}
+
+L3INT Q931ProcUnknownMessage(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom)
+{
+ /* TODO: Unhandled paramaters */
+ (void)pTrunk;
+ (void)b;
+ (void)iFrom;
+
+ return 0;
+}
+
+L3INT Q931ProcUnexpectedMessage(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom)
+{
+ /* TODO: Unhandled paramaters */
+ (void)pTrunk;
+ (void)b;
+ (void)iFrom;
+
+ return 0;
+}
+
+L3INT Q931Disconnect(Q931_TrunkInfo_t *pTrunk, L3INT iTo, L3INT iCRV, L3INT iCause)
+{
+ /* TODO: Unhandled paramaters */
+ (void)pTrunk;
+ (void)iTo;
+ (void)iCRV;
+ (void)iCause;
+
+ return 0;
+}
+
+L3INT Q931ReleaseComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+ Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+ ptr->MesType = Q931mes_RELEASE_COMPLETE;
+ ptr->CRVFlag = !(ptr->CRVFlag);
+ return Q931Tx32Data(pTrunk,0,buf,ptr->Size);
+}
+
+L3INT Q931AckRestart(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+ L3INT RetCode;
+
+ Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+ ptr->MesType = Q931mes_RESTART_ACKNOWLEDGE;
+ //if (ptr->CRV) {
+ ptr->CRVFlag = !(ptr->CRVFlag);
+ //}
+
+ RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+ return RetCode;
+}
+
+L3INT Q931AckSetup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+ L3INT RetCode;
+
+ Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+ ptr->MesType = Q931mes_SETUP_ACKNOWLEDGE;
+
+ RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+ return RetCode;
+}
+
+L3INT Q931AckConnect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+ L3INT RetCode;
+
+ Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+ ptr->MesType = Q931mes_CONNECT_ACKNOWLEDGE;
+
+ RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+ return RetCode;
+}
+
+L3INT Q931AckService(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+ L3INT RetCode;
+
+ Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+ ptr->MesType = Q931mes_SERVICE_ACKNOWLEDGE;
+ if (ptr->CRV) {
+ ptr->CRVFlag = !(ptr->CRVFlag);
+ }
+
+ RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+ return RetCode;
+}
+
+Q931_ENUM_NAMES(DIALECT_TYPE_NAMES, DIALECT_STRINGS)
+Q931_STR2ENUM(q931_str2Q931Dialect_type, q931_Q931Dialect_type2str, Q931Dialect_t, DIALECT_TYPE_NAMES, Q931_Dialect_Count)
Added: freeswitch/trunk/libs/freetdm/src/isdn/Q931ie.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/Q931ie.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/Q931ie.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3074 @@
+/*****************************************************************************
+
+ FileName: Q931ie.c
+
+ Contents: Information Element Pack/Unpack functions.
+
+ These functions will pack out a Q931 message from the bit
+ packed original format into structs that are easier to process
+ and pack the same structs back into bit fields when sending
+ messages out.
+
+ The messages contains a short for each possible IE. The MSB
+ bit flags the precense of an IE, while the remaining bits
+ are the offset into a buffer to find the actual IE.
+
+ Each IE are supported by 3 functions:
+
+ Q931Pie_XXX Pack struct into Q.931 IE
+ Q931Uie_XXX Unpack Q.931 IE into struct
+ Q931InitIEXXX Initialize IE (see Q931api.c).
+
+ Dialect Note: This file will only contain standard DSS1 IE. Other IE as
+ used in QSIG, NI2, Q.932 etc are located in separate files.
+
+ See q931.h for description.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "Q931.h"
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+#if (_MSC_VER >= 1400) /* VC8+ */
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+#ifndef _CRT_NONSTDC_NO_DEPRECATE
+#define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+#endif
+#ifndef strcasecmp
+#define strcasecmp(s1, s2) _stricmp(s1, s2)
+#endif
+#ifndef strncasecmp
+#define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n)
+#endif
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#endif
+
+/*****************************************************************************
+
+ Macro: Q931MoreIE
+
+ Description: Local helper macro detecting if there is more IE space left
+ based on the 3 standard parameters Octet, Off and IESpace.
+ This can be used to test if the IE is completed to avoid
+ that the header of the next IE is interpreted as a part of
+ the current IE.
+
+*****************************************************************************/
+#define Q931MoreIE() (Octet + Off - 2 < IESize)
+
+#define Q931IESizeTest(x) {\
+ if (Octet + Off - 2 != IESize) {\
+ Q931SetError(pTrunk, x, Octet, Off);\
+ return x;\
+ }\
+}
+
+/*****************************************************************************
+
+ Function: Q931ReadExt
+
+ Description: Many of the octets in the standard have an MSB 'ext.1'. This
+ means that the octet usually is the latest octet, but that a
+ futhure standard may extend the octet. A stack must be able
+ to handle such extensions by skipping the extension octets.
+
+ This function will increase the offset counter with 1 for
+ each octet with an MSB of zero. This will allow the stack to
+ skip extensions wihout knowing anything about them.
+
+ Parameters: IBuf ptr to octet array.
+ Off Starting offset counter
+
+ Return Value: New offset value.
+
+*****************************************************************************/
+
+L3INT Q931ReadExt(L3UCHAR * IBuf, L3INT Off)
+{
+ L3INT c = 0;
+ while ((IBuf[c] & 0x80) == 0) {
+ c++;
+ }
+ return Off + c;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_BearerCap
+
+ Description: Unpack a bearer capability ie.
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+
+L3INT Q931Uie_BearerCap(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_BearerCap *pie = (Q931ie_BearerCap*)OBuf;
+ ie *pIE = &pMsg->BearerCap;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+ *pIE = 0;
+
+ /* Octet 1 */
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->CodStand = ieGetOctet((IBuf[Octet] & 0x60) >> 5);
+ pie->ITC = ieGetOctet(IBuf[Octet] & 0x1f);
+ Off = Q931ReadExt(&IBuf[Octet], Off);
+ Octet++;
+
+ /* Octet 4 */
+ pie->TransMode = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+ pie->ITR = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+ Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+ Octet++;
+
+ /* Octet 4.1. Rate multiplier is only present if ITR = Multirate */
+ if (pie->ITR == 0x18) {
+ pie->RateMul = ieGetOctet(IBuf[Octet + Off] & 0x7f);
+ Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+ Off ++;
+ }
+
+ /* Octet 5 */
+ if ((IBuf[Octet + Off] & 0x60) == 0x20 && Q931MoreIE()) {
+ pie->Layer1Ident = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+ pie->UIL1Prot = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+ Octet++;
+
+ /* Octet 5a. The octet may be present if ITC is unrestrictd digital info
+ * and UIL1Prot is either V.110, I.460 and X.30 or V.120. It may also
+ * be present if ITC = 3.1 kHz audio and UIL1Prot is G.711.
+ * Bit 8 of Octet 5 = 0 indicates that 5a is present.
+ */
+
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ if (((pie->ITC == 0x08) && (pie->UIL1Prot == 0x01 || pie->UIL1Prot == 0x08))
+ || ((pie->ITC == 0x10) && (pie->UIL1Prot == 0x02 || pie->UIL1Prot == 0x03))) {
+ pie->SyncAsync = ieGetOctet((IBuf[Octet + Off] & 0x40) >> 6);
+ pie->Negot = ieGetOctet((IBuf[Octet + Off] & 0x20) >> 5);
+ pie->UserRate = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+ Off ++;
+ }
+ else {
+ /* We have detected bit 8 = 0, but no setting that require the */
+ /* additional octets ??? */
+ Q931SetError(pTrunk, Q931E_BEARERCAP, 5,Off);
+ return Q931E_BEARERCAP;
+ }
+
+ /* Octet 5b. Two different structures used. */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ if (pie->UIL1Prot == 0x01) { /* ITU V.110, I.460 and X.30 */
+ pie->InterRate = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+ pie->NIConTx = ieGetOctet((IBuf[Octet + Off] & 0x10) >> 4);
+ pie->NIConRx = ieGetOctet((IBuf[Octet + Off] & 0x08) >> 3);
+ pie->FlowCtlTx = ieGetOctet((IBuf[Octet + Off] & 0x04) >> 2);
+ pie->FlowCtlRx = ieGetOctet((IBuf[Octet + Off] & 0x20) >> 1);
+ Off++;
+ }
+ else if (pie->UIL1Prot == 0x08) { /* ITU V.120 */
+ pie->HDR = ieGetOctet((IBuf[Octet + Off] & 0x40) >> 6);
+ pie->MultiFrame = ieGetOctet((IBuf[Octet + Off] & 0x20) >> 5);
+ pie->Mode = ieGetOctet((IBuf[Octet + Off] & 0x10) >> 4);
+ pie->LLInegot = ieGetOctet((IBuf[Octet + Off] & 0x08) >> 3);
+ pie->Assignor = ieGetOctet((IBuf[Octet + Off] & 0x04) >> 2);
+ pie->InBandNeg = ieGetOctet((IBuf[Octet + Off] & 0x02) >> 1);
+ Off++;
+ }
+ else {
+ Q931SetError(pTrunk,Q931E_BEARERCAP, 5,Off);
+ return Q931E_BEARERCAP;
+ }
+
+ /* Octet 5c */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ pie->NumStopBits = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+ pie->NumDataBits = ieGetOctet((IBuf[Octet + Off] & 0x18) >> 3);
+ pie->Parity = ieGetOctet(IBuf[Octet + Off] & 0x07);
+ Off++;
+
+ /* Octet 5d */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ pie->DuplexMode = ieGetOctet((IBuf[Octet + Off] & 0x40) >> 6);
+ pie->ModemType = ieGetOctet(IBuf[Octet + Off] & 0x3f);
+ Off ++;
+ }
+ }
+ }
+ }
+ }
+
+ /* Octet 6 */
+ if ((IBuf[Octet + Off] & 0x60) == 0x40 && Q931MoreIE()) {
+ pie->Layer2Ident = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+ pie->UIL2Prot = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+
+ Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+ Octet ++;
+ }
+
+ /* Octet 7 */
+ if ((IBuf[Octet + Off] & 0x60) == 0x60 && Q931MoreIE()) {
+ pie->Layer3Ident = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+ pie->UIL3Prot = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+ Octet++;
+
+ /* Octet 7a */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ if (pie->UIL3Prot == 0x0c) {
+ pie->AL3Info1 = ieGetOctet(IBuf[Octet + Off] & 0x0f);
+ Off++;
+
+ /* Octet 7b */
+ if (IsQ931Ext(IBuf[Octet + Off])) {
+ pie->AL3Info2 = ieGetOctet(IBuf[Octet + Off] & 0x0f);
+ Off++;
+ }
+ }
+ else {
+ Q931SetError(pTrunk,Q931E_BEARERCAP, 7, Off);
+ return Q931E_BEARERCAP;
+
+ }
+ }
+ }
+
+ Q931IESizeTest(Q931E_BEARERCAP);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_BearerCap);
+ pie->Size = sizeof(Q931ie_BearerCap);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_BearerCap
+
+ Description: Packing a Q.931 Bearer Capability element from a generic
+ struct into a packed octet structure in accordance with the
+ standard.
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+
+L3INT Q931Pie_BearerCap(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_BearerCap *pIE = (Q931ie_BearerCap*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet; /* remember current offset */
+ L3INT li;
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Encoding Bearer Capability IE\n");
+
+ OBuf[(*Octet)++] = Q931ie_BEARER_CAPABILITY ;
+ li = (*Octet)++; /* remember length position */
+
+ /* Octet 3 - Coding standard / Information transfer capability */
+ OBuf[(*Octet)++] = 0x80 | ((pIE->CodStand << 5) & 0x60) | (pIE->ITC & 0x1f);
+
+ /* Octet 4 - Transfer mode / Information transfer rate */
+ OBuf[(*Octet)++] = 0x80 | ((pIE->TransMode << 5) & 0x60) | (pIE->ITR & 0x1f);
+
+ if (pIE->ITR == 0x18) {
+ /* Octet 4.1 - Rate Multiplier */
+ OBuf[(*Octet)++] = 0x80 | (pIE->RateMul & 0x7f);
+ }
+
+ /* Octet 5 - Layer 1 Ident / User information layer 1 protocol */
+ if (pIE->Layer1Ident == 0x01) {
+ if (((pIE->ITC == 0x08) && (pIE->UIL1Prot == 0x01 || pIE->UIL1Prot == 0x08)) ||
+ ((pIE->ITC == 0x10) && (pIE->UIL1Prot == 0x02 || pIE->UIL1Prot == 0x03))) {
+ OBuf[(*Octet)++] = 0x00 | ((pIE->Layer1Ident << 5) & 0x60) | (pIE->UIL1Prot & 0x15);
+
+ /* Octet 5a - SyncAsync/Negot/UserRate */
+ OBuf[(*Octet)++] = 0x00 | ((pIE->SyncAsync << 6) & 0x40) | ((pIE->Negot << 5) & 0x20) | (pIE->UserRate & 0x1f);
+
+ /* Octet 5b - one of two types */
+ if (pIE->UIL1Prot == 0x01) { /* ITU V.110, I.460 and X.30 */
+ /* Octet 5b - Intermed rate/ Nic on Tx/Nix on Rx/FlowCtlTx/FlowCtlRx */
+ OBuf[(*Octet)++] = 0x00
+ | ((pIE->InterRate << 6) & 0x60)
+ | ((pIE->NIConTx << 4) & 0x10)
+ | ((pIE->NIConRx << 3) & 0x08)
+ | ((pIE->FlowCtlTx << 2) & 0x04)
+ | ((pIE->FlowCtlRx << 1) & 0x02);
+ }
+ else if (pIE->UIL1Prot == 0x08) { /* ITU V.120 */
+ /* Octet 5b - HDR/Multiframe/Mode/LLINegot/Assignor/Inbandneg*/
+ OBuf[(*Octet)++] = 0x00
+ | ((pIE->InterRate << 6) & 0x60)
+ | ((pIE->MultiFrame << 5) & 0x20)
+ | ((pIE->Mode << 4) & 0x10)
+ | ((pIE->LLInegot << 3) & 0x08)
+ | ((pIE->Assignor << 2) & 0x04)
+ | ((pIE->InBandNeg << 1) & 0x02);
+ }
+
+ /* Octet 5c - NumStopBits/NumStartBits/Parity */
+ OBuf[(*Octet)++] = 0x00
+ | ((pIE->NumStopBits << 5) & 0x60)
+ | ((pIE->NumDataBits << 3) & 0x18)
+ | (pIE->Parity & 0x07);
+
+ /* Octet 5d - Duplex Mode/Modem Type */
+ OBuf[(*Octet)++] = 0x80 | ((pIE->DuplexMode << 6) & 0x40) | (pIE->ModemType & 0x3f);
+ }
+ else {
+ OBuf[(*Octet)++] = 0x80 | ((pIE->Layer1Ident << 5) & 0x60) | (pIE->UIL1Prot & 0x1f);
+ }
+ }
+
+ /* Octet 6 - Layer2Ident/User information layer 2 prtocol */
+ if (pIE->Layer2Ident == 0x02) {
+ OBuf[(*Octet)++] = 0x80 | ((pIE->Layer2Ident << 5) & 0x60) | (pIE->UIL2Prot & 0x1f);
+ }
+
+ /* Octet 7 - Layer 3 Ident/ User information layer 3 protocol */
+ if (pIE->Layer3Ident == 0x03) {
+ if (pIE->UIL3Prot == 0x0c) {
+ OBuf[(*Octet)++] = 0x00 | ((pIE->Layer3Ident << 5) & 0x60) | (pIE->UIL3Prot & 0x1f);
+
+ /* Octet 7a - Additional information layer 3 msb */
+ OBuf[(*Octet)++] = 0x00 | (pIE->AL3Info1 & 0x0f);
+
+ /* Octet 7b - Additional information layer 3 lsb */
+ OBuf[(*Octet)++] = 0x80 | (pIE->AL3Info2 & 0x0f);
+ }
+ else {
+ OBuf[(*Octet)++] = 0x80 | ((pIE->Layer3Ident << 5) & 0x60) | (pIE->UIL3Prot & 0x1f);
+ }
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_CallID
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CallID(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_CallID *pie = (Q931ie_CallID*)OBuf;
+ ie *pIE = &pMsg->CallID;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT x = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ /* Octet 1 */
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ do {
+ pie->CallId[x] = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ x++;
+ } while (Q931MoreIE());
+
+ Q931IESizeTest(Q931E_CALLID);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_CallID) + x - 1;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_CallID) + x - 1);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_CallID
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+
+L3INT Q931Pie_CallID(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_CallID *pIE = (Q931ie_CallID*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;/* remember current offset */
+ L3INT li;
+ L3INT sCI = pIE->Size - sizeof(Q931ie_CallID) + 1;
+ L3INT x;
+
+ OBuf[(*Octet)++] = Q931ie_CALL_IDENTITY ;
+ li = (*Octet)++; /* remember length position */
+
+ for (x = 0; x < sCI; x++) {
+ OBuf[(*Octet)++] = pIE->CallId[x];
+ }
+
+ OBuf[(*Octet) - 1] |= 0x80; /* set complete flag at last octet*/
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_CallState
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CallState(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_CallState *pie = (Q931ie_CallState*)OBuf;
+ ie *pIE = &pMsg->CallState;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ /* Octet 1 */
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->CodStand = (IBuf[Octet + Off] >> 6) & 0x03;
+ pie->CallState = IBuf[Octet + Off] & 0x3f;
+ Octet++;
+
+ Q931IESizeTest(Q931E_CALLSTATE);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_CallState);
+ pie->Size = sizeof(Q931ie_CallState);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_CallState
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CallState(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_CallState *pIE = (Q931ie_CallState*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet; /* remember current offset */
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_CALL_STATE;
+ li = (*Octet)++; /* remember length position */
+
+ OBuf[(*Octet)++] = (pIE->CodStand << 6) | (pIE->CallState & 0x3f);
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_CalledSub
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CalledSub(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_CalledSub *pie = (Q931ie_CalledSub*)OBuf;
+ ie *pIE = &pMsg->CalledSub;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT x;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ /* Octet 1 */
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->TypNum = (IBuf[Octet + Off] >> 4) & 0x07;
+ pie->OddEvenInd = (IBuf[Octet + Off] >> 3) & 0x01;
+ Octet++;
+
+ /* Octet 4 */
+ x = 0;
+ do {
+ pie->Digit[x] = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ x++;
+ } while (Q931MoreIE() && x < 20);
+
+ Q931IESizeTest(Q931E_CALLEDSUB);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_CalledSub) + x - 1;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_CalledSub) + x - 1);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_CalledSub
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CalledSub(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_CalledSub *pIE = (Q931ie_CalledSub*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+ L3INT sN = pIE->Size - sizeof(Q931ie_CalledSub) + 1;
+ L3INT x;
+
+ /* Octet 1 */
+ OBuf[(*Octet)++] = Q931ie_CALLED_PARTY_SUBADDRESS;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = 0x80 | (pIE->TypNum << 4) | (pIE->OddEvenInd << 3);
+
+ /* Octet 4 */
+ for (x = 0; x<sN; x++) {
+ OBuf[(*Octet)++] = pIE->Digit[x];
+ }
+
+ OBuf[(*Octet) - 1] |= 0x80; /* Terminate bit */
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_CalledNum
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CalledNum(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_CalledNum *pie = (Q931ie_CalledNum*)OBuf;
+ ie *pIE = &pMsg->CalledNum;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT x;
+ L3INT IESize; /* # digits in this case */
+
+ *pIE = 0;
+
+ /* Octet 1 */
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->TypNum = (IBuf[Octet + Off] >> 4) & 0x07;
+ pie->NumPlanID = IBuf[Octet + Off] & 0x0f;
+ Octet++;
+
+ /* Octet 4*/
+ x = 0;
+ do {
+ pie->Digit[x] = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ x++;
+ } while ((IBuf[Octet + Off]&0x80) == 0 && Q931MoreIE());
+
+ pie->Digit[x] = '\0';
+
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_CalledNum) + x;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_CalledNum) + x);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_CalledNum
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CalledNum(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_CalledNum *pIE = (Q931ie_CalledNum*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+ L3INT sN = pIE->Size - sizeof(Q931ie_CalledNum);
+ L3INT x;
+
+ /* Octet 1 */
+ OBuf[(*Octet)++] = Q931ie_CALLED_PARTY_NUMBER;
+
+ /* Octet 2 */
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = 0x80 | (pIE->TypNum << 4) | (pIE->NumPlanID);
+
+ /* Octet 4 */
+ for (x = 0; x<sN; x++) {
+ OBuf[(*Octet)++] = pIE->Digit[x];
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_CallingNum
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CallingNum(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_CallingNum *pie = (Q931ie_CallingNum*)OBuf;
+ ie *pIE = &pMsg->CallingNum;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT x;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ /* Octet 1 */
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->TypNum = (IBuf[Octet + Off] >> 4) & 0x07;
+ pie->NumPlanID = IBuf[Octet + Off] & 0x0f;
+
+ /* Octet 3a */
+ if ((IBuf[Octet + Off] & 0x80) == 0) {
+ Off++;
+ pie->PresInd = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->ScreenInd = IBuf[Octet + Off] & 0x03;
+ }
+ Octet++;
+
+ /* Octet 4 */
+ x = 0;
+ while (Q931MoreIE()) {
+ pie->Digit[x++] = IBuf[Octet + Off] & 0x7f;
+
+ if ((IBuf[Octet + Off] & 0x80) != 0) {
+ break;
+ }
+ Off++;
+ }
+ pie->Digit[x] = '\0';
+
+ Q931IESizeTest(Q931E_CALLINGNUM);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_CallingNum) + x;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_CallingNum) + x);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_CallingNum
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CallingNum(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_CallingNum *pIE = (Q931ie_CallingNum*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+ L3INT sN = pIE->Size - sizeof(Q931ie_CallingNum);
+ L3INT x;
+
+ /* Octet 1 */
+ OBuf[(*Octet)++] = Q931ie_CALLING_PARTY_NUMBER;
+
+ /* Octet 2 */
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = 0x00 | (pIE->TypNum << 4) | (pIE->NumPlanID);
+
+ /* Octet 4 */
+ OBuf[(*Octet)++] = 0x80;
+
+ /* Octet 5 */
+ for (x = 0; x<sN; x++) {
+ OBuf[(*Octet)++] = pIE->Digit[x];
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_CallingSub
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CallingSub(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_CallingSub *pie = (Q931ie_CallingSub*)OBuf;
+ ie *pIE = &pMsg->CallingSub;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT x;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ /* Octet 1 */
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->TypNum = (IBuf[Octet + Off] >> 4) & 0x07;
+ pie->OddEvenInd = (IBuf[Octet + Off] >> 3) & 0x01;
+ Octet++;
+
+ /* Octet 4*/
+ x = 0;
+ do {
+ pie->Digit[x] = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ x++;
+ } while (Q931MoreIE() && x < 20);
+
+ Q931IESizeTest(Q931E_CALLINGSUB);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_CallingSub) + x -1;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_CallingSub) + x -1);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_CallingSub
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CallingSub(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_CallingSub *pIE = (Q931ie_CallingSub*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+ L3INT sN = pIE->Size - sizeof(Q931ie_CallingSub) + 1;
+ L3INT x;
+
+ /* Octet 1 */
+ OBuf[(*Octet)++] = Q931ie_CALLING_PARTY_SUBADDRESS;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = 0x80 | (pIE->TypNum << 4) | (pIE->OddEvenInd << 3);
+
+ /* Octet 4 */
+ for (x = 0; x<sN; x++) {
+ OBuf[(*Octet)++] = pIE->Digit[x];
+ }
+
+ OBuf[(*Octet) - 1] |= 0x80; /* Terminate bit */
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_Cause
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_Cause(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_Cause *pie = (Q931ie_Cause*)OBuf;
+ ie *pIE = &pMsg->Cause;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2*/
+ IESize = IBuf[Octet++];
+
+ /* Octet 3*/
+ pie->CodStand = (IBuf[Octet + Off]>>5) & 0x03;
+ pie->Location = IBuf[Octet + Off] & 0x0f;
+
+ /* Octet 3a */
+ if ((IBuf[Octet + Off] & 0x80) == 0) {
+ Off++;
+ pie->Recom = IBuf[Octet + Off] & 0x7f;
+ }
+ Octet++;
+
+ /* Octet 4 */
+ pie->Value = IBuf[Octet + Off] & 0x7f;
+ Octet++;
+
+ /* Consume optional Diagnostic bytes */
+ while (Q931MoreIE()) {
+ Off++;
+ };
+
+ Q931IESizeTest(Q931E_CAUSE);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_Cause);
+ pie->Size = sizeof(Q931ie_Cause);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_Cause
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_Cause(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_Cause *pIE = (Q931ie_Cause*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_CAUSE;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = 0x80 | (pIE->CodStand<<5) | pIE->Location;
+
+ /* Octet 3a - currently not supported in send */
+
+ /* Octet 4 */
+ OBuf[(*Octet)++] = 0x80 | pIE->Value;
+
+ /* Octet 5 - diagnostics not supported in send */
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_CongLevel
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CongLevel(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_CongLevel *pie = (Q931ie_CongLevel*)OBuf;
+ ie *pIE = &pMsg->CongestionLevel;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet] & 0xf0;
+ pie->CongLevel = IBuf[Octet] & 0x0f;
+ Octet ++;
+
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_CongLevel);
+ pie->Size = sizeof(Q931ie_CongLevel);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_CongLevel
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CongLevel(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_CongLevel *pIE = (Q931ie_CongLevel*)IBuf;
+ L3INT rc = 0;
+ /* L3INT Beg = *Octet; */
+
+ OBuf[(*Octet)++] = Q931ie_CONGESTION_LEVEL | pIE->CongLevel;
+
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_ChanID
+
+ Parameters: IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Uie_ChanID(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_ChanID *pie = (Q931ie_ChanID*)OBuf;
+ ie *pIE = &pMsg->ChanID;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+//18 04 e1 80 83 01
+ *pIE = 0;
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Decoding ChanID IE\n");
+
+ /* Octet 1 */
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->IntIDPresent = (IBuf[Octet] >> 6) & 0x01;
+ pie->IntType = (IBuf[Octet] >> 5) & 0x01;
+ pie->PrefExcl = (IBuf[Octet] >> 3) & 0x01;
+ pie->DChanInd = (IBuf[Octet] >> 2) & 0x01;
+ pie->InfoChanSel = IBuf[Octet] & 0x03;
+
+ Off = Q931ReadExt(&IBuf[Octet++], Off);
+
+ /* Octet 3.1 */
+ if (pie->IntIDPresent) {
+ pie->InterfaceID = IBuf[Octet + Off] & 0x7f;
+
+ /* Temp fix. Interface id can be extended using the extension bit */
+ /* this will read the octets, but do nothing with them. this is done */
+ /* because the usage of this field is a little unclear */
+ /* 30.jan.2001/JVB */
+ Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+ Off++;
+ }
+
+ if ((Octet + Off - 2) != IESize) {
+ /* Octet 3.2 */
+ if (pie->IntType == 1) { /* PRI etc */
+ pie->CodStand = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->NumMap = (IBuf[Octet + Off] >> 4) & 0x01;
+ pie->ChanMapType = IBuf[Octet + Off] & 0x0f;
+ Off++;
+
+ /* Octet 3.3 */
+ /* Temp fix. Assume B channel. H channels not supported */
+ pie->ChanSlot = IBuf[Octet + Off] & 0x7f;
+
+ /* Some dialects don't follow the extension coding properly for this, but this should be safe for all */
+ if ((Octet + Off - 1) != IESize) {
+ Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+ }
+ Off++;
+ }
+ }
+
+ Q931IESizeTest(Q931E_CHANID);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_ChanID);
+ pie->Size = sizeof(Q931ie_ChanID);
+
+ if (pTrunk->loglevel == Q931_LOG_DEBUG) {
+ const char *iface;
+ char tmp[100] = "";
+
+ if (!pie->IntType) {
+ switch (pie->InfoChanSel) {
+ case 0x0:
+ iface = "None";
+ break;
+ case 0x1:
+ iface = "B1";
+ break;
+ case 0x2:
+ iface = "B2";
+ break;
+ default:
+ iface = "Any Channel";
+ }
+
+ snprintf(tmp, sizeof(tmp)-1, "InfoChanSel: %d (%s)", pie->InfoChanSel, iface);
+ }
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG,
+ "\n-------------------------- Q.931 Channel ID ------------------------\n"
+ " Pref/Excl: %s, Interface Type: %s\n"
+ " %s\n"
+ "--------------------------------------------------------------------\n\n",
+ ((pie->PrefExcl) ? "Preferred" : "Exclusive"),
+ ((pie->IntType) ? "PRI/Other" : "BRI"),
+ tmp);
+ }
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_ChanID
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_ChanID(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_ChanID *pIE = (Q931ie_ChanID*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet; /* remember current offset */
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_CHANNEL_IDENTIFICATION;
+ li = (*Octet)++; /* remember length position */
+
+ /* Octet 3 flags & BRI chan # */
+ OBuf[(*Octet)++] = 0x80
+ | ((pIE->IntIDPresent << 6) & 0x40)
+ | ((pIE->IntType << 5) & 0x20)
+ | ((pIE->PrefExcl << 3) & 0x08)
+ | (pIE->InfoChanSel & 0x03);
+
+ /* Octet 3.1 - Interface Identifier */
+ if (pIE->IntIDPresent) {
+ OBuf[(*Octet)++] = 0x80 | (pIE->InterfaceID & 0x7f);
+ }
+
+ /* Octet 3.2 & 3.3 - PRI */
+ if (pIE->IntType) {
+ OBuf[(*Octet)++] = 0x80
+ | ((pIE->CodStand << 5) & 0x60)
+ | ((pIE->NumMap << 4) & 0x10)
+ | (pIE->ChanMapType & 0x0f); /* TODO: support all possible channel map types */
+
+ /* Octet 3.3 Channel number */
+ switch (pIE->ChanMapType) {
+ case 0x6: /* Slot map: H0 Channel Units */ /* unsupported, Octets 3.3.1 - 3.3.3 */
+ return Q931E_CHANID;
+
+ case 0x8: /* Slot map: H11 Channel Units */
+ case 0x9: /* Slot map: H12 Channel Units */
+ default: /* Channel number */
+ OBuf[(*Octet)++] = 0x80 | (pIE->ChanSlot & 0x7f);
+ break;
+ }
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+
+/*****************************************************************************
+
+ Function: Q931Uie_CRV
+
+ Description: Reading CRV.
+
+ The CRV is currently returned in the return value that
+ Q921Rx23 will assign to the CRV field in the unpacked
+ message. CRV is basically 2 bytes etc, but the spec allows
+ the use of longer CRV values.
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: CRV
+
+*****************************************************************************/
+L3USHORT Q931Uie_CRV(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff)
+{
+ L3USHORT CRV = 0;
+ L3INT Octet = *IOff;
+ L3INT l = IBuf[Octet++];
+
+ if (l == 1) { /* One octet CRV */
+ CRV = IBuf[Octet++] & 0x7F;
+ }
+ else if (l == 2) { /* two octet CRV */
+ CRV = (IBuf[Octet++] & 0x7f) << 8;
+ CRV |= IBuf[Octet++];
+ }
+ else {
+ /* Long CRV is not used, so we skip this */
+ /* TODO: is it right to set to 0 here? */
+ CRV = 0;
+ Octet += l;
+ }
+
+ *IOff = Octet;
+ return CRV;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_DateTime
+
+ Parameters: pTrunk [IN] Ptr to trunk information.
+ pIE [OUT] ptr to Information Element id.
+ IBuf [IN] ptr to a packed ie.
+ OBuf [OUT] ptr to buffer for Unpacked ie.
+ IOff [IN\OUT] Input buffer offset
+ OOff [IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_DateTime(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_DateTime * pie = (Q931ie_DateTime*)OBuf;
+ ie *pIE = &pMsg->DateTime;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize = 0;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 - Year */
+ pie->Year = IBuf[Octet++];
+
+ /* Octet 4 - Month */
+ pie->Month = IBuf[Octet++];
+
+ /* Octet 5 - Day */
+ pie->Day = IBuf[Octet++];
+
+ /*******************************************************************
+ The remaining part of the IE are optioinal, but only the length
+ can now tell us wherever these fields are present or not
+ (always remember: IESize does not include ID and Size octet)
+ ********************************************************************/
+ pie->Format = 0;
+
+ /* Octet 6 - Hour (optional)*/
+ if (IESize >= 4) {
+ pie->Format = 1;
+ pie->Hour = IBuf[Octet++];
+
+ /* Octet 7 - Minute (optional)*/
+ if (IESize >= 5) {
+ pie->Format = 2;
+ pie->Minute = IBuf[Octet++];
+
+ /* Octet 8 - Second (optional)*/
+ if (IESize >= 6) {
+ pie->Format = 3;
+ pie->Second = IBuf[Octet++];
+ }
+ }
+ }
+
+ Q931IESizeTest(Q931E_DATETIME);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_DateTime);
+ pie->Size = sizeof(Q931ie_DateTime);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_DateTime
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_DateTime(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_DateTime *pIE = (Q931ie_DateTime*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_DATETIME;
+ li = (*Octet)++;
+
+ OBuf[(*Octet)++] = pIE->Year;
+ OBuf[(*Octet)++] = pIE->Month;
+ OBuf[(*Octet)++] = pIE->Day;
+ if (pIE->Format >= 1) {
+ OBuf[(*Octet)++] = pIE->Hour;
+
+ if (pIE->Format >= 2) {
+ OBuf[(*Octet)++] = pIE->Minute;
+
+ if (pIE->Format >= 3) {
+ OBuf[(*Octet)++] = pIE->Second;
+ }
+ }
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet)-Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_Display
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_Display(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_Display *pie = (Q931ie_Display*)OBuf;
+ ie *pIE = &pMsg->Display;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+ L3INT x;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+ IESize = IBuf[Octet++];
+
+ for (x = 0; x<IESize; x++) {
+ pie->Display[x] = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+
+ Q931IESizeTest(Q931E_DISPLAY);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_Display) + x - 1;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_Display) + x - 1);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_Display
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_Display(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_Display *pIE = (Q931ie_Display*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+ L3INT DSize;
+ L3INT x;
+
+ OBuf[(*Octet)++] = Q931ie_DISPLAY;
+ li = (*Octet)++;
+
+ DSize = pIE->Size - sizeof(Q931ie_Display);
+
+ for (x = 0; x< DSize; x++) {
+
+ OBuf[(*Octet)++] = pIE->Display[x];
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_HLComp
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_HLComp(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_HLComp * pie = (Q931ie_HLComp*)OBuf;
+ ie *pIE = &pMsg->HLComp;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3*/
+ pie->CodStand = (IBuf[Octet + Off] >>5) & 0x03;
+ pie->Interpret = (IBuf[Octet + Off] >>2) & 0x07;
+ pie->PresMeth = IBuf[Octet + Off] & 0x03;
+ Octet++;
+
+ /* Octet 4 */
+ pie->HLCharID = IBuf[Octet + Off] & 0x7f;
+ Octet++;
+
+ /* Octet 4a*/
+ if ((IBuf[Octet + Off - 1] & 0x80) == 0 && Q931MoreIE()) {
+ if (pie->HLCharID == 0x5e || pie->HLCharID == 0x5f) {
+ pie->EHLCharID = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+ else if ( pie->HLCharID >= 0xc3 && pie->HLCharID <= 0xcf) {
+ pie->EVideoTlfCharID = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+ else {
+ /* error Octet 4a indicated, but invalid value in Octet 4. */
+ Q931SetError(pTrunk,Q931E_HLCOMP, 4, Off);
+ return Q931E_HLCOMP;
+ }
+ Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+ }
+
+ Q931IESizeTest(Q931E_HLCOMP);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_HLComp);
+ pie->Size = sizeof(Q931ie_HLComp);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_HLComp
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_HLComp(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_HLComp *pIE = (Q931ie_HLComp*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_HIGH_LAYER_COMPATIBILITY;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = 0x80 | ((pIE->CodStand << 5) & 0x60) | ((pIE->Interpret << 2) & 0x1c) | (pIE->PresMeth & 0x03);
+
+ /* Octet 4 */
+ OBuf[(*Octet)++] = pIE->HLCharID;
+
+ /* Octet 4a */
+ if (pIE->HLCharID == 0x5e || pIE->HLCharID == 0x5f) {
+ OBuf[(*Octet)++] = 0x80 | (pIE->EHLCharID & 0x7f);
+ }
+ else if ( pIE->HLCharID >= 0xc3 && pIE->HLCharID <= 0xcf) {
+ OBuf[(*Octet)++] = 0x80 | (pIE->EVideoTlfCharID & 0x7f);
+ }
+ else {
+ OBuf[(*Octet) - 1] |= 0x80;
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_KeypadFac
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_KeypadFac(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_KeypadFac *pie = (Q931ie_KeypadFac*)OBuf;
+ ie *pIE = &pMsg->KeypadFac;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+ L3INT x;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+ IESize = IBuf[Octet++];
+
+ for (x = 0; x<IESize; x++) {
+ pie->KeypadFac[x] = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+
+ Q931IESizeTest(Q931E_KEYPADFAC);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_KeypadFac) + x - 1;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_KeypadFac) + x - 1);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_KeypadFac
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_KeypadFac(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_KeypadFac *pIE = (Q931ie_KeypadFac*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+ L3INT DSize;
+ L3INT x;
+
+ OBuf[(*Octet)++] = Q931ie_KEYPAD_FACILITY;
+ li = (*Octet)++;
+
+ DSize = pIE->Size - sizeof(Q931ie_KeypadFac) + 1;
+
+ for (x = 0; x< DSize; x++) {
+ OBuf[(*Octet)++] = pIE->KeypadFac[x];
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_LLComp
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_LLComp(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_LLComp *pie = (Q931ie_LLComp*)OBuf;
+ ie *pIE = &pMsg->LLComp;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->CodStand = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->ITransCap = IBuf[Octet + Off] & 0x1f;
+ Octet++;
+
+ /* Octet 3a*/
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ pie->NegotInd = (IBuf[Octet + Off] >> 6) & 0x01;
+ Off++;
+ }
+
+ /* Octet 4 */
+ pie->TransMode = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->InfoRate = IBuf[Octet + Off] & 0x1f;
+
+ Octet++;
+
+ /* Octet 4.1 */
+ if (pie->InfoRate == 0x14) { /* Mutirate */
+ pie->RateMul = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+
+ /* Octet 5 - Layer 1 Ident */
+ if ((IBuf[Octet + Off] & 0x60) == 0x20) { /* Layer 1 Ident ? */
+ pie->Layer1Ident = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->UIL1Prot = IBuf[Octet + Off] & 0x1f;
+ Octet++;
+
+ /* Octet 5a */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ pie->SyncAsync = (IBuf[Octet + Off] >> 6) & 0x01;
+ pie->Negot = (IBuf[Octet + Off] >> 5) & 0x01;
+ pie->UserRate = IBuf[Octet + Off] & 0x1f;
+ Off++;
+
+ /* Octet 5b - 2 options */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ if (pie->UIL1Prot == 0x01) { /* V.110, I.460 and X.30*/
+ pie->InterRate = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->NIConTx = (IBuf[Octet + Off] >> 4) & 0x01;
+ pie->NIConRx = (IBuf[Octet + Off] >> 3) & 0x01;
+ pie->FlowCtlTx = (IBuf[Octet + Off] >> 2) & 0x01;
+ pie->FlowCtlRx = (IBuf[Octet + Off] >> 1) & 0x01;
+ Off++;
+ }
+ else if (pie->UIL1Prot == 0x80) { /* V.120 */
+ pie->HDR = (IBuf[Octet + Off] >> 6) & 0x01;
+ pie->MultiFrame = (IBuf[Octet + Off] >> 5) & 0x01;
+ pie->ModeL1 = (IBuf[Octet + Off] >> 4) & 0x01;
+ pie->NegotLLI = (IBuf[Octet + Off] >> 3) & 0x01;
+ pie->Assignor = (IBuf[Octet + Off] >> 2) & 0x01;
+ pie->InBandNeg = (IBuf[Octet + Off] >> 1) & 0x01;
+ Off++;
+ }
+ else if (pie->UIL1Prot == 0x07) { /* non standard */
+ Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+ Off++;
+ }
+ else {
+ Q931SetError(pTrunk,Q931E_LLCOMP, 5,2);
+ return Q931E_LLCOMP;
+ }
+
+ /* Octet 5c */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ pie->NumStopBits = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->NumDataBits = (IBuf[Octet + Off] >> 3) & 0x03;
+ pie->Parity = IBuf[Octet + Off] & 0x07;
+ Off++;
+
+ /* Octet 5d */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ pie->DuplexMode = (IBuf[Octet + Off] >> 6) & 0x01;
+ pie->ModemType = IBuf[Octet + Off] & 0x3f;
+ Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+ Off++;
+ }
+ }
+ }
+ }
+ }
+
+ /* Octet 6 - Layer 2 Ident */
+ if ((IBuf[Octet + Off] & 0x60) == 0x40) { /* Layer 1 Ident ? */
+ pie->Layer2Ident = (IBuf[Octet + Off] >>5) & 0x03;
+ pie->UIL2Prot = IBuf[Octet + Off] & 0x1f;
+ Octet++;
+
+ /* Octet 6a */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ if (pie->UIL2Prot == 0x10) { /* 2nd 6a */
+ pie->UsrSpcL2Prot = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+ else { /* assume 1st 6a */
+ pie->ModeL2 = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->Q933use = IBuf[Octet + Off] & 0x03;
+ Off++;
+ }
+ /* Octet 6b */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ pie->WindowSize = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+ }
+ }
+
+ /* Octet 7 - layer 3 Ident */
+ if ((IBuf[Octet + Off] & 0x60) == 0x60) { /* Layer 3 Ident ? */
+ pie->Layer3Ident = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->UIL3Prot = IBuf[Octet + Off] & 0x1f;
+ Octet++;
+
+ /* Octet 7a */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ if (pie->UIL3Prot == 0x0b) {
+ /* Octet 7a + 7b AddL3Info */
+ pie->AddL3Info = ((IBuf[Octet + Off] << 4) & 0xf0)
+ | (IBuf[Octet + Off + 1] & 0x0f);
+ Off += 2;
+ }
+ else {
+ if (pie->UIL3Prot == 0x1f) {
+ pie->ModeL3 = (IBuf[Octet + Off] >> 5) & 0x03;
+ Off++;
+ }
+ else {
+ pie->OptL3Info = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+
+ /* Octet 7b*/
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ pie->DefPackSize = IBuf[Octet + Off] & 0x0f;
+ Off++;
+
+ /* Octet 7c */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ pie->PackWinSize= IBuf[Octet + Off] & 0x7f;
+ }
+ }
+ }
+ }
+ }
+
+ Q931IESizeTest(Q931E_LLCOMP);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_LLComp);
+ pie->Size = sizeof(Q931ie_LLComp);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_LLComp
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_LLComp(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_LLComp *pIE = (Q931ie_LLComp*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_LOW_LAYER_COMPATIBILITY;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = (pIE->CodStand << 6) | pIE->ITransCap;
+
+ /* Octet 3a */
+ OBuf[(*Octet)++] = 0x80 | (pIE->NegotInd << 6);
+
+ /* Octet 4 */
+ OBuf[(*Octet)++] = 0x80 | (pIE->TransMode << 5) | pIE->InfoRate;
+
+ /* Octet 4.1 */
+ if (pIE->InfoRate == 0x18) {
+ OBuf[(*Octet)++] = 0x80 | pIE->RateMul;
+ }
+
+ /* Octet 5 */
+ if (pIE->Layer1Ident == 0x01) {
+ OBuf[(*Octet)++] = (pIE->Layer1Ident << 5) | pIE->UIL1Prot;
+
+ /* Octet 5a */
+ if ((pIE->ITransCap == 0x08 && (pIE->UIL1Prot == 0x01 || pIE->UIL1Prot == 0x08))
+ || (pIE->ITransCap == 0x10 && (pIE->UIL1Prot == 0x02 || pIE->UIL1Prot == 0x03))) {
+ OBuf[(*Octet)++] = (pIE->SyncAsync<<6) | (pIE->Negot<<5) | pIE->UserRate;
+
+ /* Octet 5b*/
+ if (pIE->UIL1Prot == 0x01) {
+ OBuf[(*Octet)++] = (pIE->InterRate << 5)
+ | (pIE->NIConTx << 4)
+ | (pIE->NIConTx << 3)
+ | (pIE->FlowCtlTx << 2)
+ | (pIE->FlowCtlRx << 1);
+ }
+ else if (pIE->UIL1Prot == 0x08) {
+ OBuf[(*Octet)++] = (pIE->HDR << 6)
+ | (pIE->MultiFrame << 5)
+ | (pIE->ModeL1 << 4)
+ | (pIE->NegotLLI << 3)
+ | (pIE->Assignor << 2)
+ | (pIE->InBandNeg << 1);
+ }
+ else {
+ OBuf[(*Octet) - 1] |= 0x80;
+ }
+
+ /* How to detect wherever 5c and 5d is to present is not clear
+ * but they have been inculded as 'standard'
+ * Octet 5c
+ */
+ if (pIE->UIL1Prot == 0x01 || pIE->UIL1Prot == 0x08) {
+ OBuf[(*Octet)++] = (pIE->NumStopBits << 5) | (pIE->NumDataBits << 3) | pIE->Parity ;
+
+ /* Octet 5d */
+ OBuf[(*Octet)++] = 0x80 | (pIE->DuplexMode << 6) | pIE->ModemType;
+ }
+ }
+ else {
+ OBuf[(*Octet) - 1] |= 0x80;
+ }
+ }
+
+ /* Octet 6 */
+ if (pIE->Layer2Ident == 0x02) {
+ OBuf[(*Octet)++] = (pIE->Layer2Ident << 5) | pIE->UIL2Prot;
+
+ /* Octet 6a*/
+ if (pIE->UIL2Prot == 0x02 /* Q.921/I.441 */
+ || pIE->UIL2Prot == 0x06 /* X.25 link layer */
+ || pIE->UIL2Prot == 0x07 /* X.25 multilink */
+ || pIE->UIL2Prot == 0x09 /* HDLC ARM */
+ || pIE->UIL2Prot == 0x0a /* HDLC NRM */
+ || pIE->UIL2Prot == 0x0b /* HDLC ABM */
+ || pIE->UIL2Prot == 0x0d /* X.75 SLP */
+ || pIE->UIL2Prot == 0x0e /* Q.922 */
+ || pIE->UIL2Prot == 0x11) { /* ISO/ECE 7776 DTE-DCE */
+ OBuf[(*Octet)++] = (pIE->ModeL2 << 5) | pIE->Q933use;
+
+ /* Octet 6b */
+ OBuf[(*Octet)++] = 0x80 | pIE->WindowSize;
+ }
+ else if (pIE->UIL2Prot == 0x10) { /* User Specific */
+ OBuf[(*Octet)++] = 0x80 | pIE->UsrSpcL2Prot;
+ }
+ else {
+ OBuf[(*Octet) - 1] |= 0x80;
+ }
+ }
+
+ /* Octet 7 */
+ if (pIE->Layer3Ident == 0x03) {
+ OBuf[(*Octet)++] = (pIE->Layer3Ident << 5) | pIE->UIL3Prot;
+
+ /* Octet 7a - 3 different ones */
+ if (pIE->UIL3Prot == 0x10) {
+ OBuf[(*Octet++)] = 0x80 | pIE->OptL3Info;
+ }
+ else if (pIE->UIL3Prot == 0x06
+ || pIE->UIL3Prot == 0x07
+ || pIE->UIL3Prot == 0x08) {
+ OBuf[(*Octet)++] = pIE->ModeL3 << 5;
+
+ /* Octet 7b note 7 */
+ OBuf[(*Octet)++] = pIE->DefPackSize;
+
+ /* Octet 7c note 7 */
+ OBuf[(*Octet)++] = 0x80 | pIE->PackWinSize;
+ }
+ else if (pIE->UIL3Prot == 0x0b) {
+ OBuf[(*Octet)++] = (pIE->AddL3Info >> 4) & 0x0f;
+ OBuf[(*Octet)++] = 0x80 | (pIE->AddL3Info & 0x0f);
+ }
+ else {
+ OBuf[(*Octet) - 1] |= 0x80;
+ }
+ }
+ else {
+ Q931SetError(pTrunk,Q931E_LLCOMP, 7,0);
+ rc = Q931E_LLCOMP;
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_NetFac
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_NetFac(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_NetFac *pie = (Q931ie_NetFac*)OBuf;
+ ie *pIE = &pMsg->NetFac;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT x = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ pie->LenNetID = IBuf[Octet + Off]; /* full octet is used */
+ Octet++;
+
+ if (pie->LenNetID > 0) {
+ /* Octet 3.1 */
+ pie->TypeNetID = (IBuf[Octet + Off] >> 4) & 0x0f;
+ pie->NetIDPlan = IBuf[Octet + Off] & 0x0f;
+ Off = Q931ReadExt(&IBuf[Octet], Off);
+ Off++;
+
+ /* Octet 3.2*/
+ for (x = 0; x < pie->LenNetID; x++) {
+ pie->NetID[x] = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+ }
+
+ /* Octet 4*/
+ pie->NetFac = IBuf[Octet + Off]; /* Full Octet is used */
+ Octet++;
+
+ Q931IESizeTest(Q931E_NETFAC);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_NetFac) + x - 1;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_NetFac) + x - 1);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_NetFac
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_NetFac(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_NetFac *pIE = (Q931ie_NetFac*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet;
+ L3INT li;
+ L3INT x;
+
+ OBuf[(*Octet)++] = Q931ie_NETWORK_SPECIFIC_FACILITIES;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = pIE->LenNetID;
+
+ if (pIE->LenNetID > 0) {
+ /* Octet 3.1 */
+ OBuf[(*Octet)++] = 0x80 | (pIE->TypeNetID << 4) | pIE->NetIDPlan;
+
+ /* Octet 3.2 */
+ for (x = 0; x <pIE->LenNetID; x++) {
+ OBuf[(*Octet)++] = pIE->NetID[x];
+ }
+ }
+
+ /* Octet 4 */
+ OBuf[(*Octet)++] = pIE->NetFac;
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_NotifInd
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_NotifInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_NotifInd *pie = (Q931ie_NotifInd*)OBuf;
+ ie *pIE = &pMsg->NotifInd;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2*/
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->Notification = IBuf[Octet + Off] & 0x7f;
+
+ Off = Q931ReadExt(&IBuf[Octet], Off);
+ Octet++;
+
+ Q931IESizeTest(Q931E_NOTIFIND);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_NotifInd);
+ pie->Size = sizeof(Q931ie_NotifInd);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_NotifInd
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_NotifInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_NotifInd *pIE = (Q931ie_NotifInd*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_NOTIFICATION_INDICATOR;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = pIE->Notification;
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_ProgInd
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_ProgInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_ProgInd *pie = (Q931ie_ProgInd*)OBuf;
+ ie *pIE = &pMsg->ProgInd;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->CodStand = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->Location = IBuf[Octet + Off] & 0x0f;
+
+ Off = Q931ReadExt(&IBuf[Octet], Off);
+ Octet++;
+
+ /* Octet 4 */
+ pie->ProgDesc = IBuf[Octet + Off] & 0x7f;
+ Off = Q931ReadExt(&IBuf[Octet], Off);
+ Octet++;
+
+ Q931IESizeTest(Q931E_PROGIND);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_ProgInd);
+ pie->Size = sizeof(Q931ie_ProgInd);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_ProgInd
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset L3INTo OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_ProgInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_ProgInd *pIE = (Q931ie_ProgInd*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_PROGRESS_INDICATOR;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = 0x80 | (pIE->CodStand << 5) | pIE->Location;
+
+ /* Octet 4 */
+ OBuf[(*Octet)++] = 0x80 | pIE->ProgDesc;
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_RepeatInd
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_RepeatInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_RepeatInd *pie = (Q931ie_RepeatInd*)OBuf;
+ ie *pIE = &pMsg->RepeatInd;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet] & 0xf0;
+ pie->RepeatInd = IBuf[Octet] & 0x0f;
+ Octet ++;
+
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_RepeatInd);
+ pie->Size = sizeof(Q931ie_RepeatInd);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_RepeatInd
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_RepeatInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_RepeatInd *pIE = (Q931ie_RepeatInd*)IBuf;
+ L3INT rc = 0;
+ /* L3INT Beg = *Octet; */
+
+ OBuf[(*Octet)++] = Q931ie_REPEAT_INDICATOR | pIE->RepeatInd;
+
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_RevChargeInd
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_RevChargeInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ ie iE;
+ /* ie *pIE = &pMsg->RevChargeInd; */
+ Q931SetIE(iE, *OOff);
+
+ return iE;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_RevChargeInd
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_RevChargeInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_RestartInd
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_RestartInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_RestartInd *pie = (Q931ie_RestartInd*)OBuf;
+ ie *pIE = &pMsg->RestartInd;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->Class = IBuf[Octet + Off] & 0x07;
+ pie->Spare = IBuf[Octet + Off] & 0x78;
+
+ Off = Q931ReadExt(&IBuf[Octet], Off);
+ Octet++;
+
+ Q931IESizeTest(Q931E_RESTARTIND);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_RestartInd);
+ pie->Size = sizeof(Q931ie_RestartInd);
+
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_RestartInd
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_RestartInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_RestartInd *pIE = (Q931ie_RestartInd*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_RESTART_INDICATOR;
+ li = (*Octet)++;
+
+ /* Octet 3*/
+ OBuf[(*Octet)++] = 0x80 | pIE->Class ;
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_Segment
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_Segment(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_Segment *pie = (Q931ie_Segment*)OBuf;
+ ie *pIE = &pMsg->Segment;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+ Octet++;
+
+ /* Octet 2*/
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->FSI = (IBuf[Octet + Off] & 0x80) >> 7;
+ pie->NumSegRem = IBuf[Octet + Off] & 0x7f;
+ Octet++;
+
+ /* Octet 4 */
+ pie->SegType = IBuf[Octet + Off] & 0x7f;
+ Octet++;
+
+ Q931IESizeTest(Q931E_SEGMENT);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_Segment);
+ pie->Size = sizeof(Q931ie_Segment);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_Segment
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_Segment(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_Segment *pIE = (Q931ie_Segment*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_SEGMENTED_MESSAGE;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = (pIE->FSI << 7) | pIE->NumSegRem;
+
+ /* Octet 4 */
+ OBuf[(*Octet)++] = pIE->SegType;
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_SendComplete
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_SendComplete(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_SendComplete *pie = (Q931ie_SendComplete*)OBuf;
+ ie *pIE = &pMsg->SendComplete;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+
+ *pIE = 0;
+ Octet++;
+
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_SendComplete);
+ pie->Size = sizeof(Q931ie_SendComplete);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_ProgInd
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_SendComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ /* Q931ie_SendComplete * pIE = (Q931ie_SendComplete*)IBuf; */
+ L3INT rc = Q931E_NO_ERROR;
+ /* L3INT Beg = *Octet; */
+
+ OBuf[(*Octet)++] = 0x80 | (L3UCHAR)Q931ie_SENDING_COMPLETE;
+
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_Signal
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_Signal(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_Signal *pie = (Q931ie_Signal*)OBuf;
+ ie *pIE = &pMsg->Signal;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->Signal = IBuf[Octet + Off];
+ Octet++;
+
+ Q931IESizeTest(Q931E_SIGNAL);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_Signal);
+ pie->Size = sizeof(Q931ie_Signal);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_Signal
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_Signal(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_Signal *pIE = (Q931ie_Signal*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_SIGNAL;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = pIE->Signal;
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_TransNetSel
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_TransNetSel(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_TransNetSel *pie = (Q931ie_TransNetSel*)OBuf;
+ ie *pIE = &pMsg->TransNetSel;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT x = 0;
+ L3INT l;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ l = IBuf[Octet++] - 3;
+
+ /* Octet 3 */
+ pie->Type = (IBuf[Octet + Off] >> 4) & 0x07;
+
+ Off = Q931ReadExt(&IBuf[Octet], Off);
+ Octet++;
+
+ for (x = 0; x < l; x++) {
+ pie->NetID[x] = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_TransNetSel) + x - 1;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_TransNetSel) + x - 1);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_TransNetSel
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_TransNetSel(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_TransNetSel *pIE = (Q931ie_TransNetSel*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet;
+ L3INT li;
+ L3INT x;
+ L3INT l;
+
+ OBuf[(*Octet)++] = Q931ie_TRANSIT_NETWORK_SELECTION;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = 0x80 | (pIE->Type << 4) | pIE->NetIDPlan;
+
+ /* Octet 4 */
+ l = pIE->Size - sizeof(Q931ie_TransNetSel) + 1;
+ for (x = 0; x < l; x++) {
+ OBuf[(*Octet)++] = pIE->NetID[x];
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_UserUser
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_UserUser(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_UserUser *pie = (Q931ie_UserUser*)OBuf;
+ ie *pIE = &pMsg->UserUser;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT l;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ l = IBuf[Octet++] - 1;
+
+ /* Octet 3 */
+ pie->ProtDisc = IBuf[Octet++];
+
+ for (Off = 0; Off < l; Off++) {
+ pie->User[Off] = IBuf[Octet + Off];
+ }
+
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_UserUser) + Off - 1;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_UserUser) + Off - 1);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_UserUser
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_UserUser(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_UserUser *pIE = (Q931ie_UserUser*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet;
+ L3INT li;
+ L3INT x;
+ L3INT l;
+
+ OBuf[(*Octet)++] = Q931ie_USER_USER;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = pIE->ProtDisc;
+
+ /* Octet 4 */
+ l = pIE->Size - sizeof(Q931ie_UserUser) + 1;
+ for (x = 0; x < l; x++) {
+ OBuf[(*Octet)++] = pIE->User[x];
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_GenericDigits
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_GenericDigits(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_GenericDigits *pie = (Q931ie_GenericDigits*)OBuf;
+ ie *pIE = &pMsg->GenericDigits;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT x;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ /* Octet 1 */
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->Type = (IBuf[Octet]) & 0x1F;
+ pie->Encoding = (IBuf[Octet] >> 5) & 0x07;
+ Octet++;
+
+ /* Octet 4*/
+ if (pie->Encoding == 0) { /* BCD Even */
+ x = 0;
+ do {
+ pie->Digit[x++] = IBuf[Octet + Off] & 0x0f;
+ pie->Digit[x++] = (IBuf[Octet + Off] >> 4) & 0x0f;
+ Off++;
+ } while (Q931MoreIE());
+ } else if (pie->Encoding == 1) { /* BCD Odd */
+ x = 0;
+ do {
+ pie->Digit[x++] = IBuf[Octet + Off] & 0x0f;
+ if (Q931MoreIE()) {
+ pie->Digit[x] = (IBuf[Octet + Off] >> 4) & 0x0f;
+ }
+ x++;
+ Off++;
+ } while (Q931MoreIE());
+ } else if (pie->Encoding == 2) { /* IA5 */
+ x = 0;
+ do {
+ pie->Digit[x++] = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ } while (Q931MoreIE());
+ } else {
+ /* Binary encoding type unkown */
+ Q931SetError(pTrunk, Q931E_GENERIC_DIGITS, Octet, Off);
+ return Q931E_GENERIC_DIGITS;
+ }
+
+ Q931IESizeTest(Q931E_GENERIC_DIGITS);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_CallingSub) + x - 1;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_CallingSub) + x - 1);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_GenericDigits
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+
+L3INT Q931Pie_GenericDigits(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ OBuf[(*Octet)++] = (Q931ie_GENERIC_DIGITS & 0xFF);
+ OBuf[(*Octet)++] = 0;
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_ChangeStatus
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_ChangeStatus(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_ChangeStatus *pie = (Q931ie_ChangeStatus*)OBuf;
+ ie *pIE = &pMsg->ChangeStatus;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->Preference = (IBuf[Octet + Off] >> 6) & 0x01;
+ pie->Spare = IBuf[Octet + Off] & 0x38;
+ pie->NewStatus = IBuf[Octet + Off] & 0x07;
+ Octet++;
+
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_ChangeStatus);
+ pie->Size = sizeof(Q931ie_ChangeStatus);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_ChangeStatus
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_ChangeStatus(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_ChangeStatus *pIE = (Q931ie_ChangeStatus*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_CHANGE_STATUS;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = 0x80 | pIE->NewStatus | ((pIE->Preference & 0x01) << 6);
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+
+
+L3INT Q931Uie_Generic(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff)
+{
+ L3INT Octet = 0;
+ L3UCHAR id = 0;
+
+ /* id */
+ id = IBuf[Octet++];
+
+ /* Length */
+ Octet += IBuf[Octet];
+ Octet++;
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Discarding IE %#hhx with length %d\n", id, Octet - 2);
+
+ *IOff += Octet;
+ return Q931E_NO_ERROR;
+}
+
+L3INT Q931Pie_Generic(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ /* do nothing */
+ return Q931E_NO_ERROR;
+}
Added: freeswitch/trunk/libs/freetdm/src/isdn/Q931mes.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/Q931mes.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/Q931mes.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1870 @@
+/*****************************************************************************
+
+ FileName: Q931mes.c
+
+ Contents: Pack/Unpack functions. These functions will unpack a Q931
+ message from the bit packed original format into structs
+ that contains variables sized by the user. It will also pack
+ the struct back into a Q.931 message as required.
+
+ See q931.h for description.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+
+*****************************************************************************/
+
+#include "Q931.h"
+
+/**
+ * Q931MesgHeader
+ * \brief Create Q.931 Message header
+ */
+L3INT Q931MesgHeader(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *mes, L3UCHAR *OBuf, L3INT Size, L3INT *IOff)
+{
+ L3INT Octet = *IOff;
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Creating Q.931 Message Header:\n ProtDisc %d (%#x), CRV %d (%#x), CRVflag: %d (%#x), MesType: %d (%#x)\n",
+ mes->ProtDisc, mes->ProtDisc, mes->CRV, mes->CRV, mes->CRVFlag, mes->CRVFlag, mes->MesType, mes->MesType);
+
+ OBuf[Octet++] = mes->ProtDisc; /* Protocol discriminator */
+ if (!Q931_IS_BRI(pTrunk)) {
+ OBuf[Octet++] = 2; /* length is 2 octets */
+ OBuf[Octet++] = (L3UCHAR)((mes->CRV >> 8) & 0x7f) | ((mes->CRVFlag << 7) & 0x80); /* msb */
+ OBuf[Octet++] = (L3UCHAR) (mes->CRV & 0xff); /* lsb */
+ } else {
+ OBuf[Octet++] = 1; /* length is 1 octet */
+ OBuf[Octet++] = (L3UCHAR) (mes->CRV & 0x7f) | ((mes->CRVFlag << 7) & 0x80); /* CRV & flag */
+ }
+ OBuf[Octet++] = mes->MesType; /* message header */
+
+ *IOff = Octet;
+ return 0;
+}
+
+
+/*****************************************************************************
+
+ Function: Q931Umes_Alerting
+
+*****************************************************************************/
+
+L3INT Q931Umes_Alerting(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_BEARER_CAPABILITY:
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_DISPLAY:
+ case Q931ie_SIGNAL:
+ case Q931ie_HIGH_LAYER_COMPATIBILITY:
+ case Q931ie_USER_USER:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Alerting
+
+*****************************************************************************/
+L3INT Q931Pmes_Alerting(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Bearer capability */
+ if (Q931IsIEPresent(pMes->BearerCap)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Channel Identification */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* High Layer Compatibility */
+ if (Q931IsIEPresent(pMes->HLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_CallProceeding
+
+*****************************************************************************/
+L3INT Q931Umes_CallProceeding(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_BEARER_CAPABILITY:
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_DISPLAY:
+ case Q931ie_HIGH_LAYER_COMPATIBILITY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_CallProceeding
+
+*****************************************************************************/
+L3INT Q931Pmes_CallProceeding(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Bearer capability */
+ if (Q931IsIEPresent(pMes->BearerCap)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Channel Identification */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* High Layer Compatibility */
+ if (Q931IsIEPresent(pMes->HLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_CongestionControl
+
+*****************************************************************************/
+L3INT Q931Umes_CongestionControl(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(mes);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+
+/*****************************************************************************
+
+ Function: Q931Pmes_CongestionControl
+
+*****************************************************************************/
+L3INT Q931Pmes_CongestionControl(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ *OSize = 0;
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Connect
+
+*****************************************************************************/
+L3INT Q931Umes_Connect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_BEARER_CAPABILITY:
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_DISPLAY:
+ case Q931ie_DATETIME:
+ case Q931ie_SIGNAL:
+ case Q931ie_LOW_LAYER_COMPATIBILITY:
+ case Q931ie_HIGH_LAYER_COMPATIBILITY:
+ case Q931ie_CONNECTED_NUMBER: /* not actually used, seen while testing BRI PTMP TE */
+ case Q931ie_USER_USER:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+
+ default:
+ Q931Log(pTrunk, Q931_LOG_ERROR, "Illegal IE %#hhx in Connect Message\n", IBuf[IOff]);
+
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Connect
+
+*****************************************************************************/
+L3INT Q931Pmes_Connect(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Bearer capability */
+ if (Q931IsIEPresent(pMes->BearerCap)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Channel Identification */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Date/Time */
+ if (Q931IsIEPresent(pMes->DateTime)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Low Layer Compatibility */
+ if (Q931IsIEPresent(pMes->LLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* High Layer Compatibility */
+ if (Q931IsIEPresent(pMes->HLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_ConnectAck
+
+*****************************************************************************/
+L3INT Q931Umes_ConnectAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_DISPLAY:
+ case Q931ie_SIGNAL:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+
+/*****************************************************************************
+
+ Function: Q931Pmes_ConnectAck
+
+*****************************************************************************/
+L3INT Q931Pmes_ConnectAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Disconnect
+
+*****************************************************************************/
+L3INT Q931Umes_Disconnect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CAUSE:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_DISPLAY:
+ case Q931ie_SIGNAL:
+ case Q931ie_FACILITY:
+ case Q931ie_USER_USER:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Disconnect
+
+*****************************************************************************/
+L3INT Q931Pmes_Disconnect(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Cause */
+ if (Q931IsIEPresent(pMes->Cause)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Information
+
+*****************************************************************************/
+L3INT Q931Umes_Information(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_SENDING_COMPLETE:
+ case Q931ie_DISPLAY:
+ case Q931ie_KEYPAD_FACILITY:
+ case Q931ie_CALLED_PARTY_NUMBER:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Information
+
+*****************************************************************************/
+L3INT Q931Pmes_Information(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Sending Complete */
+ if (Q931IsIEPresent(pMes->SendComplete)) {
+ OBuf[Octet++] = (L3UCHAR)(pMes->SendComplete & 0x00ff);
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Keypad Facility */
+ if (Q931IsIEPresent(pMes->KeypadFac)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Called Party number */
+ if (Q931IsIEPresent(pMes->CalledNum)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Notify
+
+*****************************************************************************/
+L3INT Q931Umes_Notify(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_BEARER_CAPABILITY:
+ case Q931ie_NOTIFICATION_INDICATOR:
+ case Q931ie_DISPLAY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Notify
+
+*****************************************************************************/
+L3INT Q931Pmes_Notify(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Bearer capability */
+ if (Q931IsIEPresent(pMes->BearerCap)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Progress
+
+*****************************************************************************/
+L3INT Q931Umes_Progress(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_BEARER_CAPABILITY:
+ case Q931ie_CAUSE:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_DISPLAY:
+ case Q931ie_HIGH_LAYER_COMPATIBILITY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Progress
+
+*****************************************************************************/
+L3INT Q931Pmes_Progress(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Bearer capability */
+ if (Q931IsIEPresent(pMes->BearerCap)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Cause */
+ if (Q931IsIEPresent(pMes->Cause)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* High Layer Compatibility */
+ if (Q931IsIEPresent(pMes->HLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Release
+
+*****************************************************************************/
+L3INT Q931Umes_Release(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CAUSE:
+ case Q931ie_DISPLAY:
+ case Q931ie_SIGNAL:
+ case Q931ie_USER_USER:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Release
+
+*****************************************************************************/
+L3INT Q931Pmes_Release(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Cause */
+ if (Q931IsIEPresent(pMes->Cause)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_ReleaseComplete
+
+*****************************************************************************/
+L3INT Q931Umes_ReleaseComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CAUSE:
+ case Q931ie_DISPLAY:
+ case Q931ie_SIGNAL:
+ case Q931ie_USER_USER:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_ReleaseComplete
+
+*****************************************************************************/
+L3INT Q931Pmes_ReleaseComplete(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Cause */
+ if (Q931IsIEPresent(pMes->Cause)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Restart
+
+*****************************************************************************/
+L3INT Q931Umes_Restart(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_DISPLAY:
+ case Q931ie_RESTART_INDICATOR:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Restart
+
+*****************************************************************************/
+L3INT Q931Pmes_Restart(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* ChanID */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* RestartInd */
+ if (Q931IsIEPresent(pMes->RestartInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_RESTART_INDICATOR](pTrunk, Q931GetIEPtr(pMes->RestartInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_RestartAck
+
+*****************************************************************************/
+L3INT Q931Umes_RestartAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size)
+{
+ Q931mes_Generic *mes = (Q931mes_Generic*)OBuf;
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_DISPLAY:
+ case Q931ie_RESTART_INDICATOR:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_RestartAck
+
+*****************************************************************************/
+L3INT Q931Pmes_RestartAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* ChanID */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* RestartInd */
+ if (Q931IsIEPresent(pMes->RestartInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_RESTART_INDICATOR](pTrunk, Q931GetIEPtr(pMes->RestartInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Resume
+
+*****************************************************************************/
+L3INT Q931Umes_Resume(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CALL_IDENTITY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Resume
+
+*****************************************************************************/
+L3INT Q931Pmes_Resume(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Call Identity */
+ if (Q931IsIEPresent(pMes->CallID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALL_IDENTITY](pTrunk, Q931GetIEPtr(pMes->CallID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_ResumeAck
+
+*****************************************************************************/
+L3INT Q931Umes_ResumeAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_DISPLAY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+
+/*****************************************************************************
+
+ Function: Q931Pmes_ResumeAck
+
+*****************************************************************************/
+L3INT Q931Pmes_ResumeAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Channel Identification */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_ResumeReject
+
+*****************************************************************************/
+L3INT Q931Umes_ResumeReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CAUSE:
+ case Q931ie_DISPLAY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+
+/*****************************************************************************
+
+ Function: Q931Pmes_ResumeReject
+
+*****************************************************************************/
+L3INT Q931Pmes_ResumeReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Cause */
+ if (Q931IsIEPresent(pMes->Cause)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+L3INT Q931Umes_Segment(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT OOff)
+{
+ L3INT i = IOff;
+
+ return IOff - i;
+}
+
+L3INT Q931Pmes_Segment(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ *OSize = 0;
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Setup
+
+*****************************************************************************/
+L3INT Q931Umes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT ir = 0;
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_SENDING_COMPLETE:
+ IOff++;
+ break;
+
+ case Q931ie_BEARER_CAPABILITY:
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_NETWORK_SPECIFIC_FACILITIES:
+ case Q931ie_DISPLAY:
+ case Q931ie_DATETIME:
+ case Q931ie_KEYPAD_FACILITY:
+ case Q931ie_SIGNAL:
+ case Q931ie_CALLING_PARTY_NUMBER:
+ case Q931ie_CALLING_PARTY_SUBADDRESS:
+ case Q931ie_CALLED_PARTY_NUMBER:
+ case Q931ie_CALLED_PARTY_SUBADDRESS:
+ case Q931ie_TRANSIT_NETWORK_SELECTION:
+ case Q931ie_LOW_LAYER_COMPATIBILITY:
+ case Q931ie_HIGH_LAYER_COMPATIBILITY:
+ case Q931ie_FACILITY:
+ case Q931ie_USER_USER:
+ case Q931ie_REDIRECTING_NUMBER:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+
+ case Q931ie_REPEAT_INDICATOR:
+ if (ir < 2) {
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ ir++;
+ } else {
+ return Q931E_ILLEGAL_IE;
+ }
+ break;
+
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Setup
+
+ Decription: Pack a Q931mes_Generic into a real Q.931 message. The user will
+ set up a SETUP message and issue this to the stack where it
+ is processed by Q931ProcSetup that processes and validates
+ it before it actually sends it out. This function is called
+ to compute the real Q.931 message.
+
+ Parameters: IBuf[IN] Ptr to un-packed struct
+ ISize[IN] Size of input buffer (unpacked message).
+ OBuf[OUT] Ptr to packed 'octet' wise message.
+ OSize[OUT] Size of packed message.
+
+ Called By: Q931ProcSetup
+
+*****************************************************************************/
+L3INT Q931Pmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Sending Complete */
+ if (Q931IsIEPresent(pMes->SendComplete)) {
+ OBuf[Octet++] = (L3UCHAR)Q931ie_SENDING_COMPLETE & 0xff;
+ }
+
+ /* Repeat Indicator */
+ if (Q931IsIEPresent(pMes->RepeatInd)) {
+ OBuf[Octet++] = (L3UCHAR)Q931ie_REPEAT_INDICATOR & 0xff;
+ }
+
+ /* Bearer capability */
+ if (Q931IsIEPresent(pMes->BearerCap)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ } else {
+ rc = Q931E_BEARERCAP;
+ }
+
+ /* Channel Identification */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Network spesific facilities */
+ if (Q931IsIEPresent(pMes->NetFac)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_NETWORK_SPECIFIC_FACILITIES](pTrunk, Q931GetIEPtr(pMes->NetFac,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Date/Time */
+ if (Q931IsIEPresent(pMes->DateTime)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Keypad Facility */
+ if (Q931IsIEPresent(pMes->KeypadFac)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Calling Party Number */
+ if (Q931IsIEPresent(pMes->CallingNum)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CallingNum,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Calling Party Subaddress */
+ if (Q931IsIEPresent(pMes->CallingSub)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CallingSub,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Called Party number */
+ if (Q931IsIEPresent(pMes->CalledNum)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Called party subaddress */
+ if (Q931IsIEPresent(pMes->CalledSub)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CalledSub,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Transit network selection */
+ if (Q931IsIEPresent(pMes->TransNetSel)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_TRANSIT_NETWORK_SELECTION](pTrunk, Q931GetIEPtr(pMes->TransNetSel,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Repeat Indicator */
+ if (Q931IsIEPresent(pMes->LLRepeatInd)) {
+ rc = Q931E_UNKNOWN_IE;/* TODO */
+ }
+
+ /* Low Layer Compatibility */
+ if (Q931IsIEPresent(pMes->LLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* High Layer Compatibility */
+ if (Q931IsIEPresent(pMes->HLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_SetupAck
+
+*****************************************************************************/
+L3INT Q931Umes_SetupAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_DISPLAY:
+ case Q931ie_SIGNAL:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_SetupAck
+
+*****************************************************************************/
+L3INT Q931Pmes_SetupAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Channel Identification */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Status
+
+*****************************************************************************/
+L3INT Q931Umes_Status(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CAUSE:
+ case Q931ie_CALL_STATE:
+ case Q931ie_DISPLAY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Status
+
+*****************************************************************************/
+L3INT Q931Pmes_Status(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Cause */
+ if (Q931IsIEPresent(pMes->Cause)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Call State */
+ if (Q931IsIEPresent(pMes->CallState)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALL_STATE](pTrunk, Q931GetIEPtr(pMes->CallState,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_StatusEnquiry
+
+*****************************************************************************/
+L3INT Q931Umes_StatusEnquiry(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_DISPLAY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_StatusEnquiry
+
+*****************************************************************************/
+L3INT Q931Pmes_StatusEnquiry(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Suspend
+
+*****************************************************************************/
+L3INT Q931Umes_Suspend(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CALL_IDENTITY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Suspend
+
+*****************************************************************************/
+L3INT Q931Pmes_Suspend(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Call Identity */
+ if (Q931IsIEPresent(pMes->CallID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALL_IDENTITY](pTrunk, Q931GetIEPtr(pMes->CallID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_SuspendAck
+
+*****************************************************************************/
+L3INT Q931Umes_SuspendAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_DISPLAY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_SuspendAck
+
+*****************************************************************************/
+L3INT Q931Pmes_SuspendAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_SuspendReject
+
+*****************************************************************************/
+L3INT Q931Umes_SuspendReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CAUSE:
+ case Q931ie_DISPLAY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_SuspendReject
+
+*****************************************************************************/
+L3INT Q931Pmes_SuspendReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Cause */
+ if (Q931IsIEPresent(pMes->Cause)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_UserInformation
+
+*****************************************************************************/
+L3INT Q931Umes_UserInformation(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT I, L3INT O)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(mes);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_UserInformation
+
+*****************************************************************************/
+L3INT Q931Pmes_UserInformation(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ *OSize = 0;
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Service
+
+*****************************************************************************/
+L3INT Q931Umes_Service(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ case Q931ie_CHANGE_STATUS:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Service
+
+*****************************************************************************/
+L3INT Q931Pmes_Service(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ if (Q931IsIEPresent(pMes->ChangeStatus)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANGE_STATUS](pTrunk, Q931GetIEPtr(pMes->ChangeStatus,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_ServiceAck
+
+*****************************************************************************/
+L3INT Q931Umes_ServiceAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ case Q931ie_CHANGE_STATUS:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_ServiceAck
+
+*****************************************************************************/
+L3INT Q931Pmes_ServiceAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ if (Q931IsIEPresent(pMes->ChangeStatus)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANGE_STATUS](pTrunk, Q931GetIEPtr(pMes->ChangeStatus,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
Added: freeswitch/trunk/libs/freetdm/src/isdn/Q932mes.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/Q932mes.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/Q932mes.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,286 @@
+/*****************************************************************************
+
+ FileName: Q932mes.c
+
+ Contents: Q.932 Message Encoders/Decoders
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "Q931.h"
+
+/*****************************************************************************
+
+ Function: Q932Umes_Facility
+
+*****************************************************************************/
+
+L3INT Q932Umes_Facility(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+
+ /* TODO */
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Facility
+
+*****************************************************************************/
+L3INT Q932Pmes_Facility(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q932Umes_Hold
+
+*****************************************************************************/
+
+L3INT Q932Umes_Hold(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+
+ /* TODO */
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Hold
+
+*****************************************************************************/
+L3INT Q932Pmes_Hold(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q932Umes_HoldAck
+
+*****************************************************************************/
+
+L3INT Q932Umes_HoldAck(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+
+ /* TODO */
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_HoldAck
+
+*****************************************************************************/
+L3INT Q932Pmes_HoldAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q932Umes_HoldReject
+
+*****************************************************************************/
+
+L3INT Q932Umes_HoldReject(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+
+ /* TODO */
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_HoldReject
+
+*****************************************************************************/
+L3INT Q932Pmes_HoldReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q932Umes_Register
+
+*****************************************************************************/
+
+L3INT Q932Umes_Register(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+
+ /* TODO */
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Register
+
+*****************************************************************************/
+L3INT Q932Pmes_Register(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q932Umes_Retrieve
+
+*****************************************************************************/
+
+L3INT Q932Umes_Retrieve(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+
+ /* TODO */
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Retrieve
+
+*****************************************************************************/
+L3INT Q932Pmes_Retrieve(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q932Umes_RetrieveAck
+
+*****************************************************************************/
+
+L3INT Q932Umes_RetrieveAck(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+
+ /* TODO */
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_RetrieveAck
+
+*****************************************************************************/
+L3INT Q932Pmes_RetrieveAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q932Umes_RetrieveReject
+
+*****************************************************************************/
+
+L3INT Q932Umes_RetrieveReject(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+
+ /* TODO */
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_RetrieveReject
+
+*****************************************************************************/
+L3INT Q932Pmes_RetrieveReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
Added: freeswitch/trunk/libs/freetdm/src/isdn/include/5ESS.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/include/5ESS.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/include/5ESS.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,103 @@
+/******************************************************************************
+
+ FileName: 5ESS.h
+
+ Contents: Header and definition for the AT&T 5ESS ISDN dialect. The
+ header contains the following parts:
+
+ - Definition of codes
+ - Definition of information elements (5ESSie_).
+ - Definition of messages (5ESSmes_).
+ - Function prototypes.
+
+ Description: The AT&T 5ESS ISDN dialect here covers ????
+
+ Related Files: 5ESS.h AT&T 5ESS ISDN Definitions
+ 5ESSie.c AT&T 5ESS ISDN IE encoders/coders (not extant yet)
+ See Q931ie.c for IE encoders/coders
+ 5ESSStateTE.c AT&T 5ESS ISDN TE State Engine
+ 5ESSStateNT.c AT&T 5ESS ISDN NT State Engine
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ Copyright (c) 2007, Michael S. Collins, All rights reserved.
+ email:mcollins@fcnetwork.com
+
+ 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 Case Labs, Ltd 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.
+******************************************************************************/
+
+#ifndef _5ESS_NL
+#define _5ESS_NL
+
+#include "Q931.h"
+
+/*****************************************************************************
+
+ Q.931 Message codes
+ Only 5ESS specific message and ie types
+ here the rest are inherited from Q931.h
+
+*****************************************************************************/
+
+
+/*****************************************************************************
+
+ Q.931 Message Pack/Unpack functions. Implemented in 5ESSmes.c
+ Note: Because C variables may not begin with numeric digit, all identifiers
+ are prefixed with "ATT5ESS" instead of a bare "5ESS"
+
+*****************************************************************************/
+L3INT ATT5ESSUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT ATT5ESSPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT ATT5ESSUmes_SetupAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT ATT5ESSPmes_SetupAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+L3INT ATT5ESSUmes_0x07(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT ATT5ESSPmes_0x07(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT ATT5ESSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT ATT5ESSPmes_0x0f(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+
+
+/*****************************************************************************
+
+ Q.931 Process Function Prototyping. Implemented in 5ESSStateTE.c
+
+*****************************************************************************/
+L3INT ATT5ESSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom);
+L3INT ATT5ESSProc0x07TE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom);
+
+
+void ATT5ESSCreateTE(L3UCHAR i);
+void ATT5ESSCreateNT(L3UCHAR i);
+
+#endif /* _5ESS_NL */
Added: freeswitch/trunk/libs/freetdm/src/isdn/include/DMS.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/include/DMS.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/include/DMS.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,91 @@
+/******************************************************************************
+
+ FileName: national.h
+
+ Contents: Header and definition for the National ISDN dialect. The
+ header contents the following parts:
+ - Definition of codes
+ - Definition of information elements (nationalie_).
+ - Definition of messages (nationalmes_).
+ - Function prototypes.
+
+ Description: The National ISDN dialect here covers ????
+
+ Related Files: national.h National ISDN Definitions
+ nationalie.c National ISDN IE encoders/coders
+ nationalStateTE.c National ISDN TE State Engine
+ nationalStateNT.c National ISDN NT State Engine
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ 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 Case Labs, Ltd 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.
+******************************************************************************/
+
+#ifndef _DMS_NL
+#define _DMS_NL
+
+#include "Q931.h"
+
+/*****************************************************************************
+
+ Q.931 Message codes
+ Only National specific message and ie types
+ here the rest are inherited from national.h
+
+*****************************************************************************/
+
+
+/*****************************************************************************
+
+ Q.931 Message Pack/Unpack functions. Implemented in nationalmes.c
+
+*****************************************************************************/
+L3INT DMSUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT DMSPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT DMSUmes_0x07(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT DMSPmes_0x07(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT DMSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT DMSPmes_0x0f(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+/*****************************************************************************
+
+ Q.931 Process Function Prototyping. Implemented in nationalStateTE.c
+
+*****************************************************************************/
+
+L3INT DMSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom);
+L3INT DMSProc0x07TE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom);
+
+void DMSCreateTE(L3UCHAR i);
+void DMSCreateNT(L3UCHAR i);
+
+#endif /* _DMS_NL */
Added: freeswitch/trunk/libs/freetdm/src/isdn/include/Q921.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/include/Q921.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/include/Q921.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,227 @@
+/*****************************************************************************
+
+ FileName: q921.h
+
+ Description: Contains headers of a Q.921 protocol.
+
+ Note: This header file is the only include file that should be
+ acessed by users of the Q.921 stack.
+
+ Interface: The Q.921 stack contains 2 layers.
+
+ - One interface layer.
+ - One driver layer.
+
+ The interface layer contains the interface functions required
+ for a layer 2 stack to be able to send and receive messages.
+
+ The driver layer will simply feed bytes into the ship as
+ required and queue messages received out from the ship.
+
+ Q921TimeTick The Q.921 like any other blackbox
+ modules contains no thread by it's own
+ and must therefore be called regularly
+ by an external 'thread' to do maintenance
+ etc.
+
+ Q921Rx32 Receive message from layer 3. Called by
+ the layer 3 stack to send a message.
+
+
+ NOTE: The following are not yet implemented
+
+ OnQ921Error Function called every if an error is
+ detected.
+
+ OnQ921Log Function called if logging is active.
+
+
+ <TODO> Maintenance/Configuration interface
+ <TODO> Logging
+ <TODO> DL_ message passing to layer 3
+ <TODO> Timers
+ <TODO> Api commands to tell 921 to stop and start for a trunk
+
+ Created: 27.dec.2000/JVB
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+
+*****************************************************************************/
+
+/****************************************************************************
+ * Changes:
+ *
+ * - June,July 2008: Stefan Knoblich <s.knoblich@axsentis.de>:
+ * Add PTMP TEI management
+ * Add timers
+ * Add retransmit counters
+ * Add logging
+ * Various cleanups
+ *
+ ****************************************************************************/
+
+#ifndef _Q921
+#define _Q921
+
+#define Q921MAXHDLCSPACE 3000
+#define L2UCHAR unsigned char /* Min 8 bit */
+#define L2USHORT unsigned short /* 16 bit */
+#define L2INT int /* Min 16 bit signed */
+#define L2ULONG unsigned long /* Min 32 bit */
+#define L2TRUNK Q921Data_t *
+
+#define Q921_TEI_BCAST 127
+#define Q921_TEI_MAX Q921_TEI_BCAST
+
+#define Q921_TEI_DYN_MIN 64
+#define Q921_TEI_DYN_MAX 126
+
+
+typedef enum /* Network/User Mode */
+{
+ Q921_TE=0, /* 0 : User Mode */
+ Q921_NT=1 /* 1 : Network Mode */
+} Q921NetUser_t;
+
+typedef enum /* Type of connection */
+{
+ Q921_PTP=0, /* 0 : Point-To-Point */
+ Q921_PTMP=1 /* 1 : Point-To-Multipoint */
+} Q921NetType_t;
+
+typedef enum
+{
+ Q921_LOG_NONE = -1,
+ Q921_LOG_EMERG = 0,
+ Q921_LOG_ALERT,
+ Q921_LOG_CRIT,
+ Q921_LOG_ERROR,
+ Q921_LOG_WARNING,
+ Q921_LOG_NOTICE,
+ Q921_LOG_INFO,
+ Q921_LOG_DEBUG
+} Q921LogLevel_t;
+
+
+/*
+ * Messages for L2 <-> L3 communication
+ */
+typedef enum {
+ Q921_DL_ESTABLISH = 0,
+ Q921_DL_ESTABLISH_CONFIRM,
+ Q921_DL_RELEASE,
+ Q921_DL_RELEASE_CONFIRM,
+ Q921_DL_DATA,
+ Q921_DL_UNIT_DATA
+} Q921DLMsg_t;
+
+typedef int (*Q921Tx21CB_t) (void *, L2UCHAR *, L2INT);
+typedef int (*Q921Tx23CB_t) (void *, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *, L2INT);
+typedef int (*Q921LogCB_t) (void *, Q921LogLevel_t, char *, L2INT);
+
+struct Q921_Link;
+
+typedef struct Q921Data
+{
+ L2INT initialized;
+
+ L2UCHAR sapi; /*!< User assigned SAPI */
+ L2UCHAR tei; /*!< User assigned TEI value */
+
+ L2INT Q921HeaderSpace;
+ Q921NetUser_t NetUser;
+ Q921NetType_t NetType;
+
+ struct Q921_Link *context; /*!< per-TEI / link context space */
+
+ /* timers */
+ L2ULONG T202; /*!< PTMP TE mode TEI retransmit timer */
+ L2ULONG T200Timeout;
+ L2ULONG T201Timeout;
+ L2ULONG T202Timeout;
+ L2ULONG T203Timeout;
+
+ L2ULONG TM01Timeout;
+
+ /* counters */
+ L2ULONG N200Limit; /*!< max retransmit */
+
+ L2ULONG N202; /*!< PTMP TE mode retransmit counter */
+ L2ULONG N202Limit; /*!< PTMP TE mode max retransmit */
+
+ L2ULONG N201Limit; /*!< max number of octets */
+ L2ULONG k; /*!< max number of unacknowledged I frames */
+
+ /* callbacks and callback data pointers */
+ Q921Tx21CB_t Q921Tx21Proc;
+ Q921Tx23CB_t Q921Tx23Proc;
+ void *PrivateData21;
+ void *PrivateData23;
+
+ /* logging */
+ Q921LogLevel_t loglevel; /*!< trunk loglevel */
+ Q921LogCB_t Q921LogProc; /*!< log callback procedure */
+ void *PrivateDataLog; /*!< private data pointer for log proc */
+
+ /* tei mgmt */
+ L2UCHAR tei_map[Q921_TEI_MAX]; /*!< */
+
+ L2UCHAR HDLCInQueue[Q921MAXHDLCSPACE]; /*!< HDLC input queue */
+} Q921Data_t;
+
+/*
+ * Public functions
+ */
+int Q921_InitTrunk(L2TRUNK trunk,
+ L2UCHAR sapi,
+ L2UCHAR tei,
+ Q921NetUser_t NetUser,
+ Q921NetType_t NetType,
+ L2INT hsize,
+ Q921Tx21CB_t cb21,
+ Q921Tx23CB_t cb23,
+ void *priv21,
+ void *priv23);
+int Q921Start(L2TRUNK trunk);
+int Q921Stop(L2TRUNK trunk);
+
+void Q921SetLogCB(L2TRUNK trunk, Q921LogCB_t func, void *priv);
+void Q921SetLogLevel(L2TRUNK trunk, Q921LogLevel_t level);
+
+int Q921Rx12(L2TRUNK trunk);
+int Q921Rx32(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR * Mes, L2INT Size);
+
+int Q921QueueHDLCFrame(L2TRUNK trunk, L2UCHAR *b, L2INT size);
+
+void Q921SetGetTimeCB(L2ULONG (*callback)(void));
+void Q921TimerTick(L2TRUNK trunk);
+
+#endif
Added: freeswitch/trunk/libs/freetdm/src/isdn/include/Q921priv.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/include/Q921priv.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/include/Q921priv.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,321 @@
+/*****************************************************************************
+
+ FileName: Q921priv.h
+
+ Description: Private declarations
+
+ Created: 08.Aug.2008/STKN
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2008, Stefan Knoblich, axsentis GmbH. All rights reserved.
+ email:s.knoblich@axsentis.de
+
+ 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 Case Labs, Ltd 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.
+
+*****************************************************************************/
+#ifndef _Q921_PRIV_H_
+#define _Q921_PRIV_H_
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+#if (_MSC_VER >= 1400) /* VC8+ */
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+#ifndef _CRT_NONSTDC_NO_DEPRECATE
+#define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+#endif
+#ifndef strcasecmp
+#define strcasecmp(s1, s2) _stricmp(s1, s2)
+#endif
+#ifndef strncasecmp
+#define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n)
+#endif
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#endif
+
+typedef enum /* Q.921 States */
+{
+ Q921_STATE_STOPPED = 0, /* Trunk stopped */
+ Q921_STATE_TEI_UNASSIGNED = 1, /* TEI unassigned */
+ Q921_STATE_TEI_AWAITING, /* Assign awaiting TEI */
+ Q921_STATE_TEI_ESTABLISH, /* Establish awaiting TEI */
+ Q921_STATE_TEI_ASSIGNED, /* TEI assigned */
+ Q921_STATE_AWAITING_ESTABLISHMENT, /* Awaiting establishment */
+ Q921_STATE_AWAITING_RELEASE, /* Awaiting release */
+ Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, /* Multiple frame established */
+ Q921_STATE_TIMER_RECOVERY /* Timer recovery */
+} Q921State_t;
+
+/*
+ * Flags
+ */
+enum Q921_Flags {
+ Q921_FLAG_L3_INITIATED = (1 << 0),
+
+ Q921_FLAG_UI_FRAME_QUEUED = (1 << 1),
+ Q921_FLAG_I_FRAME_QUEUED = (1 << 2),
+
+ Q921_FLAG_ACK_PENDING = (1 << 3),
+ Q921_FLAG_REJECT = (1 << 4),
+
+ Q921_FLAG_RECV_BUSY = (1 << 5),
+ Q921_FLAG_PEER_RECV_BUSY = (1 << 6)
+};
+
+#define Q921_SET_FLAG(x, f) ((x)->flags |= f)
+#define Q921_CHECK_FLAG(x, f) ((x)->flags & f)
+#define Q921_CLEAR_FLAG(x, f) ((x)->flags &= ~f)
+
+
+/*
+ * dynamic TEI handling
+ */
+#define Q921_SAPI_TEI 63 /* SAPI for all TEI Messages */
+#define Q921_LAYER_ENT_ID_TEI 0x0f /* UN Layer Management Entity ID for TEI Mgmt */
+#define Q921_LAYER_ENT_ID_Q931 0x08 /* Q.931 Layer Management Entity ID */
+
+
+typedef enum {
+ Q921_TEI_ID_REQUEST = 1,
+ Q921_TEI_ID_ASSIGNED,
+ Q921_TEI_ID_DENIED,
+ Q921_TEI_ID_CHECKREQ,
+ Q921_TEI_ID_CHECKRESP,
+ Q921_TEI_ID_REMOVE,
+ Q921_TEI_ID_VERIFY
+} Q921TeiMessageType_t;
+
+
+/**
+ * Per-Datalink context
+ */
+struct Q921_Link {
+ L2UCHAR tei; /*!< This endpoint's TEI */
+
+ L2UCHAR va;
+ L2UCHAR vs;
+ L2UCHAR vr;
+
+ L2INT flags;
+ Q921State_t state;
+
+ L2ULONG N202; /*!< PTMP TE mode retransmit counter */
+ L2ULONG N200; /*!< retransmit counter (per-TEI in PTMP NT mode) */
+
+ L2ULONG TM01; /*!< Datalink inactivity disconnect timer */
+
+ L2ULONG T200;
+ L2ULONG T201; /*!< PTMP NT mode timer */
+ L2ULONG T203;
+
+ L2USHORT ri; /*!< random id for TEI request mgmt */
+
+ /* I + UI Frame queue */
+ L2UCHAR UIFrameQueue[Q921MAXHDLCSPACE];
+ L2UCHAR IFrameQueue[Q921MAXHDLCSPACE];
+ L2UCHAR IFrameResendQueue[Q921MAXHDLCSPACE];
+};
+
+
+#define Q921_LINK_CONTEXT(tr, tei) \
+ (Q921_IS_PTMP_NT(tr) && tei != Q921_TEI_BCAST) ? ((struct Q921_Link *)&(tr)->context[tei]) : (tr)->context
+
+#define Q921_TRUNK_CONTEXT(tr) \
+ (tr)->context
+
+#define Q921_LOGBUFSIZE 2000
+#define INITIALIZED_MAGIC 42
+
+/*
+ * Helper macros
+ */
+#define Q921_INC_COUNTER(x) (x = (x + 1) % 128)
+#define Q921_DEC_COUNTER(x) (x = (x) ? (x - 1) : 127)
+
+#define Q921_UFRAME_HEADER_SIZE 3
+#define Q921_UFRAME_DATA_OFFSET(tr) ((tr)->Q921HeaderSpace + Q921_UFRAME_HEADER_SIZE)
+
+#define Q921_SFRAME_HEADER_SIZE 4
+#define Q921_SFRAME_DATA_OFFSET(tr) ((tr)->Q921HeaderSpace + Q921_SFRAME_HEADER_SIZE)
+
+#define Q921_IFRAME_HEADER_SIZE 4
+#define Q921_IFRAME_DATA_OFFSET(tr) ((tr)->Q921HeaderSpace + Q921_IFRAME_HEADER_SIZE)
+
+#define Q921_IS_TE(x) ((x)->NetUser == Q921_TE)
+#define Q921_IS_NT(x) ((x)->NetUser == Q921_NT)
+
+#define Q921_IS_STOPPED(tr) ((tr)->state == Q921_STATE_STOPPED)
+
+/* TODO: rework this one */
+#define Q921_IS_READY(tr) ((tr)->state >= Q921_STATE_TEI_ASSIGNED)
+
+#define Q921_IS_PTMP(x) ((x)->NetType == Q921_PTMP)
+#define Q921_IS_PTMP_TE(x) ((x)->NetType == Q921_PTMP && (x)->NetUser == Q921_TE)
+#define Q921_IS_PTMP_NT(x) ((x)->NetType == Q921_PTMP && (x)->NetUser == Q921_NT)
+
+#define Q921_IS_PTP(x) ((x)->NetType == Q921_PTP)
+#define Q921_IS_PTP_TE(x) ((x)->NetType == Q921_PTP && (x)->NetUser == Q921_TE)
+#define Q921_IS_PTP_NT(x) ((x)->NetType == Q921_PTP && (x)->NetUser == Q921_NT)
+
+/* Make life a little easier */
+#define Q921_COMMAND(x) ((x)->NetUser == Q921_TE ? 0 : 1)
+#define Q921_RESPONSE(x) ((x)->NetUser == Q921_TE ? 1 : 0)
+
+#define Q921_IS_COMMAND(tr, x) ((x) == (Q921_IS_TE(tr) ? 1 : 0))
+#define Q921_IS_RESPONSE(tr, x) ((x) == (Q921_IS_TE(tr) ? 0 : 1))
+
+
+/*******************************************************************************
+ * Private functions
+ *******************************************************************************/
+
+/*
+ * L1 / L2 Interface
+ */
+static int Q921Tx21Proc(L2TRUNK trunk, L2UCHAR *Msg, L2INT size);
+static int Q921Tx23Proc(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *Msg, L2INT size);
+
+
+/*
+ * Timers
+ */
+static L2ULONG Q921GetTime(void);
+
+static void Q921T200TimerStart(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T200TimerStop(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T200TimerReset(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T200TimerExpire(L2TRUNK trunk, L2UCHAR tei);
+
+static void Q921T201TimerStart(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T201TimerStop(L2TRUNK trunk, L2UCHAR tei);
+/* static void Q921T201TimerReset(L2TRUNK trunk, L2UCHAR tei); - Unused for now */
+static void Q921T201TimerExpire(L2TRUNK trunk, L2UCHAR tei);
+
+static void Q921T202TimerStart(L2TRUNK trunk);
+static void Q921T202TimerStop(L2TRUNK trunk);
+static void Q921T202TimerReset(L2TRUNK trunk);
+static void Q921T202TimerExpire(L2TRUNK trunk);
+
+static void Q921T203TimerStart(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T203TimerStop(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T203TimerReset(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T203TimerExpire(L2TRUNK trunk, L2UCHAR tei);
+
+static void Q921TM01TimerStart(L2TRUNK trunk, L2UCHAR tei);
+/* static void Q921TM01TimerStop(L2TRUNK trunk, L2UCHAR tei); - Unused for now */
+static void Q921TM01TimerReset(L2TRUNK trunk, L2UCHAR tei);
+/* static void Q921TM01TimerExpire(L2TRUNK trunk, L2UCHAR tei); - Unused for now */
+
+/*
+ * Frame encoding
+ */
+static int Q921SendS(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR sv, L2UCHAR *mes, L2INT size);
+static int Q921SendU(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR m, L2UCHAR *mes, L2INT size);
+
+static int Q921SendRNR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendREJ(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendSABME(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendDM(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendDISC(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendUA(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendUN(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf, L2UCHAR *mes, L2INT size);
+static int Q921SendRR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+
+/*
+ * Frame decoding
+ */
+static int Q921ProcIFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcSFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcUFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+
+static int Q921ProcSABME(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcDM(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcUA(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcDISC(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcRR(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcRNR(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcREJ(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+
+
+/*
+ * (Common) procedures defined in the Q.921 SDL
+ */
+static int Q921SendEnquiry(L2TRUNK trunk, L2UCHAR tei);
+static int Q921SendEnquiryResponse(L2TRUNK trunk, L2UCHAR tei);
+static void Q921ResetExceptionConditions(L2TRUNK trunk, L2UCHAR tei);
+static int Q921EstablishDataLink(L2TRUNK trunk, L2UCHAR tei);
+static int Q921NrErrorRecovery(L2TRUNK trunk, L2UCHAR tei);
+static int Q921InvokeRetransmission(L2TRUNK trunk, L2UCHAR tei, L2UCHAR nr);
+static int Q921AcknowledgePending(L2TRUNK trunk, L2UCHAR tei);
+/*
+static int Q921SetReceiverBusy(L2TRUNK trunk);
+static int Q921ClearReceiverBusy(L2TRUNK trunk);
+*/
+
+/*
+ * Queueing
+ */
+static int Q921SendQueuedIFrame(L2TRUNK trunk, L2UCHAR tei);
+static int Q921EnqueueI(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR *mes, L2INT size);
+
+/*
+ * TEI management
+ */
+static int Q921TeiSendAssignRequest(L2TRUNK trunk);
+static int Q921TeiProcAssignResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiSendVerifyRequest(L2TRUNK trunk);
+static int Q921TeiProcCheckRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiProcRemoveRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiProcAssignRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiProcCheckResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiProcVerifyRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiSendRemoveRequest(L2TRUNK trunk, L2UCHAR tei);
+static int Q921TeiSendDenyResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri);
+static int Q921TeiSendAssignedResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri);
+static int Q921TeiSendCheckRequest(L2TRUNK trunk, L2UCHAR tei);
+
+/*
+ * Logging
+ */
+static int Q921Log(L2TRUNK trunk, Q921LogLevel_t level, const char *fmt, ...);
+static int Q921LogMesg(L2TRUNK trunk, Q921LogLevel_t level, L2UCHAR received, L2UCHAR *mes, L2INT size, const char *fmt, ...);
+
+/*
+ * State handling
+ */
+static int Q921ChangeState(L2TRUNK trunk, Q921State_t state, L2UCHAR tei);
+
+#endif
Added: freeswitch/trunk/libs/freetdm/src/isdn/include/Q931.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/include/Q931.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/include/Q931.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1175 @@
+/******************************************************************************
+
+ FileName: Q931.h
+
+ Contents: Header and definition for the ITU-T Q.931 stack. The
+ header contents the following parts:
+
+ - Definition of codes
+ - Definition of information elements (Q931ie_).
+ - Definition of messages (Q931mes_).
+ - Definitian of variables (var_).
+ - Function prototypes.
+
+ Description: The Q.931 stack provided here covers ITU-T Q.931 w/Q.932
+ supplementary services for both PRI, BRI and variants.
+ The stack is generic and designed to deal with variants as
+ needed.
+
+ The stack uses the following interface functions:
+
+ - Q931Initialize Initialize the Q.931 stack.
+ - Q931Rx23 Receive a message from layer 2
+ - Q931Tx32 Send a message to layer 2
+ - Q931Rx43 Receive a message from layer 4 or above.
+ - Q931Tx34 Send a message to layer 4 or above.
+ - Q931TimeTick Periodical timer processing.
+ - Q931ErrorProc Callback for stack error message.
+
+ The protocol is a module with no external dependencies and
+ can easely be ported to any operating system like Windows,
+ Linux, rtos and others.
+
+ Related Files: Q931.h Q.931 Definitions
+ Q931.c Q.931 Interface Functions.
+ Q931api.c Low level L4 API functions.
+
+ Q932.h Q.932 Suplementary Services
+ Q932mes.c Q.932 encoders/coders
+
+ Q931mes.c Q.931 Message encoders/coders
+ Q931ie.c Q.931 IE encoders/coders
+ Q931StateTE.c Generic Q.931 TE State Engine
+ Q931StateNT.c Generic Q.931 NT State Engine
+
+ Design Note 1: For each variant please add separate files starting with
+ the variant short-name as follows:
+
+ <variant>.h Spesific headers needed.
+ <variant>mes.c Message encoders/decores.
+ <variant>ie.c IE encoders/decoders.
+ <variant>StateTE.c TE side state engine.
+ <variant>StateNT.c NT side state engine.
+
+ Design Note 2: The stack is deliberatly made non-threading. Use 1
+ thread per Trunk, but lock access from the timertick
+ and rx, tx functions. And make sure the callbacks only
+ dump messages to a queue, no time-consuming processing
+ inside stack processing.
+
+ All stack processing is async 'fire and forget', meaning
+ that there are not, and should not be any time-consuming
+ processing within the stack-time. The best way to thread
+ a stack is to use one single thread that signal 5 queues.
+
+ - Incoming L2 queue.
+ - Incoming L4 queue.
+ - Outgoing L2 queue.
+ - Outgoing L4 queue.
+ - Error/Trace queue.
+
+ Design Note 3: DSP optimization. The L3 (Rx23) can be called directly
+ from a HDLC receiver without usage of queues for optimized
+ processing. But keep in mind that Q.931 calls Tx34 or Tx32
+ as part of receiving a message from Layer 2.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+******************************************************************************/
+
+#ifndef _Q931_NL
+#define _Q931_NL
+
+/* uncomment the #define below to add x.25 support to the Q.931 */
+/* #define Q931_X25_SUPPORT */
+
+#include "stdio.h"
+
+#ifdef _MSC_VER
+#pragma warning(disable:4100)
+#ifndef strcasecmp
+#define strcasecmp(s1, s2) _stricmp(s1, s2)
+#endif
+#endif
+#include <string.h>
+
+
+/*****************************************************************************
+
+ Enum helper macros <Need description of these macros>
+
+*****************************************************************************/
+#define Q931_ENUM_NAMES(_NAME, _STRINGS) static const char * _NAME [] = { _STRINGS , NULL };
+#define Q931_STR2ENUM_P(_FUNC1, _FUNC2, _TYPE) _TYPE _FUNC1 (const char *name); const char * _FUNC2 (_TYPE type);
+#define Q931_STR2ENUM(_FUNC1, _FUNC2, _TYPE, _STRINGS, _MAX) \
+ _TYPE _FUNC1 (const char *name) \
+ { \
+ int i; \
+ _TYPE t = _MAX ; \
+ \
+ for (i = 0; i < _MAX ; i++) { \
+ if (!strcasecmp(name, _STRINGS[i])) { \
+ t = (_TYPE) i; \
+ break; \
+ } \
+ } \
+ \
+ return t; \
+ } \
+ const char * _FUNC2 (_TYPE type) \
+ { \
+ if (type > _MAX) { \
+ type = _MAX; \
+ } \
+ return _STRINGS[(int)type]; \
+ } \
+
+/*****************************************************************************
+
+ Error Codes
+
+*****************************************************************************/
+typedef enum {
+ Q931E_NO_ERROR = 0,
+
+ Q931E_UNKNOWN_MESSAGE = -3001,
+ Q931E_ILLEGAL_IE = -3002,
+ Q931E_UNKNOWN_IE = -3003,
+ Q931E_BEARERCAP = -3004,
+ Q931E_HLCOMP = -3005,
+ Q931E_LLCOMP = -3006,
+ Q931E_INTERNAL = -3007,
+ Q931E_MISSING_CB = -3008,
+ Q931E_UNEXPECTED_MESSAGE = -3009,
+ Q931E_ILLEGAL_MESSAGE = -3010,
+ Q931E_TOMANYCALLS = -3011,
+ Q931E_INVALID_CRV = -3012,
+ Q931E_CALLID = -3013,
+ Q931E_CALLSTATE = -3014,
+ Q931E_CALLEDSUB = -3015,
+ Q931E_CALLEDNUM = -3016,
+ Q931E_CALLINGNUM = -3017,
+ Q931E_CALLINGSUB = -3018,
+ Q931E_CAUSE = -3019,
+ Q931E_CHANID = -3020,
+ Q931E_DATETIME = -3021,
+ Q931E_DISPLAY = -3022,
+ Q931E_KEYPADFAC = -3023,
+ Q931E_NETFAC = -3024,
+ Q931E_NOTIFIND = -3025,
+ Q931E_PROGIND = -3026,
+ Q931E_RESTARTIND = -3027,
+ Q931E_SEGMENT = -3028,
+ Q931E_SIGNAL = -3029,
+ Q931E_GENERIC_DIGITS = -3030
+} q931_error_t;
+
+/* The q931_error_t enum should be kept in sync with the q931_error_names array in Q931.c */
+
+const char *q931_error_to_name(q931_error_t error);
+
+/*****************************************************************************
+
+ Some speed optimization can be achieved by changing all variables to the
+ word size of your processor. A 32 bit processor has to do a lot of extra
+ work to read a packed 8 bit integer. Changing all fields to 32 bit integer
+ will result in usage of some extra space, but will speed up the stack.
+
+ The stack has been designed to allow L3UCHAR etc. to be any size of 8 bit
+ or larger.
+
+*****************************************************************************/
+
+#define L3UCHAR unsigned char /* Min 8 bit */
+#define L3USHORT unsigned short /* Min 16 bit unsigned */
+#define L3UINT unsigned int /* Min 16 bit unsigned */
+#define L3INT int /* Min 16 bit signed */
+#define L3ULONG unsigned long /* Min 32 bit */
+#define L3BOOL char /* Min 1 bit, valuse 0 & 1 only */
+
+#define L3TRUE 1
+#define L3FALSE 0
+
+/*****************************************************************************
+
+ Global defines.
+
+*****************************************************************************/
+
+typedef L3USHORT ie; /* Special data type to hold a dynamic */
+ /* or optional information element as */
+ /* part of a message struct. MSB = 1 */
+ /* indicate that the ie is present, the */
+ /* last 15 bits is an offset ( or the */
+ /* value for single octet ) to the */
+ /* struct holding the ie. Offset = 0 */
+ /* is buf[1] etc. */
+ /* ie == 0xffff indicates error */
+
+/*****************************************************************************
+
+ MAXTRUNKS sets how many physical trunks this system might have. This
+ number should be keept at a minimum since it will use global space.
+
+ It is recommended that you leave MAXCHPERTRUNK as is
+
+*****************************************************************************/
+
+#define Q931_LOGBUFSIZE 1024 /* size of logging buffer */
+
+#define Q931L4BUF 1000 /* size of message buffer */
+
+#define Q931L2BUF 300 /* size of message buffer */
+
+#define Q931MAXTRUNKS 4 /* Total number of trunks that will be */
+ /* processed by this instance of the */
+ /* stack */
+
+#define Q931MAXCHPERTRUNK 32 /* Number of channels per trunk. The */
+ /* stack uses a static set of 32 */
+ /* channels regardless if it is E1, T1 */
+ /* or BRI that actually is used. */
+
+#define Q931MAXCALLPERTRUNK (Q931MAXCHPERTRUNK * 2)
+ /* Number of max active CRV per trunk. */
+ /* Q.931 can have more calls than there */
+ /* are channels. */
+
+
+#define Q931_IS_BRI(x) ((x)->TrunkType == Q931_TrType_BRI || (x)->TrunkType == Q931_TrType_BRI_PTMP)
+#define Q931_IS_PRI(x) (!Q931_IS_BRI(x))
+
+#define Q931_IS_PTP(x) ((x)->TrunkType != Q931_TrType_BRI_PTMP)
+#define Q931_IS_PTMP(X) ((x)->TrunkType == Q931_TrType_BRI_PTMP)
+
+#define Q931_BRI_MAX_CRV 127
+#define Q931_PRI_MAX_CRV 32767
+
+/*****************************************************************************
+
+ The following defines control the dialect switch tables and should only be
+ changed when a new dialect needs to be inserted into the stack.
+
+ This stack uses an array of functions to know which function to call as
+ it receives a SETUP message etc. A new dialect can when choose to use
+ the proc etc. for standard Q.931 or insert a modified proc.
+
+ This technique has also been used to distinguish between user and network
+ mode to make the code as easy to read and maintainable as possible.
+
+ A message and IE index have been used to save space. These indexes allowes
+ the message or IE code to be used directly and will give back a new index
+ into the table.
+
+*****************************************************************************/
+
+/* WARNING! Initialize Q931CreateDialectCB[] will NULL when increasing the */
+/* Q931MAXDLCT value to avoid Q931Initialize from crashing if one entry is */
+/* not used. */
+#define Q931MAXDLCT 8 /* Max dialects included in this */
+ /* compile. User and Network count as */
+ /* one dialect each. */
+
+#define Q931MAXMES 128 /* Number of messages */
+#define Q931MAXIE 255 /* Number of IE */
+#define Q931MAXUSEDIE 50 /* Maximum number of ie types per Dialect */
+#define Q931MAXCODESETS 7 /* Maximum number of codests (by spec, 0-7) */
+#define Q931MAXSTATE 100 /* Size of state tables */
+#define Q931MAXTIMER 25 /* Maximum number of timers */
+
+/*****************************************************************************
+
+ Call States for ITU-T Q.931 TE (User Mode)
+
+*****************************************************************************/
+
+#define Q931_U0 0
+#define Q931_U1 1
+#define Q931_U2 2
+#define Q931_U3 3
+#define Q931_U4 4
+#define Q931_U6 6
+#define Q931_U7 7
+#define Q931_U8 8
+#define Q931_U9 9
+#define Q931_U10 10
+#define Q931_U11 11
+#define Q931_U12 12
+#define Q931_U15 15
+#define Q931_U17 17
+#define Q931_U19 19
+#define Q931_U25 25
+
+/*****************************************************************************
+
+ Call States for ITU-T Q.931 NT (Network Mode)
+
+*****************************************************************************/
+#define Q931_N0 (0x0100 | 0)
+#define Q931_N1 (0x0100 | 1)
+#define Q931_N2 (0x0100 | 2)
+#define Q931_N3 (0x0100 | 3)
+#define Q931_N4 (0x0100 | 4)
+#define Q931_N6 (0x0100 | 6)
+#define Q931_N7 (0x0100 | 7)
+#define Q931_N8 (0x0100 | 8)
+#define Q931_N9 (0x0100 | 9)
+#define Q931_N10 (0x0100 | 11)
+#define Q931_N11 (0x0100 | 11)
+#define Q931_N12 (0x0100 | 12)
+#define Q931_N15 (0x0100 | 15)
+#define Q931_N17 (0x0100 | 17)
+#define Q931_N19 (0x0100 | 19)
+#define Q931_N22 (0x0100 | 22)
+#define Q931_N25 (0x0100 | 25)
+
+/*****************************************************************************
+
+ Q.931 Message codes
+
+*****************************************************************************/
+
+#define Q931mes_ALERTING 0x01 /* 0000 0001 */
+#define Q931mes_CALL_PROCEEDING 0x02 /* 0000 0010 */
+#define Q931mes_CONNECT 0x07 /* 0000 0111 */
+#define Q931mes_CONNECT_ACKNOWLEDGE 0x0f /* 0000 1111 */
+#define Q931mes_PROGRESS 0x03 /* 0000 0011 */
+#define Q931mes_SETUP 0x05 /* 0000 0101 */
+#define Q931mes_SETUP_ACKNOWLEDGE 0x0d /* 0000 1101 */
+#define Q931mes_RESUME 0x26 /* 0010 0110 */
+#define Q931mes_RESUME_ACKNOWLEDGE 0x2e /* 0010 1110 */
+#define Q931mes_RESUME_REJECT 0x22 /* 0010 0010 */
+#define Q931mes_SUSPEND 0x25 /* 0010 0101 */
+#define Q931mes_SUSPEND_ACKNOWLEDGE 0x2d /* 0010 1101 */
+#define Q931mes_SUSPEND_REJECT 0x21 /* 0010 0001 */
+#define Q931mes_USER_INFORMATION 0x20 /* 0010 0000 */
+#define Q931mes_DISCONNECT 0x45 /* 0100 0101 */
+#define Q931mes_RELEASE 0x4d /* 0100 1101 */
+#define Q931mes_RELEASE_COMPLETE 0x5a /* 0101 1010 */
+#define Q931mes_RESTART 0x46 /* 0100 0110 */
+#define Q931mes_RESTART_ACKNOWLEDGE 0x4e /* 0100 1110 */
+#define Q931mes_CONGESTION_CONTROL 0x79 /* 0111 1001 */
+#define Q931mes_INFORMATION 0x7b /* 0111 1011 */
+#define Q931mes_NOTIFY 0x6e /* 0110 1110 */
+#define Q931mes_STATUS 0x7d /* 0111 1101 */
+#define Q931mes_STATUS_ENQUIRY 0x75 /* 0111 0101 */
+#define Q931mes_SEGMENT 0x60 /* 0110 0000 */
+
+#define Q931mes_SERVICE 0x0f /* 0000 1111 */
+#define Q931mes_SERVICE_ACKNOWLEDGE 0x07 /* 0000 0111 */
+
+
+/**
+ * Generic Q.931 Timers
+ */
+enum {
+ Q931_TIMER_T300 = 1, /* */
+ Q931_TIMER_T301,
+ Q931_TIMER_T302,
+ Q931_TIMER_T303,
+ Q931_TIMER_T304,
+ Q931_TIMER_T305,
+ Q931_TIMER_T306,
+ Q931_TIMER_T307,
+ Q931_TIMER_T308,
+ Q931_TIMER_T309,
+ Q931_TIMER_T310,
+ Q931_TIMER_T311,
+ Q931_TIMER_T312,
+ Q931_TIMER_T313,
+ Q931_TIMER_T314,
+ Q931_TIMER_T315,
+ Q931_TIMER_T316,
+ Q931_TIMER_T317,
+ Q931_TIMER_T318,
+ Q931_TIMER_T319,
+ Q931_TIMER_T320,
+ Q931_TIMER_T321,
+ Q931_TIMER_T322,
+};
+
+/**
+ * Q.931 ToN
+ */
+enum {
+ Q931_TON_UNKNOWN = 0x00,
+ Q931_TON_INTERNATIONAL = 0x01,
+ Q931_TON_NATIONAL = 0x02,
+ Q931_TON_NETWORK_SPECIFIC = 0x03,
+ Q931_TON_SUBSCRIBER_NUMBER = 0x04,
+ Q931_TON_ABBREVIATED_NUMBER = 0x06,
+ Q931_TON_RESERVED = 0x07
+};
+
+/**
+ * Q.931 Numbering Plan
+ */
+enum {
+ Q931_NUMPLAN_UNKNOWN = 0x00,
+ Q931_NUMPLAN_E164 = 0x01,
+ Q931_NUMPLAN_X121 = 0x03,
+ Q931_NUMPLAN_F69 = 0x04,
+ Q931_NUMPLAN_NATIONAL = 0x08,
+ Q931_NUMPLAN_PRIVATE = 0x09,
+ Q931_NUMPLAN_RESERVED = 0x0e
+};
+
+/**
+ * Q.931 Presentation Indicator
+ */
+enum {
+ Q931_PRES_ALLOWED = 0x00,
+ Q931_PRES_RESTRICTED = 0x01,
+ Q931_PRES_NOT_AVAILABLE = 0x02,
+ Q931_PRES_RESERVED = 0x03
+};
+
+/**
+ * Q.931 Screening Indicator
+ */
+enum {
+ Q931_SCREEN_USER_NOT_SCREENED = 0x00,
+ Q931_SCREEN_USER_VERIFIED_PASSED = 0x01,
+ Q931_SCREEN_USER_VERIFIED_FAILED = 0x02,
+ Q931_SCREEN_NETWORK = 0x03
+};
+
+/**
+ * Q.931 Coding Standard
+ */
+enum {
+ Q931_CODING_ITU = 0x00,
+ Q931_CODING_ISO = 0x01,
+ Q931_CODING_NATIONAL = 0x02,
+ Q931_CODING_NETWORK = 0x03
+};
+
+/**
+ * Q.931 High layer characteristik id
+ */
+enum {
+ Q931_HLCHAR_TELEPHONY = 0x01,
+ Q931_HLCHAR_FAX_G23 = 0x04,
+ Q931_HLCHAR_FAX_G4 = 0x21,
+ Q931_HLCHAR_FAX_G4II = 0x24,
+ Q931_HLCHAR_T102 = 0x32,
+ Q931_HLCHAR_T101 = 0x33,
+ Q931_HLCHAR_F60 = 0x35,
+ Q931_HLCHAR_X400 = 0x38,
+ Q931_HLCHAR_X200 = 0x41
+};
+
+/**
+ * Q.931 User information layer 1 protocol
+ */
+enum {
+ Q931_UIL1P_V110 = 0x01,
+ Q931_UIL1P_I460 = 0x01,
+ Q931_UIL1P_X30 = 0x01,
+
+ Q931_UIL1P_G711U = 0x02,
+ Q931_UIL1P_G711A = 0x03,
+ Q931_UIL1P_G721 = 0x04,
+
+ Q931_UIL1P_H221 = 0x05,
+ Q931_UIL1P_H242 = 0x05,
+
+ Q931_UIL1P_H223 = 0x06,
+ Q931_UIL1P_H245 = 0x06,
+
+ Q931_UIL1P_RATE_ADAP = 0x07,
+
+ Q931_UIL1P_V120 = 0x08,
+ Q931_UIL1P_X31 = 0x09
+};
+
+/**
+ * Q.931 Information Transfer Capability
+ */
+enum {
+ Q931_ITC_SPEECH = 0x00,
+ Q931_ITC_UNRESTRICTED = 0x08,
+ Q931_ITC_RESTRICTED = 0x09,
+ Q931_ITC_3K1_AUDIO = 0x10,
+ Q931_ITC_UNRESTRICTED_TONES = 0x11,
+ Q931_ITC_VIDEO = 0x18
+};
+
+/**
+ * Q.931 Information transfer rate
+ */
+enum {
+ Q931_ITR_PACKET = 0x00,
+ Q931_ITR_64K = 0x10,
+ Q931_ITR_128K = 0x11,
+ Q931_ITR_384K = 0x13,
+ Q931_ITR_1536K = 0x15,
+ Q931_ITR_1920K = 0x17,
+ Q931_ITR_MULTI = 0x18
+};
+
+/*****************************************************************************
+
+ Struct: Q931mes_Header
+
+ Description: Used to read the header & message code.
+
+*****************************************************************************/
+typedef struct {
+ L3UINT Size; /* Size of message in bytes */
+ L3UCHAR ProtDisc; /* Protocol Discriminator */
+ L3UCHAR MesType; /* Message type */
+ L3UCHAR CRVFlag; /* Call reference value flag */
+ L3INT CRV; /* Call reference value */
+
+} Q931mes_Header;
+
+/*****************************************************************************
+
+ Struct: Q931mes_Generic
+
+ Description: Generic header containing all IE's. This is not used, but is
+ provided in case a proprietary variant needs it.
+
+*****************************************************************************/
+typedef struct {
+ L3UINT Size; /* Size of message in bytes */
+ L3UCHAR ProtDisc; /* Protocol Discriminator */
+ L3UCHAR MesType; /* Message type */
+ L3UCHAR CRVFlag; /* Call reference value flag */
+ L3INT CRV; /* Call reference value */
+
+ /* WARNING: don't touch anything above this line (TODO: use Q931mes_Header directly to make sure it's the same) */
+
+ L3UCHAR Tei; /* TEI */
+
+ ie Shift;
+ ie MoreData;
+ ie SendComplete;
+ ie CongestionLevel;
+ ie RepeatInd;
+
+ ie Segment; /* Segmented message */
+ ie BearerCap; /* Bearer Capability */
+ ie Cause; /* Cause */
+ ie CallState; /* Call State */
+ ie CallID; /* Call Identity */
+ ie ChanID; /* Channel Identification */
+ ie ChangeStatus; /* Change Staus */
+ ie ProgInd; /* Progress Indicator */
+ ie NetFac; /* Network Spesific Facilities */
+ ie NotifInd; /* Notification Indicator */
+ ie Display; /* Display */
+ ie DateTime; /* Date/Time */
+ ie KeypadFac; /* Keypad Facility */
+ ie Signal; /* Signal */
+ ie InfoRate; /* Information rate */
+ ie EndEndTxDelay; /* End to End Transmit Delay */
+ ie TransDelSelInd; /* Transmit Delay Sel. and Ind. */
+ ie PackParam; /* Packed Layer Binary parameters */
+ ie PackWinSize; /* Packet Layer Window Size */
+ ie PackSize; /* Packed Size */
+ ie ClosedUserGrp; /* Closed User Group */
+ ie RevChargeInd; /* Reverse Charging Indicator */
+ ie CalledNum; /* Called Party Number */
+ ie CalledSub; /* Called Party subaddress */
+ ie CallingNum; /* Calling Party Number */
+ ie CallingSub; /* Calling Party Subaddress */
+ ie RedirNum; /* Redirection Number */
+ ie TransNetSel; /* Transmit Network Selection */
+ ie LLRepeatInd; /* Repeat Indicator 2 LLComp */
+ ie RestartWin; /* Restart Window */
+ ie RestartInd; /* Restart Indicator */
+ ie LLComp; /* Low Layer Compatibility */
+ ie HLComp; /* High Layer Compatibility */
+ ie UserUser; /* User-user */
+ ie Escape; /* Escape for extension */
+ ie Switchhook;
+ ie FeatAct;
+ ie FeatInd;
+ ie GenericDigits;
+
+ L3UCHAR buf[1]; /* Buffer for IE's */
+
+} Q931mes_Generic;
+
+
+/*****************************************************************************
+
+ Struct: Q931_TrunkInfo
+
+ Description: TrunkInfo is the struct entry used to store Q.931 related
+ information and state for E1/T1/J1 trunks and associated
+ channels in the system.
+
+ The user should store this information outside this stack
+ and needs to feed the interface functions with a pointer to
+ the TrunkInfo entry.
+
+*****************************************************************************/
+typedef struct Q931_TrunkInfo Q931_TrunkInfo_t;
+
+typedef enum {
+ Q931_LOG_NONE = -1,
+ Q931_LOG_EMERG,
+ Q931_LOG_ALERT,
+ Q931_LOG_CRIT,
+ Q931_LOG_ERROR,
+ Q931_LOG_WARNING,
+ Q931_LOG_NOTICE,
+ Q931_LOG_INFO,
+ Q931_LOG_DEBUG
+} Q931LogLevel_t;
+
+typedef L3INT (*Q931Tx34CB_t) (void *,L3UCHAR *, L3INT);
+typedef L3INT (*Q931Tx32CB_t) (void *, L3INT, L3UCHAR, L3UCHAR *, L3INT);
+typedef L3INT (*Q931ErrorCB_t) (void *,L3INT,L3INT,L3INT);
+typedef L3INT (*Q931LogCB_t) (void *, Q931LogLevel_t, char *, L3INT);
+
+typedef enum { /* Network/User Mode. */
+ Q931_TE=0, /* 0 : User Mode */
+ Q931_NT=1 /* 1 : Network Mode */
+} Q931NetUser_t;
+
+typedef enum { /* Dialect enum */
+ Q931_Dialect_Q931 = 0,
+ Q931_Dialect_National = 2,
+ Q931_Dialect_DMS = 4,
+ Q931_Dialect_5ESS = 6, /* Coming soon to a PRI stack near you! */
+
+ Q931_Dialect_Count
+} Q931Dialect_t;
+#define DIALECT_STRINGS "q931", "", "national", "", "dms", "", "5ess", ""
+Q931_STR2ENUM_P(q931_str2Q931Dialect_type, q931_Q931Dialect_type2str, Q931Dialect_t)
+
+typedef enum { /* Trunk Line Type. */
+ Q931_TrType_E1 = 0, /* 0 : E1 Trunk */
+ Q931_TrType_T1 = 1, /* 1 : T1 Trunk */
+ Q931_TrType_J1 = 2, /* 2 : J1 Trunk */
+ Q931_TrType_BRI = 3, /* 3 : BRI Trunk */
+ Q931_TrType_BRI_PTMP = 4 /* 4 : BRI PTMP Trunk */
+} Q931_TrunkType_t;
+
+typedef enum { /* Trunk State */
+ Q931_TrState_NoAlignment=0, /* Trunk not aligned */
+ Q931_TrState_Aligning=1, /* Aligning in progress */
+ Q931_TrState_Aligned=2 /* Trunk Aligned */
+} Q931_TrunkState_t;
+
+typedef enum {
+ Q931_ChType_NotUsed=0, /* Unused Channel */
+ Q931_ChType_B=1, /* B Channel (Voice) */
+ Q931_ChType_D=2, /* D Channel (Signalling) */
+ Q931_ChType_Sync=3 /* Sync Channel */
+} Q931_ChanType_t;
+
+struct Q931_Call
+{
+ L3UCHAR InUse; /* Indicate if entry is in use. */
+ /* 0 = Not in Use */
+ /* 1 = Active Call. */
+
+ L3UCHAR Tei; /* Associated TEI */
+
+ L3UCHAR BChan; /* Associated B Channel. */
+ /* 0 - 31 valid B chan */
+ /* 255 = Not allocated */
+
+ L3INT CRV; /* Associated CRV. */
+
+ L3UINT State; /* Call State. */
+ /* 0 is Idle, but other values are */
+ /* defined per dialect. */
+ /* Default usage is 1-99 for TE and */
+ /* 101 - 199 for NT. */
+
+ L3ULONG Timer; /* Timer in ms. The TimeTick will check */
+ /* if this has exceeded the timeout, and */
+ /* if so call the timers timeout proc. */
+
+ L3USHORT TimerID; /* Timer Identification/State */
+ /* actual values defined by dialect */
+ /* 0 : No timer running */
+ /* ITU-T Q.931:301 - 322 Timer running */
+};
+
+struct Q931_TrunkInfo
+{
+ Q931NetUser_t NetUser; /* Network/User Mode. */
+ Q931_TrunkType_t TrunkType; /* Trunk Line Type. */
+ Q931Dialect_t Dialect; /* Q.931 Based dialect index. */
+
+ Q931Tx34CB_t Q931Tx34CBProc;
+ Q931Tx32CB_t Q931Tx32CBProc;
+ Q931ErrorCB_t Q931ErrorCBProc;
+ Q931LogCB_t Q931LogCBProc;
+ void *PrivateData32;
+ void *PrivateData34;
+ void *PrivateDataLog;
+
+ Q931LogLevel_t loglevel;
+
+ L3UCHAR Enabled; /* Enabled/Disabled */
+ /* 0 = Disabled */
+ /* 1 = Enabled */
+
+ Q931_TrunkState_t TrunkState;
+
+ L3INT LastCRV; /* Last used crv for the trunk. */
+
+ L3UCHAR L3Buf[Q931L4BUF]; /* message buffer for messages to be */
+ /* send from Q.931 L4. */
+
+ L3UCHAR L2Buf[Q931L2BUF]; /* buffer for messages send to L2. */
+
+ /* The auto flags below switch on/off automatic Ack messages. SETUP ACK */
+ /* as an example can be sent by the stack in response to SETUP to buy */
+ /* time in processing on L4. Setting this to true will cause the stack */
+ /* to automatically send this. */
+
+ L3BOOL autoSetupAck; /* Indicate if the stack should send */
+ /* SETUP ACK or not. 0=No, 1 = Yes. */
+
+ L3BOOL autoConnectAck; /* Indicate if the stack should send */
+ /* CONNECT ACT or not. 0=No, 1=Yes. */
+
+ L3BOOL autoRestartAck; /* Indicate if the stack should send */
+ /* RESTART ACK or not. 0=No, 1=Yes. */
+
+ L3BOOL autoServiceAck; /* Indicate if the stack should send */
+ /* SERVICE ACK or not. 0=No, 1=Yes. */
+
+ /* channel array holding info per channel. Usually defined to 32 */
+ /* channels to fit an E1 since T1/J1 and BRI will fit inside a E1. */
+ struct _charray
+ {
+ Q931_ChanType_t ChanType; /* Unused, B, D, Sync */
+
+ L3UCHAR Available; /* Channel Available Flag */
+ /* 0 : Avaiabled */
+ /* 1 : Used */
+
+ L3INT CRV; /* Associated CRV */
+
+ } ch[Q931MAXCHPERTRUNK];
+
+ /* Active Call information indentified by CRV. See Q931AllocateCRV for */
+ /* initialization of call table. */
+ struct Q931_Call call[Q931MAXCALLPERTRUNK];
+};
+
+/*****************************************************************************
+
+ Struct: Q931State
+
+ Description: Define a Q931 State, legal events and next state for each
+ event. Used to simplify the state engine logic. Each state
+ engine defines its own state table and the logic need only
+ call a helper function to check if the message is legal
+ at this stage.
+
+*****************************************************************************/
+typedef struct
+{
+ L3INT State;
+ L3INT Message;
+ L3UCHAR Direction;
+} Q931State;
+
+/*****************************************************************************
+
+ Proc table external references.
+
+ The proc tables are defined in Q931.c and initialized in Q931Initialize.
+
+*****************************************************************************/
+typedef L3INT (q931proc_func_t) (Q931_TrunkInfo_t *pTrunk, L3UCHAR *, L3INT);
+
+typedef L3INT (q931umes_func_t) (Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+typedef L3INT (q931pmes_func_t) (Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+typedef L3INT (q931uie_func_t) (Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff);
+typedef L3INT (q931pie_func_t) (Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+
+typedef L3INT (q931timeout_func_t) (Q931_TrunkInfo_t *pTrunk, L3INT callIndex);
+typedef L3ULONG q931timer_t;
+
+extern q931proc_func_t *Q931Proc[Q931MAXDLCT][Q931MAXMES];
+
+extern q931umes_func_t *Q931Umes[Q931MAXDLCT][Q931MAXMES];
+extern q931pmes_func_t *Q931Pmes[Q931MAXDLCT][Q931MAXMES];
+
+extern q931uie_func_t *Q931Uie[Q931MAXDLCT][Q931MAXIE];
+extern q931pie_func_t *Q931Pie[Q931MAXDLCT][Q931MAXIE];
+
+extern q931timeout_func_t *Q931Timeout[Q931MAXDLCT][Q931MAXTIMER];
+extern q931timer_t Q931Timer[Q931MAXDLCT][Q931MAXTIMER];
+
+
+/*****************************************************************************
+
+ Macro: GetIETotoSize
+
+ Syntax: L3INT GetIETotSize(InfoElem ie);
+
+ Description: Compute the total size in bytes of an info element including
+ size of 'header'.
+
+*****************************************************************************/
+#define Q931GetIETotSize(ie) (((ie.InfoID & 0x80) != 0) ? 1 : ie.LenIE) + 2)
+
+/*****************************************************************************
+
+ Macro: IsIEPresent
+
+ Syntax: BOOL IsIEPresent(ie InfoElement);
+
+ Description: Return TRUE if the Information Element is included.
+
+*****************************************************************************/
+#define Q931IsIEPresent(x) ((x & 0x8000) != 0)
+
+/*****************************************************************************
+
+ Macro: GetIEOffset and GetIEValue
+
+ Syntax: L3INT GetIEOffset(ie InfoElement)
+ L3INT GetIEValue(ie InfoElement)
+
+ Description: Returns the offset (or the value )to the Information Element.
+
+ Note: GetIEValue assumes that the 15 lsb bit is the value of a
+ single octet information element. This macro can not be used
+ on a variable information element.
+
+*****************************************************************************/
+#define Q931GetIEOffset(x) (x & 0x7fff)
+#define Q931GetIEValue(x) (x & 0x7fff)
+
+/*****************************************************************************
+
+ Macro: Q931GetIEPtr
+
+ Syntax: void * Q931GetIEPtr(ie InfoElement, L3UCHAR * Buf);
+
+ Description: Compute a Ptr to the information element.
+
+*****************************************************************************/
+#define Q931GetIEPtr(ie,buf) ((void *)&buf[Q931GetIEOffset(ie)])
+
+/*****************************************************************************
+
+ Macro: SetIE
+
+ Syntax: void SetIE(ie InfoElement, L3INT Offset);
+
+ Description: Set an information element.
+
+*****************************************************************************/
+#define Q931SetIE(x,o) { x = (ie)(o) | 0x8000; }
+
+/*****************************************************************************
+
+ Macro: IsQ931Ext
+
+ Syntax BOOL IsQ931Ext(L3UCHAR c)
+
+ Description: Return true Check if the msb (bit 8) is 0. This indicate
+ that the octet is extended.
+
+*****************************************************************************/
+#define IsQ931Ext(x) ((x & 0x80) == 0)
+
+/*****************************************************************************
+
+ Macro: ieGetOctet
+
+ Syntax: unsigned L3UCHAR ieGetOctet(L3INT e)
+
+ Description: Macro to fetch one byte from an integer. Mostly used to
+ avoid warnings.
+
+*****************************************************************************/
+#define ieGetOctet(x) ((L3UCHAR)(x))
+
+/*****************************************************************************
+
+ Macro: NoWarning
+
+ Syntax: void NoWarning(x)
+
+ Description: Macro to suppress unreferenced formal parameter warnings
+
+ Used during creation of the stack since the stack is
+ developed for Warning Level 4 and this creates a lot of
+ warning for the initial empty functions.
+
+*****************************************************************************/
+#define NoWarning(x) (x = x)
+
+/*****************************************************************************
+
+ External references. See Q931.c for details.
+
+*****************************************************************************/
+
+#include "Q931ie.h"
+
+#include "Q932.h"
+
+/*****************************************************************************
+
+ Q.931 Message Pack/Unpack functions. Implemented in Q931mes.c
+
+*****************************************************************************/
+L3INT Q931Pmes_Alerting(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_CallProceeding(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Connect(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ConnectAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Progress(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_SetupAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Resume(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ResumeAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ResumeReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Suspend(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_SuspendAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_SuspendReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_UserInformation(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Disconnect(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Release(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ReleaseComplete(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Restart(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_RestartAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_CongestionControl(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Information(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Notify(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Segment(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Status(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_StatusEnquiry(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Service(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ServiceAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+
+L3INT Q931Umes_Alerting(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_CallProceeding(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Connect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_ConnectAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Progress(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_SetupAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Resume(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_ResumeAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_ResumeReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Suspend(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_SuspendAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_SuspendReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_UserInformation(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Disconnect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Release(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_ReleaseComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Restart(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_RestartAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_CongestionControl(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Information(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Notify(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Segment(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Status(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_StatusEnquiry(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Service(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT Q931Umes_ServiceAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+
+
+/*****************************************************************************
+
+ Q.931 Process Function Prototyping. Implemented in Q931StateTE.c
+
+*****************************************************************************/
+L3INT Q931ProcAlertingTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcCallProceedingTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcConnectTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcConnectAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcProgressTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSetupTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSetupAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeRejectTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendRejectTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcUserInformationTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcDisconnectTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcReleaseTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcReleaseCompleteTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcRestartTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcRestartAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcCongestionControlTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcInformationTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcNotifyTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcStatusTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcStatusEnquiryTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSegmentTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+
+L3INT Q931ProcAlertingNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcCallProceedingNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcConnectNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcConnectAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcProgressNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSetupNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSetupAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeRejectNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendRejectNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcUserInformationNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcDisconnectNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcReleaseNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcReleaseCompleteNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcRestartNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcRestartAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcCongestionControlNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcInformationNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcNotifyNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcStatusNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcStatusEnquiryNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSegmentNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+
+L3INT Q931ProcUnknownMessage(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcUnexpectedMessage(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+
+/*****************************************************************************
+
+ Interface Function Prototypes. Implemented in Q931.c
+
+*****************************************************************************/
+void Q931TimerTick(Q931_TrunkInfo_t *pTrunk);
+L3INT Q931Rx23(Q931_TrunkInfo_t *pTrunk, L3INT ind, L3UCHAR tei, L3UCHAR * Mes, L3INT Size);
+L3INT Q931Tx32Data(Q931_TrunkInfo_t *pTrunk, L3UCHAR bcast, L3UCHAR * Mes, L3INT Size);
+L3INT Q931Rx43(Q931_TrunkInfo_t *pTrunk, L3UCHAR * Mes, L3INT Size);
+L3INT Q931Tx34(Q931_TrunkInfo_t *pTrunk, L3UCHAR * Mes, L3INT Size);
+void Q931SetError(Q931_TrunkInfo_t *pTrunk,L3INT ErrID, L3INT ErrPar1, L3INT ErrPar2);
+
+void Q931SetDefaultErrorCB(Q931ErrorCB_t Q931ErrorPar);
+
+void Q931CreateTE(L3UCHAR i);
+void Q931CreateNT(L3UCHAR i);
+void Q931SetMesCreateCB(L3INT (*callback)(void));
+void Q931SetDialectCreateCB(L3INT (*callback)(L3INT));
+void Q931SetHeaderSpace(L3INT space);
+
+void Q931SetMesProc(L3UCHAR mes, L3UCHAR dialect, q931proc_func_t *Q931ProcFunc, q931umes_func_t *Q931UmesFunc, q931pmes_func_t *Q931PmesFunc);
+void Q931SetIEProc(L3UCHAR iec, L3UCHAR dialect, q931pie_func_t *Q931PieProc, q931uie_func_t *Q931UieProc);
+void Q931SetTimeoutProc(L3UCHAR dialect, L3UCHAR timer, q931timeout_func_t *Q931TimeoutProc);
+void Q931SetTimerDefault(L3UCHAR dialect, L3UCHAR timer, q931timer_t timeout);
+
+void Q931Initialize(void);
+void Q931AddDialect(L3UCHAR iDialect, void (*Q931CreateDialectCB)(L3UCHAR iDialect));
+L3INT Q931InitMesSetup(Q931mes_Generic *p);
+L3INT Q931InitMesRestartAck(Q931mes_Generic * pMes);
+L3INT Q931InitMesGeneric(Q931mes_Generic *pMes);
+
+L3INT Q931CreateCRV(Q931_TrunkInfo_t *pTrunk, L3INT * callIndex);
+L3INT Q931ReleaseCRV(Q931_TrunkInfo_t *pTrunk, L3INT CRV);
+L3INT Q931AllocateCRV(Q931_TrunkInfo_t *pTrunk, L3INT iCRV, L3INT * callIndex);
+L3INT Q931FindCRV(Q931_TrunkInfo_t *pTrunk, L3INT crv, L3INT *callindex);
+L3INT Q931GetCallState(Q931_TrunkInfo_t *pTrunk, L3INT iCRV);
+L3INT Q931StartTimer(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3USHORT iTimer);
+L3INT Q931StopTimer(Q931_TrunkInfo_t *pTrunk, L3INT callindex, L3USHORT iTimer);
+L3INT Q931SetState(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3INT iState);
+L3ULONG Q931GetTime(void);
+void Q931SetGetTimeCB(L3ULONG (*callback)(void));
+void Q931AddStateEntry(L3UCHAR iD, L3INT iState, L3INT iMes, L3UCHAR cDir);
+L3BOOL Q931IsEventLegal(L3UCHAR iD, L3INT iState, L3INT iMes, L3UCHAR cDir);
+
+/*****************************************************************************
+
+ Q.931 Low Level API Function Prototyping. Implemented in Q931API.c
+
+*****************************************************************************/
+ie Q931AppendIE(L3UCHAR *pm, L3UCHAR *pi);
+L3INT Q931GetUniqueCRV(Q931_TrunkInfo_t *pTrunk);
+
+L3INT Q931InitIEBearerCap(Q931ie_BearerCap *p);
+L3INT Q931InitIEChanID(Q931ie_ChanID *p);
+L3INT Q931InitIEProgInd(Q931ie_ProgInd *p);
+L3INT Q931InitIENetFac(Q931ie_NetFac * pIE);
+L3INT Q931InitIEDisplay(Q931ie_Display * pIE);
+L3INT Q931InitIEDateTime(Q931ie_DateTime * pIE);
+L3INT Q931InitIEKeypadFac(Q931ie_KeypadFac * pIE);
+L3INT Q931InitIESignal(Q931ie_Signal * pIE);
+L3INT Q931InitIECallingNum(Q931ie_CallingNum * pIE);
+L3INT Q931InitIECallingSub(Q931ie_CallingSub * pIE);
+L3INT Q931InitIECalledNum(Q931ie_CalledNum * pIE);
+L3INT Q931InitIECalledSub(Q931ie_CalledSub * pIE);
+L3INT Q931InitIETransNetSel(Q931ie_TransNetSel * pIE);
+L3INT Q931InitIELLComp(Q931ie_LLComp * pIE);
+L3INT Q931InitIEHLComp(Q931ie_HLComp * pIE);
+
+L3INT Q931Disconnect(Q931_TrunkInfo_t *pTrunk, L3INT iTo, L3INT iCRV, L3INT iCause);
+L3INT Q931ReleaseComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+L3INT Q931AckRestart(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+L3INT Q931AckConnect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+L3INT Q931AckSetup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+L3INT Q931AckService(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+
+L3INT Q931Api_InitTrunk(Q931_TrunkInfo_t *pTrunk,
+ Q931Dialect_t Dialect,
+ Q931NetUser_t NetUser,
+ Q931_TrunkType_t TrunkType,
+ Q931Tx34CB_t Q931Tx34CBProc,
+ Q931Tx32CB_t Q931Tx32CBProc,
+ Q931ErrorCB_t Q931ErrorCBProc,
+ void *PrivateData32,
+ void *PrivateData34);
+
+L3INT Q931GetMesSize(Q931mes_Generic *pMes);
+L3INT Q931InitMesResume(Q931mes_Generic * pMes);
+
+L3INT Q931Log(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level, const char *fmt, ...);
+void Q931SetLogCB(Q931_TrunkInfo_t *trunk, Q931LogCB_t func, void *priv);
+void Q931SetLogLevel(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level);
+
+void Q931SetL4HeaderSpace(L3INT space);
+void Q931SetL2HeaderSpace(L3INT space);
+L3INT Q931ProcDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b,L3INT c);
+L3INT Q931UmesDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT Q931UieDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff);
+L3INT Q931PmesDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931PieDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+L3INT Q931TxDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT n);
+L3INT Q931ErrorDummy(void *priv, L3INT a, L3INT b, L3INT c);
+L3INT Q931TimeoutDummy(Q931_TrunkInfo_t *pTrunk, L3INT callIndex);
+
+L3INT Q931MesgHeader(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *mes, L3UCHAR *OBuf, L3INT Size, L3INT *IOff);
+
+#endif /* _Q931_NL */
Added: freeswitch/trunk/libs/freetdm/src/isdn/include/Q931ie.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/include/Q931ie.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/include/Q931ie.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1205 @@
+/******************************************************************************
+
+ FileName: Q931ie.h
+
+ Contents: Header and definition for the ITU-T Q.931 ie
+ structures and functions
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+******************************************************************************/
+
+#ifndef _Q931IE_NL
+#define _Q931IE_NL
+
+/* Codesets */
+
+typedef enum {
+
+ Q931_CODESET_0 = ( 0 ),
+ Q931_CODESET_1 = ( 1 << 8 ),
+ Q931_CODESET_2 = ( 2 << 8 ),
+ Q931_CODESET_3 = ( 3 << 8 ),
+ Q931_CODESET_4 = ( 4 << 8 ),
+ Q931_CODESET_5 = ( 5 << 8 ),
+ Q931_CODESET_6 = ( 6 << 8 ),
+ Q931_CODESET_7 = ( 7 << 8 )
+
+} q931_codeset_t;
+
+/* Single octet information elements */
+#define Q931ie_SHIFT 0x90 /* 1001 ---- */
+#define Q931ie_MORE_DATA 0xa0 /* 1010 ---- */
+#define Q931ie_SENDING_COMPLETE 0xa1 /* 1010 0001 */
+#define Q931ie_CONGESTION_LEVEL 0xb0 /* 1011 ---- */
+#define Q931ie_REPEAT_INDICATOR 0xd0 /* 1101 ---- */
+
+/* Variable Length Information Elements */
+#define Q931ie_SEGMENTED_MESSAGE 0x00 /* 0000 0000 */
+#define Q931ie_CHANGE_STATUS 0x01 /* 0000 0001 */
+#define Q931ie_BEARER_CAPABILITY 0x04 /* 0000 0100 */
+#define Q931ie_CAUSE 0x08 /* 0000 1000 */
+#define Q931ie_CALL_IDENTITY 0x10 /* 0001 0000 */
+#define Q931ie_CALL_STATE 0x14 /* 0001 0100 */
+#define Q931ie_CHANNEL_IDENTIFICATION 0x18 /* 0001 1000 */
+#define Q931ie_PROGRESS_INDICATOR 0x1e /* 0001 1110 */
+#define Q931ie_NETWORK_SPECIFIC_FACILITIES 0x20 /* 0010 0000 */
+#define Q931ie_NOTIFICATION_INDICATOR 0x27 /* 0010 0111 */
+#define Q931ie_DISPLAY 0x28 /* 0010 1000 */
+#define Q931ie_DATETIME 0x29 /* 0010 1001 */
+#define Q931ie_KEYPAD_FACILITY 0x2c /* 0010 1100 */
+#define Q931ie_SIGNAL 0x34 /* 0011 0100 */
+#define Q931ie_SWITCHOOK 0x36 /* 0011 0110 */
+#define Q931ie_FEATURE_ACTIVATION 0x38 /* 0011 1000 */
+#define Q931ie_FEATURE_INDICATION 0x39 /* 0011 1001 */
+#define Q931ie_INFORMATION_RATE 0x40 /* 0100 0000 */
+#define Q931ie_END_TO_END_TRANSIT_DELAY 0x42 /* 0100 0010 */
+#define Q931ie_TRANSIT_DELAY_SELECTION_AND_IND 0x43 /* 0100 0011 */
+#define Q931ie_PACKED_LAYER_BIMARY_PARAMETERS 0x44 /* 0100 0100 */
+#define Q931ie_PACKED_LAYER_WINDOW_SIZE 0x45 /* 0100 0101 */
+#define Q931ie_PACKED_SIZE 0x46 /* 0100 0110 */
+#define Q931ie_CALLING_PARTY_NUMBER 0x6c /* 0110 1100 */
+#define Q931ie_CALLING_PARTY_SUBADDRESS 0x6d /* 0110 1101 */
+#define Q931ie_CALLED_PARTY_NUMBER 0x70 /* 0111 0000 */
+#define Q931ie_CALLED_PARTY_SUBADDRESS 0x71 /* 0111 0001 */
+#define Q931ie_REDIRECTING_NUMBER 0x74 /* 0111 0100 */
+#define Q931ie_TRANSIT_NETWORK_SELECTION 0x78 /* 0111 1000 */
+#define Q931ie_RESTART_INDICATOR 0x79 /* 0111 1001 */
+#define Q931ie_LOW_LAYER_COMPATIBILITY 0x7c /* 0111 1100 */
+#define Q931ie_HIGH_LAYER_COMPATIBILITY 0x7d /* 0111 1101 */
+#define Q931ie_USER_USER 0x7e /* 0111 1110 */
+#define Q931ie_ESCAPE_FOR_EX 0x7f /* 0111 1111 */
+
+/* Variable Length Codeset 6 Information Elements */
+#define Q931ie_GENERIC_DIGITS 0x37 /* 0011 0111 */
+
+/* Variable Length Information Element to shut up BRI testing */
+#define Q931ie_CONNECTED_NUMBER 0x4c /* 0100 1101 */
+#define Q931ie_FACILITY 0x1c /* 0001 1101 */
+
+
+/*****************************************************************************
+
+ Struct: Q931ie_BearerCap
+
+ Description: Bearer Capability Information Element.
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00000100 for Bearer Capability */
+ L3UCHAR Size; /* Length of Information Element */
+
+ L3UCHAR CodStand; /* Coding Standard. */
+ /* 00 - ITU-T */
+ /* 01 - ISO/IEC */
+ /* 10 - National standard */
+ /* 11 - Network side spesific */
+
+ L3UCHAR ITC; /* Information Transfer Capability */
+ /* 00000 - Speech */
+ /* 01000 - Unrestricted digital info */
+ /* 01001 - Restricted digital info */
+ /* 10000 - 3.1 kHz audio */
+ /* 10001 - Unrestricted with tones */
+ /* 11000 - Video */
+
+ L3UCHAR TransMode; /* Transfer Mode. */
+ /* 00 - Circuit mode */
+ /* 10 - Packet mode */
+
+ L3UCHAR ITR; /* Information Transfer Rate. */
+ /* 00000 - Packed mode */
+ /* 10000 - 64 kbit/s */
+ /* 10001 - 2 x 64 kbit/s */
+ /* 10011 - 384 kbit/s */
+ /* 10101 - 1536 kbit/s */
+ /* 10111 - 1920 kbit/s */
+ /* 11000 - Multirat (64 kbit/s base) */
+
+ L3UCHAR RateMul; /* Rate Multiplier */
+
+ L3UCHAR Layer1Ident; /* Layer 1 Ident. */
+
+ L3UCHAR UIL1Prot; /* User Information Layer 1 Protocol */
+ /* 00001 : ITU-T V.110, I.460 and X.30 */
+ /* 00010 : G.711 my-law */
+ /* 00011 : G.711 A-law */
+ /* 00100 : G.721 */
+ /* 00101 : H.221 and H.242 */
+ /* 00110 : H.223 and H.245 */
+ /* 00111 : Non ITU-T Standard */
+ /* 01000 : ITU-T V.120 */
+ /* 01001 : ITU-T X.31 HDLC flag stuff. */
+
+ L3UCHAR SyncAsync; /* Sync/Async */
+ /* 0 : Syncronous data */
+ /* 1 : Asyncronous data */
+
+ L3UCHAR Negot; /* Negotiation */
+ /* 0 : In-band negotiation not possib. */
+ /* 1 : In-band negotiation possible */
+
+ L3UCHAR UserRate; /* User rate */
+ /* 00000 : I.460, V.110, X,30 */
+ /* 00001 : 0.6 kbit/s x.1 */
+ /* 00010 : 1.2 kbit/s */
+ /* 00011 : 2.4 kbit/s */
+ /* 00100 : 3.6 kbit/s */
+ /* 00101 : 4.8 kbit/s */
+ /* 00110 : 7.2 kbit/s */
+ /* 00111 : 8 kbit/s I.460 */
+ /* 01000 : 9.6 kbit/s */
+ /* 01001 : 14.4 kbit/s */
+ /* 01010 : 16 kbit/s */
+ /* 01011 : 19.2 kbit/s */
+ /* 01100 : 32 kbit/s */
+ /* 01101 : 38.4 kbit/s */
+ /* 01110 : 48 kbit/s */
+ /* 01111 : 56 kbit/s */
+ /* 10000 : 57.6 kbit/s */
+ /* 10010 : 28.8 kbit/s */
+ /* 10100 : 24 kbit/s */
+ /* 10101 : 0.1345 kbit/s */
+ /* 10110 : 0.100 kbit/s */
+ /* 10111 : 0.075/1.2 kbit/s */
+ /* 11000 : 1.2/0.075/kbit/s */
+ /* 11001 : 0.050 kbit/s */
+ /* 11010 : 0.075 kbit/s */
+ /* 11011 : 0.110 kbit/s */
+ /* 11100 : 0.150 kbit/s */
+ /* 11101 : 0.200 kbit/s */
+ /* 11110 : 0.300 kbit/s */
+ /* 11111 : 12 kbit/s */
+
+ L3UCHAR InterRate; /* Intermediate Rate */
+ /* 00 : Not used */
+ /* 01 : 8 kbit/s */
+ /* 10 : 16 kbit/s */
+ /* 11 : 32 kbit/s */
+
+ L3UCHAR NIConTx; /* Network Indepentend Clock on transmit*/
+ /* 0 : Not required to send data clc */
+ /* 1 : Send data w/NIC clc */
+
+ L3UCHAR NIConRx; /* NIC on Rx */
+ /* 0 : Cannot accept indep. clc */
+ /* 1 : data with indep. clc accepted */
+
+ L3UCHAR FlowCtlTx; /* Flow control on Tx */
+ /* 0 : Send Flow ctrl not required */
+ /* 1 : Send flow ctrl required */
+
+ L3UCHAR FlowCtlRx; /* Flow control on Rx */
+ /* 0 : cannot use receive flow ctrl */
+ /* 1 : Receive flow ctrl accepted */
+ L3UCHAR HDR; /* HDR/No HDR */
+ L3UCHAR MultiFrame; /* Multi frame support */
+ /* 0 : multiframe not supported */
+ /* 1 : multiframe supported */
+
+ L3UCHAR Mode; /* Mode of operation */
+ /* 0 : bit transparent mode of operat. */
+ /* 1 : protocol sesitive mode of op. */
+
+ L3UCHAR LLInegot; /* Logical link id negotiation (oct. 5b)*/
+ /* 0 : default LLI=256 only */
+ /* 1 : Full protocol negotiation */
+
+ L3UCHAR Assignor; /* Assignor/assignee */
+ /* 0 : Default Asignee */
+ /* 1 : Assignor only */
+
+ L3UCHAR InBandNeg; /* In-band/out-band negot. */
+ /* 0 : negot done w/ USER INFO mes */
+ /* 1 : negot done in-band w/link zero */
+
+ L3UCHAR NumStopBits; /* Number of stop bits */
+ /* 00 : Not used */
+ /* 01 : 1 bit */
+ /* 10 : 1.5 bits */
+ /* 11 : 2 bits */
+
+ L3UCHAR NumDataBits; /* Number of data bits. */
+ /* 00 : not used */
+ /* 01 : 5 bits */
+ /* 10 : 7 bits */
+ /* 11 : 8 bits */
+
+ L3UCHAR Parity; /* Parity Information */
+ /* 000 : Odd */
+ /* 010 : Even */
+ /* 011 : None */
+ /* 100 : Forced to 0 */
+ /* 101 : Forced to 1 */
+
+ L3UCHAR DuplexMode; /* Mode duplex */
+ /* 0 : Half duplex */
+ /* 1 : Full duplex */
+
+ L3UCHAR ModemType; /* Modem type, see Q.931 p 64 */
+
+ L3UCHAR Layer2Ident; /* Layer 2 Ident */
+
+ L3UCHAR UIL2Prot; /* User Information Layer 2 Protocol */
+ /* 00010 : Q.921/I.441 */
+ /* 00110 : X.25 */
+ /* 01100 : LAN logical link */
+
+ L3UCHAR Layer3Ident; /* Layer 3 ident. */
+
+ L3UCHAR UIL3Prot; /* User Information Layer 3 Protocol */
+ /* 00010 : Q.931 */
+ /* 00110 : X.25 */
+ /* 01011 : ISO/IEC TR 9577 */
+
+ L3UCHAR AL3Info1; /* additional layer 3 info 1 */
+
+ L3UCHAR AL3Info2; /* additional layer 3 info 2 */
+
+} Q931ie_BearerCap;
+
+/*****************************************************************************
+
+ Struct: Q931ie_CallID
+
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00010000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR CallId[1]; /* Call identity */
+
+} Q931ie_CallID;
+
+/*****************************************************************************
+
+ Struct: Q931ie_CallState
+
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00010100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR CodStand; /* Coding Standard */
+ L3UCHAR CallState; /* Call State Value */
+
+} Q931ie_CallState;
+
+/*****************************************************************************
+
+ Struct: Q931ie_Cause
+
+ Description: Cause IE as described in Q.850
+
+*****************************************************************************/
+typedef struct {
+
+ L3UCHAR IEId; /* 00010100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR CodStand; /* Coding Standard */
+ L3UCHAR Location; /* Location */
+ L3UCHAR Recom; /* Recommendation */
+ L3UCHAR Value; /* Cause Value */
+ L3UCHAR Diag[1]; /* Optional Diagnostics Field */
+
+} Q931ie_Cause;
+
+/*****************************************************************************
+
+ Struct: Q931ie_CalledNum
+
+*****************************************************************************/
+typedef struct {
+
+ L3UCHAR IEId; /* 01110000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR TypNum; /* Type of Number */
+ L3UCHAR NumPlanID; /* Numbering plan identification */
+ L3UCHAR Digit[1]; /* Digit (IA5) */
+
+} Q931ie_CalledNum;
+
+/*****************************************************************************
+
+ Struct: Q931ie_CalledSub
+
+ Description: Called party subaddress
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01110001 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR TypNum; /* Type of subaddress */
+ L3UCHAR OddEvenInd; /* Odd/Even indicator */
+ L3UCHAR Digit[1]; /* digits */
+
+} Q931ie_CalledSub;
+
+/*****************************************************************************
+
+ Struct: Q931ie_CallingNum
+
+ Description: Calling party number
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01101100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR TypNum; /* Type of number */
+ L3UCHAR NumPlanID; /* Numbering plan identification */
+ L3UCHAR PresInd; /* Presentation indicator */
+ L3UCHAR ScreenInd; /* Screening indicator */
+ L3UCHAR Digit[1]; /* Number digits (IA5) */
+
+} Q931ie_CallingNum;
+
+/*****************************************************************************
+
+ Struct: Q931ie_CallingSub
+
+ Description: Calling party subaddress
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01101101 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR TypNum; /* Type of subaddress */
+ L3UCHAR OddEvenInd; /* Odd/Even indicator */
+ L3UCHAR Digit[1]; /* digits */
+
+} Q931ie_CallingSub;
+
+/*****************************************************************************
+
+ Struct: Q931ie_ChanID
+
+ Description: Channel identification
+
+ Channel Identificationis one of the IE elements that differ
+ between BRI and PRI. IntType = 1 = BRI and ChanSlot is used
+ for channel number, while InfoChanSel is used for BRI.
+
+ ChanID is one of the most important IE as it is passed
+ either though SETUP or CALL PROCEEDING to select the channel
+ to be used.
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00011000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR IntIDPresent; /* Int. id. present */
+ L3UCHAR IntType; /* Interface Type */
+ /* 0 : Basic Interface (BRI) */
+ /* 1 : Other interfaces, PRI etc. */
+
+ L3UCHAR PrefExcl; /* Pref./Excl. */
+ /* 0 : Indicated channel is preffered */
+ /* 1 : Exclusive, no other accepted */
+
+ L3UCHAR DChanInd; /* D-channel ind. */
+ /* 0 : chan is NOT D chan. */
+ /* 1 : chan is D chan */
+
+ L3UCHAR InfoChanSel; /* Info. channel selection */
+ /* 00 : No channel */
+ /* 01 : B1 channel */
+ /* 10 : B2 channel */
+ /* 11 : Any channel */
+
+ L3UCHAR InterfaceID; /* Interface identifier */
+
+ L3UCHAR CodStand; /* Code standard */
+ /* 00 : ITU-T standardization coding */
+ /* 01 : ISO/IEC Standard */
+ /* 10 : National Standard */
+ /* 11 : Standard def. by network. */
+
+ L3UCHAR NumMap; /* Number/Map */
+ /* 0 : chan is in following octet */
+ /* 1 : chan is indicated by slot map */
+
+ L3UCHAR ChanMapType; /* Channel type/Map element type */
+ /* 0011 : B Channel units */
+ /* 0110 : H0 channel units */
+ /* 1000 : H11 channel units */
+ /* 1001 : H12 channel units */
+
+ L3UCHAR ChanSlot; /* Channel number */
+
+} Q931ie_ChanID;
+
+/*****************************************************************************
+
+ Struct: Q931ie_DateTime
+
+ Description: Date/time
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00101001 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR Year; /* Year */
+ L3UCHAR Month; /* Month */
+ L3UCHAR Day; /* Day */
+ L3UCHAR Hour; /* Hour */
+ L3UCHAR Minute; /* Minute */
+ L3UCHAR Second; /* Second */
+ L3UCHAR Format; /* Indicate presense of Hour, Min & sec */
+ /* 0 : Only Date */
+ /* 1 : Hour present */
+ /* 2 : Hour and Minute present */
+ /* 3 : Hour, Minute and Second present */
+} Q931ie_DateTime;
+
+/*****************************************************************************
+
+ Struct: Q931ie_Display
+
+ Description: Display
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00101000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR Display[1]; /* Display information (IA5) */
+
+} Q931ie_Display;
+
+/*****************************************************************************
+
+ Struct: Q931ie_HLComp
+
+ Description: High layer compatibility
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01111101 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR CodStand; /* Coding standard */
+ L3UCHAR Interpret; /* Interpretation */
+ L3UCHAR PresMeth; /* Presentation methor of prot. profile */
+ L3UCHAR HLCharID; /* High layer characteristics id. */
+ L3UCHAR EHLCharID; /* Extended high layer character. id. */
+ L3UCHAR EVideoTlfCharID; /* Ext. videotelephony char. id. */
+
+} Q931ie_HLComp;
+
+/*****************************************************************************
+
+ Struct: Q931ie_KeypadFac
+
+ Description: Keypad facility
+
+*****************************************************************************/
+
+typedef struct {
+ L3UCHAR IEId; /* 00101100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR KeypadFac[1]; /* dynamic buffer */
+
+} Q931ie_KeypadFac;
+
+/*****************************************************************************
+
+ Struct: Q931ie_LLComp
+
+ Description: Low layer compatibility
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01111100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR CodStand; /* Coding standard */
+ /* 00 - ITU-T */
+ /* 01 - ISO/IEC */
+ /* 10 - National standard */
+ /* 11 - Network side spesific */
+
+ L3UCHAR ITransCap; /* Information transfer capability */
+ /* 00000 - Speech */
+ /* 01000 - Unrestricted digital info */
+ /* 01001 - Restricted digital info */
+ /* 10000 - 3.1 kHz audio */
+ /* 10001 - Unrestricted with tones */
+ /* 11000 - Video */
+
+ L3UCHAR NegotInd; /* Negot indic. */
+ /* 0 : Out-band neg. not possib. */
+ /* 1 : Out-band neg. possible */
+
+ L3UCHAR TransMode; /* Transfer Mode */
+ /* 00 : Circuit Mode */
+ /* 10 : Packed Mode */
+
+ L3UCHAR InfoRate; /* Information transfer rate */
+ /* 00000 - Packed mode */
+ /* 10000 - 64 kbit/s */
+ /* 10001 - 2 x 64 kbit/s */
+ /* 10011 - 384 kbit/s */
+ /* 10101 - 1536 kbit/s */
+ /* 10111 - 1920 kbit/s */
+ /* 11000 - Multirat (64 kbit/s base) */
+
+ L3UCHAR RateMul; /* Rate multiplier */
+ L3UCHAR Layer1Ident; /* Layer 1 ident. */
+ L3UCHAR UIL1Prot; /* User information layer 1 protocol */
+ /* 00001 : ITU-T V.110, I.460 and X.30 */
+ /* 00010 : G.711 my-law */
+ /* 00011 : G.711 A-law */
+ /* 00100 : G.721 */
+ /* 00101 : H.221 and H.242 */
+ /* 00110 : H.223 and H.245 */
+ /* 00111 : Non ITU-T Standard */
+ /* 01000 : ITU-T V.120 */
+ /* 01001 : ITU-T X.31 HDLC flag stuff. */
+
+ L3UCHAR SyncAsync; /* Synch/asynch */
+ /* 0 : Syncronous data */
+ /* 1 : Asyncronous data */
+
+ L3UCHAR Negot; /* Negot */
+ /* 0 : In-band negotiation not possib. */
+ /* 1 : In-band negotiation possible */
+
+ L3UCHAR UserRate; /* User rate */
+ /* 00000 : I.460, V.110, X,30 */
+ /* 00001 : 0.6 kbit/s x.1 */
+ /* 00010 : 1.2 kbit/s */
+ /* 00011 : 2.4 kbit/s */
+ /* 00100 : 3.6 kbit/s */
+ /* 00101 : 4.8 kbit/s */
+ /* 00110 : 7.2 kbit/s */
+ /* 00111 : 8 kbit/s I.460 */
+ /* 01000 : 9.6 kbit/s */
+ /* 01001 : 14.4 kbit/s */
+ /* 01010 : 16 kbit/s */
+ /* 01011 : 19.2 kbit/s */
+ /* 01100 : 32 kbit/s */
+ /* 01101 : 38.4 kbit/s */
+ /* 01110 : 48 kbit/s */
+ /* 01111 : 56 kbit/s */
+ /* 10000 : 57.6 kbit/s */
+ /* 10010 : 28.8 kbit/s */
+ /* 10100 : 24 kbit/s */
+ /* 10101 : 0.1345 kbit/s */
+ /* 10110 : 0.100 kbit/s */
+ /* 10111 : 0.075/1.2 kbit/s */
+ /* 11000 : 1.2/0.075/kbit/s */
+ /* 11001 : 0.050 kbit/s */
+ /* 11010 : 0.075 kbit/s */
+ /* 11011 : 0.110 kbit/s */
+ /* 11100 : 0.150 kbit/s */
+ /* 11101 : 0.200 kbit/s */
+ /* 11110 : 0.300 kbit/s */
+ /* 11111 : 12 kbit/s */
+
+ L3UCHAR InterRate; /* Intermediate rate */
+ /* 00 : Not used */
+ /* 01 : 8 kbit/s */
+ /* 10 : 16 kbit/s */
+ /* 11 : 32 kbit/s */
+
+ L3UCHAR NIConTx; /* Network Indepentend Clock on transmit*/
+ /* 0 : Not required to send data clc */
+ /* 1 : Send data w/NIC clc */
+
+ L3UCHAR NIConRx; /* NIC on Rx */
+ /* 0 : Cannot accept indep. clc */
+ /* 1 : data with indep. clc accepted */
+
+ L3UCHAR FlowCtlTx; /* Flow control on Tx */
+ /* 0 : Send Flow ctrl not required */
+ /* 1 : Send flow ctrl required */
+
+ L3UCHAR FlowCtlRx; /* Flow control on Rx */
+ /* 0 : cannot use receive flow ctrl */
+ /* 1 : Receive flow ctrl accepted */
+ L3UCHAR HDR; /* HDR/No HDR */
+ L3UCHAR MultiFrame; /* Multi frame support */
+ /* 0 : multiframe not supported */
+ /* 1 : multiframe supported */
+
+ L3UCHAR ModeL1; /* Mode L1 */
+ /* 0 : bit transparent mode of operat. */
+ /* 1 : protocol sesitive mode of op. */
+
+ L3UCHAR NegotLLI; /* Negot. LLI */
+ /* 0 : default LLI=256 only */
+ /* 1 : Full protocol negotiation */
+
+ L3UCHAR Assignor; /* Assignor/Assignor ee */
+ /* 0 : Default Asignee */
+ /* 1 : Assignor only */
+
+ L3UCHAR InBandNeg; /* In-band negot. */
+ /* 0 : negot done w/ USER INFO mes */
+ /* 1 : negot done in-band w/link zero */
+
+ L3UCHAR NumStopBits; /* Number of stop bits */
+ /* 00 : Not used */
+ /* 01 : 1 bit */
+ /* 10 : 1.5 bits */
+ /* 11 : 2 bits */
+
+ L3UCHAR NumDataBits; /* Number of data bits. */
+ /* 00 : not used */
+ /* 01 : 5 bits */
+ /* 10 : 7 bits */
+ /* 11 : 8 bits */
+
+ L3UCHAR Parity; /* Parity Information */
+ /* 000 : Odd */
+ /* 010 : Even */
+ /* 011 : None */
+ /* 100 : Forced to 0 */
+ /* 101 : Forced to 1 */
+
+ L3UCHAR DuplexMode; /* Mode duplex */
+ /* 0 : Half duplex */
+ /* 1 : Full duplex */
+
+ L3UCHAR ModemType; /* Modem type, see Q.931 p 89 */
+
+ L3UCHAR Layer2Ident; /* Layer 2 ident. */
+
+ L3UCHAR UIL2Prot; /* User information layer 2 protocol */
+ /* 00001 : Basic mode ISO 1745 */
+ /* 00010 : Q.921/I.441 */
+ /* 00110 : X.25 single link */
+ /* 00111 : X.25 multilink */
+ /* 01000 : Extended LAPB T.71 */
+ /* 01001 : HDLC ARM */
+ /* 01010 : HDLC NRM */
+ /* 01011 : HDLC ABM */
+ /* 01100 : LAN logical link */
+ /* 01101 : X.75 SLP */
+ /* 01110 : Q.922 */
+ /* 01111 : Q.922 core aspect */
+ /* 10000 : User specified */
+ /* 10001 : ISO/IEC 7776 DTE-DCE */
+
+ L3UCHAR ModeL2; /* Mode */
+ /* 01 : Normal Mode of operation */
+ /* 10 : Extended mode of operation */
+
+ L3UCHAR Q933use; /* Q.9333 use */
+
+ L3UCHAR UsrSpcL2Prot; /* User specified layer 2 protocol info */
+
+ L3UCHAR WindowSize; /* Window size (k) */
+
+ L3UCHAR Layer3Ident; /* Layer 3 ident */
+
+ L3UCHAR UIL3Prot; /* User Information Layer 3 protocol */
+ /* 00010 : Q.931 */
+ /* 00110 : X.25 */
+ /* 00111 : 8208 */
+ /* 01000 : X.233 ... */
+ /* 01001 : 6473 */
+ /* 01010 : T.70 */
+ /* 01011 : ISO/IEC TR 9577 */
+ /* 10000 : User specified */
+ L3UCHAR OptL3Info; /* Optional Leyer 3 info */
+
+ L3UCHAR ModeL3; /* Mode of operation */
+ /* 01 : Normal packed seq. numbering */
+ /* 10 : Extended packed seq. numbering */
+
+ L3UCHAR DefPackSize; /* Default packet size */
+
+ L3UCHAR PackWinSize; /* Packet window size */
+
+ L3UCHAR AddL3Info; /* Additional Layer 3 protocol info */
+
+} Q931ie_LLComp;
+
+/*****************************************************************************
+
+ Struct: Q931ie_NetFac;
+
+ Description: Network-specific facilities
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00100000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR LenNetID; /* Length of network facilities id. */
+ L3UCHAR TypeNetID; /* Type of network identification */
+ L3UCHAR NetIDPlan; /* Network identification plan. */
+ L3UCHAR NetFac; /* Network specific facility spec. */
+ L3UCHAR NetID[1]; /* Network id. (IA5) */
+
+} Q931ie_NetFac;
+
+/*****************************************************************************
+
+ Struct: Q931ie_NotifInd;
+
+ Description: Notification Indicator
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00100000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR Notification; /* Notification descriptor */
+
+} Q931ie_NotifInd;
+
+/*****************************************************************************
+
+ Struct: Q931ie_ProgInd
+
+ Description: Progress indicator
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00011110 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR CodStand; /* Coding standard */
+ L3UCHAR Location; /* Location */
+ L3UCHAR ProgDesc; /* Progress description */
+
+} Q931ie_ProgInd;
+
+/*****************************************************************************
+
+ Struct; Q931ie_Segment
+
+ Description: Segmented message
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00000000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR FSI; /* First segment indicator */
+ L3UCHAR NumSegRem; /* Number of segments remaining */
+ L3UCHAR SegType; /* Segment message type */
+
+} Q931ie_Segment;
+
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00000000 */
+ L3UCHAR Size; /* Length of Information Element */
+
+} Q931ie_SendComplete;
+
+/*****************************************************************************
+
+ Struct: Q931ie_Signal
+
+ Description: Signal
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00000000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR Signal; /* Signal value */
+ /* 00000000 Dial tone on */
+ /* 00000001 Ring back tone on */
+ /* 00000010 Intercept tone on */
+ /* 00000011 Network congestion on */
+ /* 00000100 Busy tone on */
+ /* 00000101 Confirm tone on */
+ /* 00000110 Answer tone on */
+ /* 00000111 Call waiting tone */
+ /* 00001000 Off-hook warning tone */
+ /* 00001001 Pre-emption tone on */
+ /* 00111111 Tones off */
+ /* 01000000 Alerting on - pattern 0 */
+ /* 01000001 Alerting on - pattern 1 */
+ /* 01000010 Alerting on - pattern 2 */
+ /* 01000011 Alerting on - pattern 3 */
+ /* 01000100 Alerting on - pattern 4 */
+ /* 01000101 Alerting on - pattern 5 */
+ /* 01000110 Alerting on - pattern 6 */
+ /* 01000111 Alerting on - pattern 7 */
+ /* 01001111 Alerting off */
+} Q931ie_Signal;
+
+/*****************************************************************************
+
+ Struct: Q931ie_TransDelSelInd
+
+ description: Transit delay selection and indication
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+ L3UCHAR IEId; /* 00000000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3ULONG TxDSIValue; /* Trans. delay sel. & ind. value */
+
+} Q931ie_TransDelSelInd;
+#endif
+
+/*****************************************************************************
+
+ Struct: Q931ie_TransNetSel
+
+ Description: Transit network selection
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01111000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR Type; /* Type of network identifier */
+ L3UCHAR NetIDPlan; /* Network idetification plan */
+ L3UCHAR NetID[1]; /* Network identification(IA5) */
+
+} Q931ie_TransNetSel;
+
+/*****************************************************************************
+
+ Struct: Q931ie_UserUser
+
+ Description: User-user
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01111110 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR ProtDisc; /* Protocol discriminator */
+ L3UCHAR User[1]; /* User information */
+
+} Q931ie_UserUser;
+
+/*****************************************************************************
+
+ Struct: Q931ie_ClosedUserGrp
+
+ Description: Closed user group
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+ L3UCHAR IEId; /* 01000111 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR CUGInd; /* CUG indication */
+ L3UCHAR CUG[1]; /* CUG index code (IA5) */
+
+} Q931ie_ClosedUserGrp;
+#endif
+
+/*****************************************************************************
+
+ Struct: Q931ie_CongLevel
+
+ Description: Congestion Level
+
+*****************************************************************************/
+typedef struct {
+
+ L3UCHAR IEId; /* 01000111 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR CongLevel; /* Conguestion Level */
+
+} Q931ie_CongLevel;
+
+/*****************************************************************************
+
+ Struct: Q931ie_EndEndTxDelay
+
+ Description: End to end transit delay
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+ L3UCHAR IEId; /* 01000010 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3ULONG CumTxDelay; /* Cumulative transit delay value */
+ L3ULONG ReqTxDelay; /* Requested end to end transit delay */
+ L3ULONG MaxTxDelay; /* Maximum transit delay */
+
+} Q931ie_EndEndTxDelay;
+#endif
+
+/*****************************************************************************
+
+ Struct: Q931ie_InfoRate
+
+ Description: Information Rate
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+ L3UCHAR IEId; /* 01100000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR InInfoRate; /* Incoming information rate */
+ L3UCHAR OutInfoRate; /* Outgoing information rate */
+ L3UCHAR MinInInfoRate; /* Minimum incoming information rate */
+ L3UCHAR MinOutInfoRate; /* Minimum outgoing information rate */
+
+} Q931ie_InfoRate;
+#endif
+
+/*****************************************************************************
+
+ Struct: Q931ie_PackParam
+
+ Description: Packed layer binary parameters
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+ L3UCHAR IEId; /* 01000100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR FastSel; /* Fast selected */
+ L3UCHAR ExpData; /* Exp. data */
+ L3UCHAR DelConf; /* Delivery conf */
+ L3UCHAR Modulus; /* Modulus */
+
+} Q931ie_PackParam;
+#endif
+
+/*****************************************************************************
+
+ Struct: Q931ie_PackWinSize
+
+ Description: Packed window size
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+ L3UCHAR IEId; /* 01000101 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR ForwardValue; /* Forward value */
+ L3UCHAR BackwardValue; /* Backward value */
+
+} Q931ie_PackWinSize;
+#endif
+
+/*****************************************************************************
+
+ Struct: Q931ie_PackSize
+
+ Description: Packet size
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+ L3UCHAR IEId; /* 01000110 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR ForwardValue; /* Forward value */
+ L3UCHAR BackwardValue; /* Backward value */
+
+} Q931ie_PackSize;
+#endif
+
+/*****************************************************************************
+
+ Struct: Q931ie_RedirNum
+
+ Description: Redirecting number
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+ L3UCHAR IEId; /* 01110100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR TypeNum; /* Type of number */
+ L3UCHAR NumPlanID; /* Number plan identification */
+ L3UCHAR PresInd; /* Presentation indicator */
+ L3UCHAR ScreenInd; /* Screening indicator */
+ L3UCHAR Reason; /* Reason for redirection */
+ L3UCHAR Digit[1]; /* Number digits (IA5) */
+
+} Q931ie_RedirNum;
+#endif
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01110100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR RepeatInd; /* 0010 Prioritized list for selecting */
+ /* one possible. */
+} Q931ie_RepeatInd;
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01110100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR Spare; /* Spare */
+ L3UCHAR Class; /* Class */
+ /* 000 Indicate channels */
+ /* 110 Single interface */
+ /* 111 All interfaces */
+} Q931ie_RestartInd;
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01110100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR Preference; /* Preference 0 = reserved, 1 = channel */
+ L3UCHAR Spare; /* Spare */
+ L3UCHAR NewStatus; /* NewStatus */
+ /* 000 In service */
+ /* 001 Maintenance */
+ /* 010 Out of service */
+} Q931ie_ChangeStatus;
+
+/*****************************************************************************
+
+ Struct: Q931ie_GenericDigits
+
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00110111 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR Type; /* Type of number */
+ L3UCHAR Encoding; /* Encoding of number */
+ L3UCHAR Digit[1]; /* Number digits (IA5) */
+
+} Q931ie_GenericDigits;
+
+
+/*****************************************************************************
+
+ Q.931 Information Element Pack/Unpack functions. Implemented in Q931ie.c
+
+*****************************************************************************/
+q931pie_func_t Q931Pie_ChangeStatus;
+q931pie_func_t Q931Pie_BearerCap;
+q931pie_func_t Q931Pie_ChanID;
+q931pie_func_t Q931Pie_ProgInd;
+q931pie_func_t Q931Pie_Display;
+q931pie_func_t Q931Pie_Signal;
+q931pie_func_t Q931Pie_HLComp;
+q931pie_func_t Q931Pie_Segment;
+q931pie_func_t Q931Pie_DateTime;
+q931pie_func_t Q931Pie_Cause;
+q931pie_func_t Q931Pie_SendComplete;
+q931pie_func_t Q931Pie_KeypadFac;
+q931pie_func_t Q931Pie_NotifInd;
+q931pie_func_t Q931Pie_CallID;
+q931pie_func_t Q931Pie_RepeatInd;
+q931pie_func_t Q931Pie_NetFac;
+q931pie_func_t Q931Pie_CallingNum;
+q931pie_func_t Q931Pie_CallingSub;
+q931pie_func_t Q931Pie_CalledNum;
+q931pie_func_t Q931Pie_CalledSub;
+q931pie_func_t Q931Pie_CalledNum;
+q931pie_func_t Q931Pie_TransNetSel;
+q931pie_func_t Q931Pie_LLComp;
+q931pie_func_t Q931Pie_CallState;
+q931pie_func_t Q931Pie_RestartInd;
+q931pie_func_t Q931Pie_UserUser;
+
+q931pie_func_t Q931Pie_GenericDigits;
+
+L3USHORT Q931Uie_CRV(Q931_TrunkInfo_t *pTrunk,L3UCHAR * IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff);
+
+q931uie_func_t Q931Uie_ChangeStatus;
+q931uie_func_t Q931Uie_BearerCap;
+q931uie_func_t Q931Uie_ChanID;
+q931uie_func_t Q931Uie_ProgInd;
+q931uie_func_t Q931Uie_Display;
+q931uie_func_t Q931Uie_Signal;
+q931uie_func_t Q931Uie_HLComp;
+q931uie_func_t Q931Uie_Segment;
+q931uie_func_t Q931Uie_DateTime;
+q931uie_func_t Q931Uie_Cause;
+q931uie_func_t Q931Uie_SendComplete;
+q931uie_func_t Q931Uie_KeypadFac;
+q931uie_func_t Q931Uie_NotifInd;
+q931uie_func_t Q931Uie_CallID;
+q931uie_func_t Q931Uie_RepeatInd;
+q931uie_func_t Q931Uie_NetFac;
+q931uie_func_t Q931Uie_CallingNum;
+q931uie_func_t Q931Uie_CallingSub;
+q931uie_func_t Q931Uie_CalledNum;
+q931uie_func_t Q931Uie_CalledSub;
+q931uie_func_t Q931Uie_TransNetSel;
+q931uie_func_t Q931Uie_LLComp;
+q931uie_func_t Q931Uie_CallState;
+q931uie_func_t Q931Uie_RestartInd;
+q931uie_func_t Q931Uie_UserUser;
+
+q931uie_func_t Q931Uie_GenericDigits;
+
+
+L3INT Q931ReadExt(L3UCHAR * IBuf, L3INT Off);
+L3INT Q931Uie_CongLevel(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff);
+L3INT Q931Pie_CongLevel(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+L3INT Q931Uie_RevChargeInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff);
+L3INT Q931Pie_RevChargeInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+
+L3INT Q931Uie_Generic(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff);
+L3INT Q931Pie_Generic(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+
+#endif /* _Q931IE_NL */
Added: freeswitch/trunk/libs/freetdm/src/isdn/include/Q932.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/include/Q932.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/include/Q932.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,95 @@
+/*****************************************************************************
+
+ FileName: Q932.h
+
+ Contents: Header w/structs for Q932 Suplementary Services.
+
+ NB: Do NOT include this header directly, include Q931.h
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+/*****************************************************************************
+ Q.932 Additional Message codes
+*****************************************************************************/
+
+#define Q932mes_HOLD 0x24 /* 0010 0100 */
+#define Q932mes_HOLD_ACKNOWLEDGE 0x28 /* 0010 1000 */
+#define Q932mes_HOLD_REJECT 0x30 /* 0011 0000 */
+#define Q932mes_RETRIEVE 0x31 /* 0011 0001 */
+#define Q932mes_RETRIEVE_ACKNOWLEDGE 0x33 /* 0011 0011 */
+#define Q932mes_RETRIEVE_REJECT 0x37 /* 0011 0111 */
+#define Q932mes_FACILITY 0x62 /* 0110 0010 */
+#define Q932mes_REGISTER 0x64 /* 0110 0100 */
+
+/*****************************************************************************
+ Q.932 Additional EI Codes
+*****************************************************************************/
+#define Q932ie_FACILITY 0x1c /* 0001 1100 */
+
+/*****************************************************************************
+ Function Prototypes.
+*****************************************************************************/
+L3INT Q932ProcFacilityTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRegisterTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+
+L3INT Q932ProcFacilityNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRegisterNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+
+L3INT Q932Pmes_Facility(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_Hold(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_HoldAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_HoldReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_Register(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_Retrieve(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_RetrieveAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_RetrieveReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+L3INT Q932Umes_Facility(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_Hold(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_HoldAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_HoldReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_Register(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_Retrieve(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_RetrieveAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_RetrieveReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
Added: freeswitch/trunk/libs/freetdm/src/isdn/include/mfifo.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/include/mfifo.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/include/mfifo.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,85 @@
+/*****************************************************************************
+
+ Filename: mfifo.h
+
+ Contents: header for MFIFO
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+#ifndef _MFIFO
+#define _MFIFO
+
+/*****************************************************************************
+
+ Struct: MINDEX
+
+ Description: Message Index used to index a dynamic size Message FIFO.
+
+*****************************************************************************/
+typedef struct _mindex {
+ int offset; /* offset to message in buf */
+ int size; /* size of message in bytes */
+} MINDEX;
+
+/*****************************************************************************
+
+ Struct: MFIFO
+
+ Description: Message FIFO. Provides a dynamic sized message based FIFO
+ queue.
+
+*****************************************************************************/
+typedef struct {
+ int first; /* first out */
+ int last; /* last in + 1 */
+ int bsize; /* buffer size */
+ unsigned char *buf; /* ptr to start of buffer */
+ int ixsize; /* index size */
+ MINDEX ix[1]; /* message index */
+} MFIFO;
+
+/*****************************************************************************
+ Function prototypes.
+*****************************************************************************/
+int MFIFOCreate(unsigned char *buf, int size, int index);
+void MFIFOClear(unsigned char * buf);
+int MFIFOGetLBOffset(unsigned char *buf);
+int MFIFOGetFBOffset(unsigned char *buf);
+void MFIFOWriteIX(unsigned char *buf, unsigned char *mes, int size, int ix, int off);
+int MFIFOWriteMes(unsigned char *buf, unsigned char *mes, int size);
+unsigned char * MFIFOGetMesPtr(unsigned char *buf, int *size);
+void MFIFOKillNext(unsigned char *buf);
+
+unsigned char * MFIFOGetMesPtrOffset(unsigned char *buf, int *size, const int pos);
+int MFIFOGetMesCount(unsigned char *buf);
+int MFIFOWriteMesOverwrite(unsigned char *buf, unsigned char *mes, int size);
+
+#endif
Added: freeswitch/trunk/libs/freetdm/src/isdn/include/national.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/include/national.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/include/national.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,86 @@
+/******************************************************************************
+
+ FileName: national.h
+
+ Contents: Header and definition for the National ISDN dialect. The
+ header contents the following parts:
+ - Definition of codes
+ - Definition of information elements (nationalie_).
+ - Definition of messages (nationalmes_).
+ - Function prototypes.
+
+ Description: The National ISDN dialect here covers ????
+
+ Related Files: national.h National ISDN Definitions
+ nationalie.c National ISDN IE encoders/coders
+ nationalStateTE.c National ISDN TE State Engine
+ nationalStateNT.c National ISDN NT State Engine
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ 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 Case Labs, Ltd 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.
+******************************************************************************/
+
+#ifndef _national_NATIONAL_NL
+#define _national_NATIONAL_NL
+
+#include "Q931.h"
+
+/*****************************************************************************
+
+ Q.931 Message codes
+ Only National specific message and ie types
+ here the rest are inherited from national.h
+
+*****************************************************************************/
+
+
+/*****************************************************************************
+
+ Q.931 Message Pack/Unpack functions. Implemented in nationalmes.c
+
+*****************************************************************************/
+L3INT nationalUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT nationalPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+#include "DMS.h"
+
+/*****************************************************************************
+
+ Q.931 Process Function Prototyping. Implemented in nationalStateTE.c
+
+*****************************************************************************/
+
+void nationalCreateTE(L3UCHAR i);
+void nationalCreateNT(L3UCHAR i);
+
+#endif /* _national_NATIONAL_NL */
Added: freeswitch/trunk/libs/freetdm/src/isdn/mfifo.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/mfifo.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/mfifo.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,399 @@
+/*****************************************************************************
+
+ Filename: mfifo.c
+
+ Description: mfifo is a message orriented fifo system with support of
+ both message and byte per byte retriaval of messages.
+
+ The fifo has been designed with two usages in mind:
+
+ - Queueing of frames for hdlc and feeding out byte per byte
+ with the possibility of re-sending of frames etc.
+
+ - fifo for messages of dynamic size.
+
+ The fifo is allocated on top of any buffer and creates an
+ index of message in the queue. The user can write/read
+ messages or write messages and read the message one byte
+ at the time.
+
+ Interface:
+ MFIFOCreate Create/reset/initialize fifo.
+ MFIFOClear Clear FIFO.
+ MFIFOWriteMes Write message into fifo
+ * MFIFOReadMes Read message from fifo.
+ MFIFOGetMesPtr Get ptr to next message.
+ MFIFOKillNext Kill next message.
+
+ * currently not implemented.
+
+ Note: The message will always be saved continuously. If there is not
+ sufficient space at the end of the buffer, the fifo will skip
+ the last bytes and save the message at the top of the buffer.
+
+ This is required to allow direct ptr access to messages
+ stored in the queue.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "mfifo.h"
+#include <memory.h>
+#include <stdlib.h>
+
+/*****************************************************************************
+
+ Function: MFIFOCreate
+
+ Description: Creates a fifo on top of an existing buffer.
+
+ Parameters: buf ptr to buffer.
+ size size of buffer in bytes.
+ index size of index entries (max no messages).
+
+ Return value: 0 if failure, 1 if ok.
+
+*****************************************************************************/
+int MFIFOCreate(unsigned char *buf, int size, int index)
+{
+ MFIFO *mf = (MFIFO *)buf;
+
+ mf->first = mf->last = 0;
+ mf->ixsize = index;
+ mf->buf = &buf[sizeof(MFIFO) + (sizeof(MINDEX) * index)];
+
+ if (mf->buf > &buf[size])
+ return 0;
+
+ mf->bsize = size - sizeof(MFIFO) - (sizeof(MINDEX) * index);
+
+ return 1;
+}
+
+/*****************************************************************************
+
+ Function: MFIFOClear
+
+ Description: Clear the FIFO
+
+ Paremeters: buf ptr to fifo
+
+ Return Value: none
+
+*****************************************************************************/
+void MFIFOClear(unsigned char * buf)
+{
+ MFIFO *mf = (MFIFO *)buf;
+
+ mf->first = mf->last = 0;
+}
+
+/*****************************************************************************
+
+ Function: MFIFOGetLBOffset
+
+ Description: Helper function caclulating offset to the 'first out' byte.
+
+ Paremeters: buf ptr to fifo
+
+ Return Value: offset.
+
+*****************************************************************************/
+int MFIFOGetLBOffset(unsigned char *buf)
+{
+ MFIFO *mf = (MFIFO *)buf;
+
+ if (mf->last != mf->first)
+ return mf->ix[mf->last].offset;
+
+ return 0;
+}
+
+/*****************************************************************************
+
+ Function: MFIFOGetFBOffset
+
+ Description: Helper function calculating the offset to the 'first in'
+ byte in the buffer. This is the position the next byte
+ entering the fifo will occupy.
+
+ Paremeters: buf ptr to fifo
+
+ Return Value: offset
+
+*****************************************************************************/
+int MFIFOGetFBOffset(unsigned char *buf)
+{
+ MFIFO *mf = (MFIFO *)buf;
+ int x;
+
+ if (mf->last == mf->first)
+ return 0;
+
+ x = mf->first - 1;
+
+ if (x < 0)
+ x = mf->ixsize - 1;
+
+ return mf->ix[x].offset + mf->ix[x].size;
+}
+
+/*****************************************************************************
+
+ Function: MFIFOWriteIX
+
+ Description: Helper function writing a calculated entry. The function
+ will perform a memcpy to move the message and set the index
+ values as well as increase the 'first in' index.
+
+ Paremeters: buf ptr to fifo
+ mes ptr to message
+ size size of message in bytes.
+ ix index to index entry.
+ off offset to position to receive the message
+
+ Return Value: none
+
+*****************************************************************************/
+void MFIFOWriteIX(unsigned char *buf, unsigned char *mes, int size, int ix, int off)
+{
+ MFIFO *mf = (MFIFO *)buf;
+ int x;
+
+ memcpy(&mf->buf[off], mes, size);
+ mf->ix[ix].offset = off;
+ mf->ix[ix].size = size;
+
+ x = mf->first + 1;
+
+ if (x >= mf->ixsize)
+ x = 0;
+
+ mf->first = x;
+}
+
+/*****************************************************************************
+
+ Function: MFIFOWriteMes
+
+ Description:
+
+ Paremeters:
+
+ Return Value:
+
+*****************************************************************************/
+int MFIFOWriteMes(unsigned char *buf, unsigned char *mes, int size)
+{
+ MFIFO *mf = (MFIFO *)buf;
+ int of, ol, x;
+
+ x = mf->first + 1;
+
+ if (x >= mf->ixsize)
+ x = 0;
+
+ if (x == mf->last)
+ return 0; /* full queue */
+
+ of = MFIFOGetFBOffset(buf);
+ ol = MFIFOGetLBOffset(buf);
+ if (mf->last == mf->first) { /* empty queue */
+ mf->first = mf->last = 0; /* optimize */
+
+ MFIFOWriteIX(buf, mes, size, mf->first, 0);
+ return 1;
+ }
+ else if (of > ol) {
+ if (mf->bsize - of >= size) {
+ MFIFOWriteIX(buf, mes, size, mf->first, of);
+ return 1;
+ }
+ else if (ol > size) {
+ MFIFOWriteIX(buf, mes, size, mf->first, ol);
+ return 1;
+ }
+ }
+ else if (ol - of > size) {
+ MFIFOWriteIX(buf, mes, size, mf->first, of);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+
+ Function: MFIFOGetMesPtr
+
+ Description:
+
+ Paremeters:
+
+ Return Value:
+
+*****************************************************************************/
+unsigned char * MFIFOGetMesPtr(unsigned char *buf, int *size)
+{
+ MFIFO *mf = (MFIFO *)buf;
+
+ if (mf->first == mf->last) {
+ return NULL;
+ }
+
+ *size = mf->ix[mf->last].size;
+ return &mf->buf[mf->ix[mf->last].offset];
+}
+
+/*****************************************************************************
+
+ Function: MFIFOKillNext
+
+ Description:
+
+ Paremeters:
+
+ Return Value:
+
+*****************************************************************************/
+void MFIFOKillNext(unsigned char *buf)
+{
+ MFIFO *mf = (MFIFO *)buf;
+ int x;
+
+ if (mf->first != mf->last) {
+ x = mf->last + 1;
+ if (x >= mf->ixsize) {
+ x = 0;
+ }
+
+ mf->last = x;
+ }
+}
+
+
+/*
+ * Queue-style accessor functions
+ */
+
+/**
+ * MFIFOGetMesPtrOffset
+ * \brief Get pointer to and size of message at position x
+ */
+unsigned char * MFIFOGetMesPtrOffset(unsigned char *buf, int *size, const int pos)
+{
+ MFIFO *mf = (MFIFO *)buf;
+ int x;
+
+ if (mf->first == mf->last) {
+ return NULL;
+ }
+
+ if (pos < 0 || pos >= mf->ixsize) {
+ return NULL;
+ }
+
+ x = pos - mf->last;
+ if (x < 0) {
+ x += (mf->ixsize - 1);
+ }
+
+ *size = mf->ix[x].size;
+ return &mf->buf[mf->ix[x].offset];
+}
+
+
+/**
+ * MFIFOGetMesCount
+ * \brief How many messages are currently in the buffer?
+ */
+int MFIFOGetMesCount(unsigned char *buf)
+{
+ MFIFO *mf = (MFIFO *)buf;
+
+ if (mf->first == mf->last) {
+ return 0;
+ }
+ else if (mf->first > mf->last) {
+ return mf->first - mf->last;
+ }
+ else {
+ return (mf->ixsize - mf->last) + mf->first;
+ }
+}
+
+/**
+ * MFIFOWriteMesOverwrite
+ * \brief Same as MFIFOWriteMes but old frames will be overwritten if the fifo is full
+ */
+int MFIFOWriteMesOverwrite(unsigned char *buf, unsigned char *mes, int size)
+{
+ MFIFO *mf = (MFIFO *)buf;
+ int of, ol, x;
+
+ x = mf->first + 1;
+
+ if (x >= mf->ixsize)
+ x = 0;
+
+ if (x == mf->last) {
+ /* advance last pointer */
+ mf->last++;
+
+ if (mf->last >= mf->ixsize)
+ mf->last = 0;
+ }
+
+ of = MFIFOGetFBOffset(buf);
+ ol = MFIFOGetLBOffset(buf);
+
+ if (mf->last == mf->first) { /* empty queue */
+ mf->first = mf->last = 0; /* optimize */
+
+ MFIFOWriteIX(buf, mes, size, mf->first, 0);
+ return 1;
+ }
+ else if (of > ol) {
+ if (mf->bsize - of >= size) {
+ MFIFOWriteIX(buf, mes, size, mf->first, of);
+ return 1;
+ }
+ else if (ol > size) {
+ MFIFOWriteIX(buf, mes, size, mf->first, ol);
+ return 1;
+ }
+ }
+ else if (ol - of > size) {
+ MFIFOWriteIX(buf, mes, size, mf->first, of);
+ return 1;
+ }
+ return 0;
+}
Added: freeswitch/trunk/libs/freetdm/src/isdn/nationalStateNT.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/nationalStateNT.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/nationalStateNT.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,130 @@
+/*****************************************************************************
+
+ FileName: nationalStateNT.c
+
+ Contents: National ISDN State Engine for NT (Network Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "national.h"
+
+/*****************************************************************************
+ Function: nationalCreateNT
+
+ Description: Will create the National ISDN NT as a Dialect in the stack. The first
+ bulk set up the message handlers, the second bulk the IE
+ encoders/coders, and the last bulk set up the state table.
+
+ Parameters: i Dialect index
+*****************************************************************************/
+void nationalCreateNT(L3UCHAR i)
+{
+ Q931SetMesProc(Q931mes_ALERTING, i, Q931ProcAlertingNT, Q931Umes_Alerting, Q931Pmes_Alerting);
+ Q931SetMesProc(Q931mes_CALL_PROCEEDING, i, Q931ProcCallProceedingNT, Q931Umes_CallProceeding, Q931Pmes_CallProceeding);
+ Q931SetMesProc(Q931mes_CONNECT, i, Q931ProcConnectNT, Q931Umes_Connect, Q931Pmes_Connect);
+ Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i, Q931ProcConnectAckNT, Q931Umes_ConnectAck, Q931Pmes_ConnectAck);
+ Q931SetMesProc(Q931mes_PROGRESS, i, Q931ProcProgressNT, Q931Umes_Progress, Q931Pmes_Progress);
+ Q931SetMesProc(Q931mes_SETUP, i, Q931ProcSetupNT, nationalUmes_Setup, nationalPmes_Setup);
+ Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE, i, Q931ProcSetupAckNT, Q931Umes_SetupAck, Q931Pmes_SetupAck);
+ Q931SetMesProc(Q931mes_RESUME, i, Q931ProcResumeNT, Q931Umes_Resume, Q931Pmes_Resume);
+ Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE, i, Q931ProcResumeAckNT, Q931Umes_ResumeAck, Q931Pmes_ResumeAck);
+ Q931SetMesProc(Q931mes_RESUME_REJECT, i, Q931ProcResumeRejectNT, Q931Umes_ResumeReject, Q931Pmes_ResumeReject);
+ Q931SetMesProc(Q931mes_SUSPEND, i, Q931ProcSuspendNT, Q931Umes_Suspend, Q931Pmes_Suspend);
+ Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE, i, Q931ProcSuspendAckNT, Q931Umes_SuspendAck, Q931Pmes_SuspendAck);
+ Q931SetMesProc(Q931mes_SUSPEND_REJECT, i, Q931ProcSuspendRejectNT, Q931Umes_SuspendReject, Q931Pmes_SuspendReject);
+ Q931SetMesProc(Q931mes_USER_INFORMATION, i, Q931ProcUserInformationNT, Q931Umes_UserInformation, Q931Pmes_UserInformation);
+ Q931SetMesProc(Q931mes_DISCONNECT, i, Q931ProcDisconnectNT, Q931Umes_Disconnect, Q931Pmes_Disconnect);
+ Q931SetMesProc(Q931mes_RELEASE, i, Q931ProcReleaseNT, Q931Umes_Release, Q931Pmes_Release);
+ Q931SetMesProc(Q931mes_RELEASE_COMPLETE, i, Q931ProcReleaseCompleteNT, Q931Umes_ReleaseComplete, Q931Pmes_ReleaseComplete);
+ Q931SetMesProc(Q931mes_RESTART, i, Q931ProcRestartNT, Q931Umes_Restart, Q931Pmes_Restart);
+ Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE, i, Q931ProcRestartAckNT, Q931Umes_RestartAck, Q931Pmes_RestartAck);
+ Q931SetMesProc(Q931mes_CONGESTION_CONTROL, i, Q931ProcCongestionControlNT, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+ Q931SetMesProc(Q931mes_INFORMATION, i, Q931ProcInformationNT, Q931Umes_Information, Q931Pmes_Information);
+ Q931SetMesProc(Q931mes_NOTIFY, i, Q931ProcNotifyNT, Q931Umes_Notify, Q931Pmes_Notify);
+ Q931SetMesProc(Q931mes_STATUS, i, Q931ProcStatusNT, Q931Umes_Status, Q931Pmes_Status);
+ Q931SetMesProc(Q931mes_STATUS_ENQUIRY, i, Q931ProcStatusEnquiryNT, Q931Umes_StatusEnquiry, Q931Pmes_StatusEnquiry);
+ Q931SetMesProc(Q931mes_SEGMENT, i, Q931ProcSegmentNT, Q931Umes_Segment, Q931Pmes_Segment);
+
+ Q931SetMesProc(Q932mes_FACILITY, i, Q932ProcFacilityNT, Q932Umes_Facility, Q932Pmes_Facility);
+ Q931SetMesProc(Q932mes_HOLD, i, Q932ProcHoldNT, Q932Umes_Hold, Q932Pmes_Hold);
+ Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE, i, Q932ProcHoldAckNT, Q932Umes_HoldAck, Q932Pmes_HoldAck);
+ Q931SetMesProc(Q932mes_HOLD_REJECT, i, Q932ProcHoldRejectNT, Q932Umes_HoldReject, Q932Pmes_HoldReject);
+ Q931SetMesProc(Q932mes_REGISTER, i, Q932ProcRegisterNT, Q932Umes_Register, Q932Pmes_Register);
+ Q931SetMesProc(Q932mes_RETRIEVE, i, Q932ProcRetrieveNT, Q932Umes_Retrieve, Q932Pmes_Retrieve);
+ Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckNT, Q932Umes_RetrieveAck, Q932Pmes_RetrieveAck);
+ Q931SetMesProc(Q932mes_RETRIEVE_REJECT, i, Q932ProcRetrieveRejectNT, Q932Umes_RetrieveReject, Q932Pmes_RetrieveReject);
+
+ /* Set up the IE encoder/decoder handle table.*/
+ Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE, i, Q931Pie_Segment, Q931Uie_Segment);
+ Q931SetIEProc(Q931ie_BEARER_CAPABILITY, i, Q931Pie_BearerCap, Q931Uie_BearerCap);
+ Q931SetIEProc(Q931ie_CAUSE, i, Q931Pie_Cause, Q931Uie_Cause);
+ Q931SetIEProc(Q931ie_CALL_IDENTITY, i, Q931Pie_CallID, Q931Uie_CallID);
+ Q931SetIEProc(Q931ie_CALL_STATE, i, Q931Pie_CallState, Q931Uie_CallState);
+ Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION, i, Q931Pie_ChanID, Q931Uie_ChanID);
+ Q931SetIEProc(Q931ie_PROGRESS_INDICATOR, i, Q931Pie_ProgInd, Q931Uie_ProgInd);
+ Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES, i, Q931Pie_NetFac, Q931Uie_NetFac);
+ Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR, i, Q931Pie_NotifInd, Q931Uie_NotifInd);
+ Q931SetIEProc(Q931ie_DISPLAY, i, Q931Pie_Display, Q931Uie_Display);
+ Q931SetIEProc(Q931ie_DATETIME, i, Q931Pie_DateTime, Q931Uie_DateTime);
+ Q931SetIEProc(Q931ie_KEYPAD_FACILITY, i, Q931Pie_KeypadFac, Q931Uie_KeypadFac);
+ Q931SetIEProc(Q931ie_SIGNAL, i, Q931Pie_Signal, Q931Uie_Signal);
+ Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER, i, Q931Pie_CallingNum, Q931Uie_CallingNum);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS, i, Q931Pie_CallingSub, Q931Uie_CallingSub);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER, i, Q931Pie_CalledNum, Q931Uie_CalledNum);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS, i, Q931Pie_CalledSub, Q931Uie_CalledSub);
+ Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_RESTART_INDICATOR, i, Q931Pie_RestartInd, Q931Uie_RestartInd);
+ Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY, i, Q931Pie_LLComp, Q931Uie_LLComp);
+ Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY, i, Q931Pie_HLComp, Q931Uie_HLComp);
+ Q931SetIEProc(Q931ie_USER_USER, i, Q931Pie_UserUser, Q931Uie_UserUser);
+ Q931SetIEProc(Q931ie_GENERIC_DIGITS, i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+ Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_FACILITY, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_REDIRECTING_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+
+ /* The following define a state machine. The point is that the Message */
+ /* procs can when search this to find out if the message/state */
+ /* combination is legale. If not, the proc for unexpected message apply.*/
+
+ /* TODO define state table here */
+}
Added: freeswitch/trunk/libs/freetdm/src/isdn/nationalStateTE.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/nationalStateTE.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/nationalStateTE.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,217 @@
+/*****************************************************************************
+
+ FileName: nationalStateTE.c
+
+ Contents: National ISDN State Engine for TE (User Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ This reference implementation uses a process per message,
+ meaning that each message must check call states. This
+ is easier for dialect maintenance as each message proc
+ can be replaced individually. A new TE variant only
+ need to copy the Q931CreateTE and replace those procs or
+ need to override.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "national.h"
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+ Function: nationalCreateTE
+
+ Description: Will create the National TE as a Dialect in the stack. The first
+ bulk set up the message handlers, the second bulk the IE
+ encoders/coders, and the last bulk set up the state table.
+
+ Parameters: i Dialect index
+*****************************************************************************/
+void nationalCreateTE(L3UCHAR i)
+{
+ Q931SetMesProc(Q931mes_ALERTING, i, Q931ProcAlertingTE, Q931Umes_Alerting, Q931Pmes_Alerting);
+ Q931SetMesProc(Q931mes_CALL_PROCEEDING, i, Q931ProcCallProceedingTE, Q931Umes_CallProceeding, Q931Pmes_CallProceeding);
+ Q931SetMesProc(Q931mes_CONNECT, i, DMSProc0x07TE, DMSUmes_0x07, DMSPmes_0x07);
+ Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i, DMSProc0x0fTE, DMSUmes_0x0f, DMSPmes_0x0f);
+ Q931SetMesProc(Q931mes_PROGRESS, i, Q931ProcProgressTE, Q931Umes_Progress, Q931Pmes_Progress);
+ Q931SetMesProc(Q931mes_SETUP, i, Q931ProcSetupTE, nationalUmes_Setup, nationalPmes_Setup);
+ Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE, i, Q931ProcSetupAckTE, Q931Umes_SetupAck, Q931Pmes_SetupAck);
+ Q931SetMesProc(Q931mes_RESUME, i, Q931ProcResumeTE, Q931Umes_Resume, Q931Pmes_Resume);
+ Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE, i, Q931ProcResumeAckTE, Q931Umes_ResumeAck, Q931Pmes_ResumeAck);
+ Q931SetMesProc(Q931mes_RESUME_REJECT, i, Q931ProcResumeRejectTE, Q931Umes_ResumeReject, Q931Pmes_ResumeReject);
+ Q931SetMesProc(Q931mes_SUSPEND, i, Q931ProcSuspendTE, Q931Umes_Suspend, Q931Pmes_Suspend);
+ Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE, i, Q931ProcSuspendAckTE, Q931Umes_SuspendAck, Q931Pmes_SuspendAck);
+ Q931SetMesProc(Q931mes_SUSPEND_REJECT, i, Q931ProcSuspendRejectTE, Q931Umes_SuspendReject, Q931Pmes_SuspendReject);
+ Q931SetMesProc(Q931mes_USER_INFORMATION, i, Q931ProcUserInformationTE, Q931Umes_UserInformation, Q931Pmes_UserInformation);
+ Q931SetMesProc(Q931mes_DISCONNECT, i, Q931ProcDisconnectTE, Q931Umes_Disconnect, Q931Pmes_Disconnect);
+ Q931SetMesProc(Q931mes_RELEASE, i, Q931ProcReleaseTE, Q931Umes_Release, Q931Pmes_Release);
+ Q931SetMesProc(Q931mes_RELEASE_COMPLETE, i, Q931ProcReleaseCompleteTE, Q931Umes_ReleaseComplete, Q931Pmes_ReleaseComplete);
+ Q931SetMesProc(Q931mes_RESTART, i, Q931ProcRestartTE, Q931Umes_Restart, Q931Pmes_Restart);
+ Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE, i, Q931ProcRestartAckTE, Q931Umes_RestartAck, Q931Pmes_RestartAck);
+ Q931SetMesProc(Q931mes_CONGESTION_CONTROL, i, Q931ProcCongestionControlTE, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+ Q931SetMesProc(Q931mes_INFORMATION, i, Q931ProcInformationTE, Q931Umes_Information, Q931Pmes_Information);
+ Q931SetMesProc(Q931mes_NOTIFY, i, Q931ProcNotifyTE, Q931Umes_Notify, Q931Pmes_Notify);
+ Q931SetMesProc(Q931mes_STATUS, i, Q931ProcStatusTE, Q931Umes_Status, Q931Pmes_Status);
+ Q931SetMesProc(Q931mes_STATUS_ENQUIRY, i, Q931ProcStatusEnquiryTE, Q931Umes_StatusEnquiry, Q931Pmes_StatusEnquiry);
+ Q931SetMesProc(Q931mes_SEGMENT, i, Q931ProcSegmentTE, Q931Umes_Segment, Q931Pmes_Segment);
+
+ Q931SetMesProc(Q932mes_FACILITY, i, Q932ProcFacilityTE, Q932Umes_Facility, Q932Pmes_Facility);
+ Q931SetMesProc(Q932mes_HOLD, i, Q932ProcHoldTE, Q932Umes_Hold, Q932Pmes_Hold);
+ Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE, i, Q932ProcHoldAckTE, Q932Umes_HoldAck, Q932Pmes_HoldAck);
+ Q931SetMesProc(Q932mes_HOLD_REJECT, i, Q932ProcHoldRejectTE, Q932Umes_HoldReject, Q932Pmes_HoldReject);
+ Q931SetMesProc(Q932mes_REGISTER, i, Q932ProcRegisterTE, Q932Umes_Register, Q932Pmes_Register);
+ Q931SetMesProc(Q932mes_RETRIEVE, i, Q932ProcRetrieveTE, Q932Umes_Retrieve, Q932Pmes_Retrieve);
+ Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckTE, Q932Umes_RetrieveAck, Q932Pmes_RetrieveAck);
+ Q931SetMesProc(Q932mes_RETRIEVE_REJECT, i, Q932ProcRetrieveRejectTE, Q932Umes_RetrieveReject, Q932Pmes_RetrieveReject);
+
+ /* Set up the IE encoder/decoder handle table.*/
+ Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE, i, Q931Pie_Segment, Q931Uie_Segment);
+ Q931SetIEProc(Q931ie_BEARER_CAPABILITY, i, Q931Pie_BearerCap, Q931Uie_BearerCap);
+ Q931SetIEProc(Q931ie_CAUSE, i, Q931Pie_Cause, Q931Uie_Cause);
+ Q931SetIEProc(Q931ie_CALL_IDENTITY, i, Q931Pie_CallID, Q931Uie_CallID);
+ Q931SetIEProc(Q931ie_CALL_STATE, i, Q931Pie_CallState, Q931Uie_CallState);
+ Q931SetIEProc(Q931ie_CHANGE_STATUS, i, Q931Pie_ChangeStatus, Q931Uie_ChangeStatus);
+ Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION, i, Q931Pie_ChanID, Q931Uie_ChanID);
+ Q931SetIEProc(Q931ie_PROGRESS_INDICATOR, i, Q931Pie_ProgInd, Q931Uie_ProgInd);
+ Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES, i, Q931Pie_NetFac, Q931Uie_NetFac);
+ Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR, i, Q931Pie_NotifInd, Q931Uie_NotifInd);
+ Q931SetIEProc(Q931ie_DISPLAY, i, Q931Pie_Display, Q931Uie_Display);
+ Q931SetIEProc(Q931ie_DATETIME, i, Q931Pie_DateTime, Q931Uie_DateTime);
+ Q931SetIEProc(Q931ie_KEYPAD_FACILITY, i, Q931Pie_KeypadFac, Q931Uie_KeypadFac);
+ Q931SetIEProc(Q931ie_SIGNAL, i, Q931Pie_Signal, Q931Uie_Signal);
+ Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER, i, Q931Pie_CallingNum, Q931Uie_CallingNum);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS, i, Q931Pie_CallingSub, Q931Uie_CallingSub);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER, i, Q931Pie_CalledNum, Q931Uie_CalledNum);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS, i, Q931Pie_CalledSub, Q931Uie_CalledSub);
+ Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_RESTART_INDICATOR, i, Q931Pie_RestartInd, Q931Uie_RestartInd);
+ Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY, i, Q931Pie_LLComp, Q931Uie_LLComp);
+ Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY, i, Q931Pie_HLComp, Q931Uie_HLComp);
+ Q931SetIEProc(Q931ie_USER_USER, i, Q931Pie_UserUser, Q931Uie_UserUser);
+ Q931SetIEProc(Q931ie_GENERIC_DIGITS, i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+ Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_FACILITY, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_REDIRECTING_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+
+ /* The following define a state machine. The point is that the Message
+ * procs can when search this to find out if the message/state
+ * combination is legale. If not, the proc for unexpected message apply.
+ */
+
+ /* State 0 Idle */
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RESUME, 2);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP, 2);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_STATUS, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE_COMPLETE, 4);
+
+ /* State 1 Call Initiating */
+ Q931AddStateEntry(i, Q931_U1, Q931mes_DISCONNECT, 2);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_SETUP_ACKNOWLEDGE, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_RELEASE_COMPLETE, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_CALL_PROCEEDING, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_CONNECT, 4);
+
+ /* State 2 Overlap Sending */
+ Q931AddStateEntry(i, Q931_U2, Q931mes_INFORMATION, 2);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_CALL_PROCEEDING, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_PROGRESS, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_CONNECT, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_RELEASE, 2);
+
+ /* State 3 Outgoing Call Proceeding */
+ Q931AddStateEntry(i, Q931_U3, Q931mes_PROGRESS, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_CONNECT, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_RELEASE, 2);
+
+ /* State 4 Call Delivered */
+ Q931AddStateEntry(i, Q931_U4, Q931mes_CONNECT, 4);
+
+ /* State 6 Call Precent */
+ Q931AddStateEntry(i, Q931_U6, Q931mes_INFORMATION, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_ALERTING, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_CALL_PROCEEDING, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_CONNECT, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE_COMPLETE, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_DISCONNECT, 4);
+
+ /* State 7 Call Received */
+ Q931AddStateEntry(i, Q931_U7, Q931mes_CONNECT, 2);
+
+ /* State 8 Connect request */
+ Q931AddStateEntry(i, Q931_U8, Q931mes_CONNECT_ACKNOWLEDGE, 4);
+
+ /* State 9 Incoming Call Proceeding */
+ Q931AddStateEntry(i, Q931_U9, Q931mes_CONNECT, 2);
+ Q931AddStateEntry(i, Q931_U9, Q931mes_ALERTING, 2);
+ Q931AddStateEntry(i, Q931_U9, Q931mes_PROGRESS, 2);
+
+ /* State 10 Active */
+ Q931AddStateEntry(i, Q931_U10, Q931mes_SUSPEND, 2);
+ Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY, 4);
+ Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY, 2);
+
+ /* State 11 Disconnect Request */
+ Q931AddStateEntry(i, Q931_U11, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U11, Q931mes_DISCONNECT, 4);
+ Q931AddStateEntry(i, Q931_U11, Q931mes_NOTIFY, 4);
+
+ /* State 12 Disconnect Ind */
+ Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 2);
+
+ /* State 15 Suspend Request */
+ Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_ACKNOWLEDGE, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_REJECT, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_DISCONNECT, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_RELEASE, 4);
+
+/* TODO
+ Q931AddStateEntry(i, Q931_U17,
+ Q931AddStateEntry(i, Q931_U19,
+ Q931AddStateEntry(i, Q931_U25,
+*/
+}
Added: freeswitch/trunk/libs/freetdm/src/isdn/nationalmes.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/isdn/nationalmes.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/nationalmes.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,269 @@
+/*****************************************************************************
+
+ FileName: nationalmes.c
+
+ Contents: Pack/Unpack functions. These functions will unpack a National ISDN
+ message from the bit packed original format into structs
+ that contains variables sized by the user. It will also pack
+ the struct back into a Q.931 message as required.
+
+ See national.h for description.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ 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 Case Labs, Ltd 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.
+
+*****************************************************************************/
+
+#include "national.h"
+
+/*****************************************************************************
+
+ Function: nationalUmes_Setup
+
+*****************************************************************************/
+L3INT nationalUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT ir = 0;
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+ L3UCHAR last_codeset = 0, codeset = 0;
+ L3UCHAR shift_lock = 1;
+
+ while (IOff < Size) {
+ if (!shift_lock) {
+ codeset = last_codeset;
+ }
+
+ if ((IBuf[IOff] & 0xF0) == Q931ie_SHIFT ) {
+ shift_lock = (IBuf[IOff] & 0x08);
+ if (shift_lock) {
+ last_codeset = codeset;
+ }
+ codeset = ((IBuf[IOff] & 0x07));
+ IOff++;
+ }
+
+ if (codeset == 0) {
+ switch (IBuf[IOff]) {
+ case Q931ie_SENDING_COMPLETE:
+ case Q931ie_BEARER_CAPABILITY:
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_NETWORK_SPECIFIC_FACILITIES:
+ case Q931ie_DISPLAY:
+ case Q931ie_DATETIME:
+ case Q931ie_KEYPAD_FACILITY:
+ case Q931ie_SIGNAL:
+ case Q931ie_CALLING_PARTY_NUMBER:
+ case Q931ie_CALLING_PARTY_SUBADDRESS:
+ case Q931ie_CALLED_PARTY_NUMBER:
+ case Q931ie_CALLED_PARTY_SUBADDRESS:
+ case Q931ie_TRANSIT_NETWORK_SELECTION:
+ case Q931ie_LOW_LAYER_COMPATIBILITY:
+ case Q931ie_HIGH_LAYER_COMPATIBILITY:
+ case Q931ie_FACILITY:
+ case Q931ie_REDIRECTING_NUMBER:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ case Q931ie_REPEAT_INDICATOR:
+ if (ir < 2) {
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ ir++;
+ } else {
+ return Q931E_ILLEGAL_IE;
+ }
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ } else if (codeset == 6) {
+ switch (IBuf[IOff]) {
+ case Q931ie_GENERIC_DIGITS:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+
+ } else {
+ return Q931E_ILLEGAL_IE;
+ }
+ }
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: nationalPmes_Setup
+
+ Decription: Pack a Q931mes_Generic into a real Q.931 message. The user will
+ set up a SETUP message and issue this to the stack where it
+ is processed by Q931ProcSetup that processes and validates
+ it before it actually sends it out. This function is called
+ to compute the real Q.931 message.
+
+ Parameters: IBuf[IN] Ptr to un-packed struct
+ ISize[IN] Size of input buffer (unpacked message).
+ OBuf[OUT] Ptr to packed 'octet' wise message.
+ OSize[OUT] Size of packed message.
+
+ Called By: Q931ProcSetup
+
+*****************************************************************************/
+L3INT nationalPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3INT rc = Q931E_NO_ERROR;
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Sending Complete */
+ if (Q931IsIEPresent(pMes->SendComplete)) {
+ OBuf[Octet++] = (L3UCHAR)(pMes->SendComplete & 0x00ff);
+ }
+
+ /* Repeat Indicator */
+ if (Q931IsIEPresent(pMes->RepeatInd)) {
+ OBuf[Octet++] = (L3UCHAR)(pMes->RepeatInd & 0x00ff);
+ }
+
+ /* Bearer capability */
+ if (Q931IsIEPresent(pMes->BearerCap)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+ else {
+ rc = Q931E_BEARERCAP;
+ }
+
+ /* Channel Identification */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Network spesific facilities */
+ if (Q931IsIEPresent(pMes->NetFac)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_NETWORK_SPECIFIC_FACILITIES](pTrunk, Q931GetIEPtr(pMes->NetFac,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Date/Time */
+ if (Q931IsIEPresent(pMes->DateTime)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Keypad Facility */
+ if (Q931IsIEPresent(pMes->KeypadFac)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Calling Party Number */
+ if (Q931IsIEPresent(pMes->CallingNum)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CallingNum,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Calling Party Subaddress */
+ if (Q931IsIEPresent(pMes->CallingSub)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CallingSub,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Called Party number */
+ if (Q931IsIEPresent(pMes->CalledNum)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Called party subaddress */
+ if (Q931IsIEPresent(pMes->CalledSub)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CalledSub,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Transit network selection */
+ if (Q931IsIEPresent(pMes->TransNetSel)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_TRANSIT_NETWORK_SELECTION](pTrunk, Q931GetIEPtr(pMes->TransNetSel,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Repeat Indicator */
+ if (Q931IsIEPresent(pMes->LLRepeatInd)) {
+ rc = Q931E_UNKNOWN_IE;/* TODO */
+ }
+
+ /* Low Layer Compatibility */
+ if (Q931IsIEPresent(pMes->LLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* High Layer Compatibility */
+ if (Q931IsIEPresent(pMes->HLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
Added: freeswitch/trunk/libs/freetdm/src/libteletone_detect.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/libteletone_detect.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/libteletone_detect.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,427 @@
+/*
+ * libteletone
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Much less efficient expansion interface was added to allow for the detection of
+ * a single arbitrary tone combination which may also exceed 2 simultaneous tones.
+ * (controlled by compile time constant TELETONE_MAX_TONES)
+ *
+ * Copyright (C) 2006 Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * libteletone_detect.c Tone Detection Code
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ *
+ *********************************************************************************
+ *
+ * Derived from tone_detect.c - General telephony tone detection, and specific
+ * detection of DTMF.
+ *
+ * Copyright (C) 2001 Steve Underwood <steveu@coppice.org>
+ *
+ * Despite my general liking of the GPL, I place this code in the
+ * public domain for the benefit of all mankind - even the slimy
+ * ones who might try to proprietize my work and use it to my
+ * detriment.
+ *
+ *
+ *
+ */
+
+#include <libteletone_detect.h>
+
+#ifndef _MSC_VER
+#include <stdint.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <fcntl.h>
+
+
+static teletone_detection_descriptor_t dtmf_detect_row[GRID_FACTOR];
+static teletone_detection_descriptor_t dtmf_detect_col[GRID_FACTOR];
+static teletone_detection_descriptor_t dtmf_detect_row_2nd[GRID_FACTOR];
+static teletone_detection_descriptor_t dtmf_detect_col_2nd[GRID_FACTOR];
+
+static float dtmf_row[] = {697.0f, 770.0f, 852.0f, 941.0f};
+static float dtmf_col[] = {1209.0f, 1336.0f, 1477.0f, 1633.0f};
+
+static char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
+
+static void goertzel_init(teletone_goertzel_state_t *goertzel_state, teletone_detection_descriptor_t *tdesc) {
+ goertzel_state->v2 = goertzel_state->v3 = 0.0;
+ goertzel_state->fac = tdesc->fac;
+}
+
+TELETONE_API(void) teletone_goertzel_update(teletone_goertzel_state_t *goertzel_state,
+ int16_t sample_buffer[],
+ int samples)
+{
+ int i;
+ float v1;
+
+ for (i = 0; i < samples; i++) {
+ v1 = goertzel_state->v2;
+ goertzel_state->v2 = goertzel_state->v3;
+ goertzel_state->v3 = (float)(goertzel_state->fac*goertzel_state->v2 - v1 + sample_buffer[i]);
+ }
+}
+#ifdef _MSC_VER
+#pragma warning(disable:4244)
+#endif
+
+#define teletone_goertzel_result(gs) (double)(((gs)->v3 * (gs)->v3 + (gs)->v2 * (gs)->v2 - (gs)->v2 * (gs)->v3 * (gs)->fac))
+
+TELETONE_API(void) teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate)
+{
+ int i;
+ float theta;
+
+ dtmf_detect_state->hit1 = dtmf_detect_state->hit2 = 0;
+
+ for (i = 0; i < GRID_FACTOR; i++) {
+ theta = (float)(M_TWO_PI*(dtmf_row[i]/(float)sample_rate));
+ dtmf_detect_row[i].fac = (float)(2.0*cos(theta));
+
+ theta = (float)(M_TWO_PI*(dtmf_col[i]/(float)sample_rate));
+ dtmf_detect_col[i].fac = (float)(2.0*cos(theta));
+
+ theta = (float)(M_TWO_PI*(dtmf_row[i]*2.0/(float)sample_rate));
+ dtmf_detect_row_2nd[i].fac = (float)(2.0*cos(theta));
+
+ theta = (float)(M_TWO_PI*(dtmf_col[i]*2.0/(float)sample_rate));
+ dtmf_detect_col_2nd[i].fac = (float)(2.0*cos(theta));
+
+ goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]);
+ goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]);
+ goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]);
+ goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]);
+
+ dtmf_detect_state->energy = 0.0;
+ }
+ dtmf_detect_state->current_sample = 0;
+ dtmf_detect_state->detected_digits = 0;
+ dtmf_detect_state->lost_digits = 0;
+ dtmf_detect_state->digits[0] = '\0';
+ dtmf_detect_state->mhit = 0;
+}
+
+TELETONE_API(void) teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map)
+{
+ float theta = 0;
+ int x = 0;
+
+ if (!mt->sample_rate) {
+ mt->sample_rate = 8000;
+ }
+
+ if (!mt->min_samples) {
+ mt->min_samples = 102;
+ }
+
+ mt->min_samples *= (mt->sample_rate / 8000);
+
+ if (!mt->positive_factor) {
+ mt->positive_factor = 2;
+ }
+
+ if(!mt->negative_factor) {
+ mt->negative_factor = 10;
+ }
+
+ if (!mt->hit_factor) {
+ mt->hit_factor = 2;
+ }
+
+ for(x = 0; x < TELETONE_MAX_TONES; x++) {
+ if ((int) map->freqs[x] == 0) {
+ break;
+ }
+ mt->tone_count++;
+ theta = (float)(M_TWO_PI*(map->freqs[x]/(float)mt->sample_rate));
+ mt->tdd[x].fac = (float)(2.0 * cos(theta));
+ goertzel_init (&mt->gs[x], &mt->tdd[x]);
+ goertzel_init (&mt->gs2[x], &mt->tdd[x]);
+ }
+
+}
+
+TELETONE_API(int) teletone_multi_tone_detect (teletone_multi_tone_t *mt,
+ int16_t sample_buffer[],
+ int samples)
+{
+ int sample, limit = 0, j, x = 0;
+ float v1, famp;
+ float eng_sum = 0, eng_all[TELETONE_MAX_TONES] = {0.0};
+ int gtest = 0, see_hit = 0;
+
+ for (sample = 0; sample >= 0 && sample < samples; sample = limit) {
+ mt->total_samples++;
+
+ if ((samples - sample) >= (mt->min_samples - mt->current_sample)) {
+ limit = sample + (mt->min_samples - mt->current_sample);
+ } else {
+ limit = samples;
+ }
+ if (limit < 0 || limit > samples) {
+ limit = samples;
+ }
+
+ for (j = sample; j < limit; j++) {
+ famp = sample_buffer[j];
+
+ mt->energy += famp*famp;
+
+ for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
+ v1 = mt->gs[x].v2;
+ mt->gs[x].v2 = mt->gs[x].v3;
+ mt->gs[x].v3 = (float)(mt->gs[x].fac * mt->gs[x].v2 - v1 + famp);
+
+ v1 = mt->gs2[x].v2;
+ mt->gs2[x].v2 = mt->gs2[x].v3;
+ mt->gs2[x].v3 = (float)(mt->gs2[x].fac*mt->gs2[x].v2 - v1 + famp);
+ }
+ }
+
+ mt->current_sample += (limit - sample);
+ if (mt->current_sample < mt->min_samples) {
+ continue;
+ }
+
+ eng_sum = 0;
+ for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
+ eng_all[x] = (float)(teletone_goertzel_result (&mt->gs[x]));
+ eng_sum += eng_all[x];
+ }
+
+ gtest = 0;
+ for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
+ gtest += teletone_goertzel_result (&mt->gs2[x]) < eng_all[x] ? 1 : 0;
+ }
+
+ if ((gtest >= 2 || gtest == mt->tone_count) && eng_sum > 42.0 * mt->energy) {
+ if(mt->negatives) {
+ mt->negatives--;
+ }
+ mt->positives++;
+
+ if(mt->positives >= mt->positive_factor) {
+ mt->hits++;
+ }
+ if (mt->hits >= mt->hit_factor) {
+ see_hit++;
+ mt->positives = mt->negatives = mt->hits = 0;
+ }
+ } else {
+ mt->negatives++;
+ if(mt->positives) {
+ mt->positives--;
+ }
+ if(mt->negatives > mt->negative_factor) {
+ mt->positives = mt->hits = 0;
+ }
+ }
+
+ /* Reinitialise the detector for the next block */
+ for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
+ goertzel_init (&mt->gs[x], &mt->tdd[x]);
+ goertzel_init (&mt->gs2[x], &mt->tdd[x]);
+ }
+
+ mt->energy = 0.0;
+ mt->current_sample = 0;
+ }
+
+ return see_hit;
+}
+
+
+TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
+ int16_t sample_buffer[],
+ int samples)
+{
+ float row_energy[GRID_FACTOR];
+ float col_energy[GRID_FACTOR];
+ float famp;
+ float v1;
+ int i;
+ int j;
+ int sample;
+ int best_row;
+ int best_col;
+ char hit;
+ int limit;
+
+ hit = 0;
+ for (sample = 0; sample < samples; sample = limit) {
+ /* BLOCK_LEN is optimised to meet the DTMF specs. */
+ if ((samples - sample) >= (BLOCK_LEN - dtmf_detect_state->current_sample)) {
+ limit = sample + (BLOCK_LEN - dtmf_detect_state->current_sample);
+ } else {
+ limit = samples;
+ }
+
+ for (j = sample; j < limit; j++) {
+ int x = 0;
+ famp = sample_buffer[j];
+
+ dtmf_detect_state->energy += famp*famp;
+
+ for(x = 0; x < GRID_FACTOR; x++) {
+ v1 = dtmf_detect_state->row_out[x].v2;
+ dtmf_detect_state->row_out[x].v2 = dtmf_detect_state->row_out[x].v3;
+ dtmf_detect_state->row_out[x].v3 = (float)(dtmf_detect_state->row_out[x].fac*dtmf_detect_state->row_out[x].v2 - v1 + famp);
+
+ v1 = dtmf_detect_state->col_out[x].v2;
+ dtmf_detect_state->col_out[x].v2 = dtmf_detect_state->col_out[x].v3;
+ dtmf_detect_state->col_out[x].v3 = (float)(dtmf_detect_state->col_out[x].fac*dtmf_detect_state->col_out[x].v2 - v1 + famp);
+
+ v1 = dtmf_detect_state->col_out2nd[x].v2;
+ dtmf_detect_state->col_out2nd[x].v2 = dtmf_detect_state->col_out2nd[x].v3;
+ dtmf_detect_state->col_out2nd[x].v3 = (float)(dtmf_detect_state->col_out2nd[x].fac*dtmf_detect_state->col_out2nd[x].v2 - v1 + famp);
+
+ v1 = dtmf_detect_state->row_out2nd[x].v2;
+ dtmf_detect_state->row_out2nd[x].v2 = dtmf_detect_state->row_out2nd[x].v3;
+ dtmf_detect_state->row_out2nd[x].v3 = (float)(dtmf_detect_state->row_out2nd[x].fac*dtmf_detect_state->row_out2nd[x].v2 - v1 + famp);
+ }
+
+ }
+
+ dtmf_detect_state->current_sample += (limit - sample);
+ if (dtmf_detect_state->current_sample < BLOCK_LEN) {
+ continue;
+ }
+ /* We are at the end of a DTMF detection block */
+ /* Find the peak row and the peak column */
+ row_energy[0] = teletone_goertzel_result (&dtmf_detect_state->row_out[0]);
+ col_energy[0] = teletone_goertzel_result (&dtmf_detect_state->col_out[0]);
+
+ for (best_row = best_col = 0, i = 1; i < GRID_FACTOR; i++) {
+ row_energy[i] = teletone_goertzel_result (&dtmf_detect_state->row_out[i]);
+ if (row_energy[i] > row_energy[best_row]) {
+ best_row = i;
+ }
+ col_energy[i] = teletone_goertzel_result (&dtmf_detect_state->col_out[i]);
+ if (col_energy[i] > col_energy[best_col]) {
+ best_col = i;
+ }
+ }
+ hit = 0;
+ /* Basic signal level test and the twist test */
+ if (row_energy[best_row] >= DTMF_THRESHOLD &&
+ col_energy[best_col] >= DTMF_THRESHOLD &&
+ col_energy[best_col] < row_energy[best_row]*DTMF_REVERSE_TWIST &&
+ col_energy[best_col]*DTMF_NORMAL_TWIST > row_energy[best_row]) {
+ /* Relative peak test */
+ for (i = 0; i < GRID_FACTOR; i++) {
+ if ((i != best_col && col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) ||
+ (i != best_row && row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) {
+ break;
+ }
+ }
+ /* ... and second harmonic test */
+ if (i >= GRID_FACTOR && (row_energy[best_row] + col_energy[best_col]) > 42.0*dtmf_detect_state->energy &&
+ teletone_goertzel_result (&dtmf_detect_state->col_out2nd[best_col])*DTMF_2ND_HARMONIC_COL < col_energy[best_col] &&
+ teletone_goertzel_result (&dtmf_detect_state->row_out2nd[best_row])*DTMF_2ND_HARMONIC_ROW < row_energy[best_row]) {
+ hit = dtmf_positions[(best_row << 2) + best_col];
+ /* Look for two successive similar results */
+ /* The logic in the next test is:
+ We need two successive identical clean detects, with
+ something different preceeding it. This can work with
+ back to back differing digits. More importantly, it
+ can work with nasty phones that give a very wobbly start
+ to a digit. */
+ if (hit == dtmf_detect_state->hit3 && dtmf_detect_state->hit3 != dtmf_detect_state->hit2) {
+ dtmf_detect_state->mhit = hit;
+ dtmf_detect_state->digit_hits[(best_row << 2) + best_col]++;
+ dtmf_detect_state->detected_digits++;
+ if (dtmf_detect_state->current_digits < TELETONE_MAX_DTMF_DIGITS) {
+ dtmf_detect_state->digits[dtmf_detect_state->current_digits++] = hit;
+ dtmf_detect_state->digits[dtmf_detect_state->current_digits] = '\0';
+ }
+ else
+ {
+ dtmf_detect_state->lost_digits++;
+ }
+ }
+ }
+ }
+ dtmf_detect_state->hit1 = dtmf_detect_state->hit2;
+ dtmf_detect_state->hit2 = dtmf_detect_state->hit3;
+ dtmf_detect_state->hit3 = hit;
+ /* Reinitialise the detector for the next block */
+ for (i = 0; i < GRID_FACTOR; i++) {
+ goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]);
+ goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]);
+ goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]);
+ goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]);
+ }
+ dtmf_detect_state->energy = 0.0;
+ dtmf_detect_state->current_sample = 0;
+ }
+ if ((!dtmf_detect_state->mhit) || (dtmf_detect_state->mhit != hit)) {
+ dtmf_detect_state->mhit = 0;
+ return(0);
+ }
+ return (hit);
+}
+
+
+TELETONE_API(int) teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state,
+ char *buf,
+ int max)
+{
+ teletone_assert(dtmf_detect_state->current_digits <= TELETONE_MAX_DTMF_DIGITS);
+
+ if (max > dtmf_detect_state->current_digits) {
+ max = dtmf_detect_state->current_digits;
+ }
+ if (max > 0) {
+ memcpy (buf, dtmf_detect_state->digits, max);
+ memmove (dtmf_detect_state->digits, dtmf_detect_state->digits + max, dtmf_detect_state->current_digits - max);
+ dtmf_detect_state->current_digits -= max;
+ }
+ buf[max] = '\0';
+ return max;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/libteletone_generate.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/libteletone_generate.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/libteletone_generate.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,452 @@
+/*
+ * libteletone_generate.c -- Tone Generator
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#include <libteletone.h>
+#include "freetdm.h"
+
+#define SMAX 32767
+#define SMIN -32768
+#define normalize_to_16bit(n) if (n > SMAX) n = SMAX; else if (n < SMIN) n = SMIN;
+
+#ifdef _MSC_VER
+#pragma warning(disable:4706)
+#endif
+
+TELETONE_API_DATA int16_t TELETONE_SINES[SINE_TABLE_MAX] = {
+ 0x00c9, 0x025b, 0x03ed, 0x057f, 0x0711, 0x08a2, 0x0a33, 0x0bc4,
+ 0x0d54, 0x0ee4, 0x1073, 0x1201, 0x138f, 0x151c, 0x16a8, 0x1833,
+ 0x19be, 0x1b47, 0x1cd0, 0x1e57, 0x1fdd, 0x2162, 0x22e5, 0x2467,
+ 0x25e8, 0x2768, 0x28e5, 0x2a62, 0x2bdc, 0x2d55, 0x2ecc, 0x3042,
+ 0x31b5, 0x3327, 0x3497, 0x3604, 0x3770, 0x38d9, 0x3a40, 0x3ba5,
+ 0x3d08, 0x3e68, 0x3fc6, 0x4121, 0x427a, 0x43d1, 0x4524, 0x4675,
+ 0x47c4, 0x490f, 0x4a58, 0x4b9e, 0x4ce1, 0x4e21, 0x4f5e, 0x5098,
+ 0x51cf, 0x5303, 0x5433, 0x5560, 0x568a, 0x57b1, 0x58d4, 0x59f4,
+ 0x5b10, 0x5c29, 0x5d3e, 0x5e50, 0x5f5e, 0x6068, 0x616f, 0x6272,
+ 0x6371, 0x646c, 0x6564, 0x6657, 0x6747, 0x6832, 0x691a, 0x69fd,
+ 0x6add, 0x6bb8, 0x6c8f, 0x6d62, 0x6e31, 0x6efb, 0x6fc2, 0x7083,
+ 0x7141, 0x71fa, 0x72af, 0x735f, 0x740b, 0x74b3, 0x7556, 0x75f4,
+ 0x768e, 0x7723, 0x77b4, 0x7840, 0x78c8, 0x794a, 0x79c9, 0x7a42,
+ 0x7ab7, 0x7b27, 0x7b92, 0x7bf9, 0x7c5a, 0x7cb7, 0x7d0f, 0x7d63,
+ 0x7db1, 0x7dfb, 0x7e3f, 0x7e7f, 0x7eba, 0x7ef0, 0x7f22, 0x7f4e,
+ 0x7f75, 0x7f98, 0x7fb5, 0x7fce, 0x7fe2, 0x7ff1, 0x7ffa, 0x7fff
+};
+
+
+TELETONE_API(int) teletone_set_tone(teletone_generation_session_t *ts, int index, ...)
+{
+ va_list ap;
+ int i = 0;
+ teletone_process_t x = 0;
+
+ va_start(ap, index);
+ while (i < TELETONE_MAX_TONES && (x = va_arg(ap, teletone_process_t))) {
+ ts->TONES[index].freqs[i++] = x;
+ }
+ va_end(ap);
+
+ return (i > TELETONE_MAX_TONES) ? -1 : 0;
+
+}
+
+TELETONE_API(int) teletone_set_map(teletone_tone_map_t *map, ...)
+{
+ va_list ap;
+ int i = 0;
+ teletone_process_t x = 0;
+
+ va_start(ap, map);
+ while (i < TELETONE_MAX_TONES && (x = va_arg(ap, teletone_process_t))) {
+ map->freqs[i++] = x;
+ }
+ va_end(ap);
+
+ return (i > TELETONE_MAX_TONES) ? -1 : 0;
+
+}
+
+TELETONE_API(int) teletone_init_session(teletone_generation_session_t *ts, int buflen, tone_handler handler, void *user_data)
+{
+ memset(ts, 0, sizeof(*ts));
+ ts->rate = 8000;
+ ts->channels = 1;
+ ts->duration = 2000;
+ ts->wait = 500;
+ ts->tmp_duration = -1;
+ ts->tmp_wait = -1;
+ ts->handler = handler;
+ ts->user_data = user_data;
+ ts->volume = -7;
+ ts->decay_step = 0;
+ ts->decay_factor = 1;
+ if (buflen) {
+ if ((ts->buffer = ftdm_calloc(buflen, sizeof(teletone_audio_t))) == 0) {
+ return -1;
+ }
+ ts->datalen = buflen;
+ } else {
+ ts->dynamic = 1024;
+ }
+ /* Add Standard DTMF Tones */
+ teletone_set_tone(ts, '1', 697.0, 1209.0, 0.0);
+ teletone_set_tone(ts, '2', 697.0, 1336.0, 0.0);
+ teletone_set_tone(ts, '3', 697.0, 1477.0, 0.0);
+ teletone_set_tone(ts, 'A', 697.0, 1633.0, 0.0);
+ teletone_set_tone(ts, '4', 770.0, 1209.0, 0.0);
+ teletone_set_tone(ts, '5', 770.0, 1336.0, 0.0);
+ teletone_set_tone(ts, '6', 770.0, 1477.0, 0.0);
+ teletone_set_tone(ts, 'B', 770.0, 1633.0, 0.0);
+ teletone_set_tone(ts, '7', 859.0, 1209.0, 0.0);
+ teletone_set_tone(ts, '8', 859.0, 1336.0, 0.0);
+ teletone_set_tone(ts, '9', 859.0, 1477.0, 0.0);
+ teletone_set_tone(ts, 'C', 859.0, 1633.0, 0.0);
+ teletone_set_tone(ts, '*', 941.0, 1209.0, 0.0);
+ teletone_set_tone(ts, '0', 941.0, 1336.0, 0.0);
+ teletone_set_tone(ts, '#', 941.0, 1477.0, 0.0);
+ teletone_set_tone(ts, 'D', 941.0, 1633.0, 0.0);
+
+ return 0;
+}
+
+TELETONE_API(int) teletone_destroy_session(teletone_generation_session_t *ts)
+{
+ if (ts->buffer) {
+ ftdm_safe_free(ts->buffer);
+ ts->buffer = NULL;
+ ts->samples = 0;
+ }
+ return 0;
+}
+
+static int ensure_buffer(teletone_generation_session_t *ts, int need)
+{
+ need += ts->samples;
+ need *= sizeof(teletone_audio_t);
+ need *= ts->channels;
+
+ if (need > ts->datalen) {
+ teletone_audio_t *tmp;
+ ts->datalen = need + ts->dynamic;
+ tmp = realloc(ts->buffer, ts->datalen);
+ if (!tmp) {
+ return -1;
+ }
+ ts->buffer = tmp;
+ }
+
+ return 0;
+}
+
+TELETONE_API(int) teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+ /*teletone_process_t period = (1.0 / ts->rate) / ts->channels;*/
+ int i, c;
+ int freqlen = 0;
+ teletone_dds_state_t tones[TELETONE_MAX_TONES+1];
+ //int decay = 0;
+ int duration;
+ int wait = 0;
+ int32_t sample;
+ int32_t dc = 0;
+ float vol = ts->volume;
+ ts->samples = 0;
+ memset(tones, 0, sizeof(tones[0]) * TELETONE_MAX_TONES);
+ duration = (ts->tmp_duration > -1) ? ts->tmp_duration : ts->duration;
+ wait = (ts->tmp_wait > -1) ? ts->tmp_wait : ts->wait;
+
+ if (map->freqs[0] > 0) {
+ for (freqlen = 0; freqlen < TELETONE_MAX_TONES && map->freqs[freqlen]; freqlen++) {
+ teletone_dds_state_set_tone(&tones[freqlen], map->freqs[freqlen], ts->rate, 0);
+ teletone_dds_state_set_tx_level(&tones[freqlen], vol);
+ }
+
+ if (ts->channels > 1) {
+ duration *= ts->channels;
+ }
+
+ if (ts->dynamic) {
+ if (ensure_buffer(ts, duration)) {
+ return -1;
+ }
+ }
+
+ for (ts->samples = 0; ts->samples < ts->datalen && ts->samples < duration; ts->samples++) {
+ if (ts->decay_direction && ++dc >= ts->decay_step) {
+ float nvol = vol + ts->decay_direction * ts->decay_factor;
+ int j;
+
+ if (nvol <= TELETONE_VOL_DB_MAX && nvol >= TELETONE_VOL_DB_MIN) {
+ vol = nvol;
+ for (j = 0; j < TELETONE_MAX_TONES && map->freqs[j]; j++) {
+ teletone_dds_state_set_tx_level(&tones[j], vol);
+ }
+ dc = 0;
+ }
+ }
+
+ sample = 128;
+
+ for (i = 0; i < freqlen; i++) {
+ int32_t s = teletone_dds_state_modulate_sample(&tones[i], 0);
+ sample += s;
+ }
+ sample /= freqlen;
+ ts->buffer[ts->samples] = (teletone_audio_t)sample;
+
+ for (c = 1; c < ts->channels; c++) {
+ ts->buffer[ts->samples+1] = ts->buffer[ts->samples];
+ ts->samples++;
+ }
+
+ }
+ }
+ if (ts->dynamic) {
+ if (ensure_buffer(ts, wait)) {
+ return -1;
+ }
+ }
+ for (c = 0; c < ts->channels; c++) {
+ for (i = 0; i < wait && ts->samples < ts->datalen; i++) {
+ ts->buffer[ts->samples++] = 0;
+ }
+ }
+
+ if (ts->debug && ts->debug_stream) {
+ if (map->freqs[0] <= 0) {
+ fprintf(ts->debug_stream, "wait %d (%dms)\n", wait, wait / (ts->rate / 1000));
+ } else {
+ fprintf(ts->debug_stream, "Generate: (");
+
+ for (i = 0; i < TELETONE_MAX_TONES && map->freqs[i]; i++) {
+ fprintf(ts->debug_stream, "%s%0.2f", i == 0 ? "" : "+",map->freqs[i]);
+ }
+
+ fprintf(ts->debug_stream,
+ ") [volume %0.2fdB; samples %d(%dms) x %d channel%s; wait %d(%dms); decay_factor %0.2fdB; decay_step %d(%dms); wrote %d bytes]\n",
+ ts->volume,
+ duration,
+ duration / (ts->rate / 1000),
+ ts->channels,
+ ts->channels == 1 ? "" : "s",
+ wait,
+ wait / (ts->rate / 1000),
+ ts->decay_factor,
+ ts->decay_step,
+ ts->decay_step / (ts->rate / 1000),
+ ts->samples * 2);
+ }
+ }
+ return ts->samples;
+}
+
+TELETONE_API(int) teletone_run(teletone_generation_session_t *ts, const char *cmd)
+{
+ char *data = NULL, *cur = NULL, *end = NULL;
+ int var = 0, LOOPING = 0;
+
+ if (!cmd) {
+ return -1;
+ }
+
+ do {
+ if (!(data = ftdm_strdup(cmd))) {
+ return -1;
+ }
+
+ cur = data;
+
+ while (*cur) {
+ var = 0;
+ if (*cur == ' ' || *cur == '\r' || *cur == '\n') {
+ cur++;
+ continue;
+ }
+
+ if ((end = strchr(cur, ';')) != 0) {
+ *end++ = '\0';
+ }
+
+ if (*(cur + 1) == '=') {
+ var = 1;
+ switch(*cur) {
+ case 'c':
+ ts->channels = atoi(cur + 2);
+ break;
+ case 'r':
+ ts->rate = atoi(cur + 2);
+ break;
+ case 'd':
+ ts->duration = atoi(cur + 2) * (ts->rate / 1000);
+ break;
+ case 'v':
+ {
+ float vol = (float)atof(cur + 2);
+ if (vol <= TELETONE_VOL_DB_MAX && vol >= TELETONE_VOL_DB_MIN) {
+ ts->volume = vol;
+ }
+ }
+ break;
+ case '>':
+ ts->decay_step = atoi(cur + 2) * (ts->rate / 1000);
+ ts->decay_direction = -1;
+ break;
+ case '<':
+ ts->decay_step = atoi(cur + 2) * (ts->rate / 1000);
+ ts->decay_direction = 1;
+ break;
+ case '+':
+ ts->decay_factor = (float)atof(cur + 2);
+ break;
+ case 'w':
+ ts->wait = atoi(cur + 2) * (ts->rate / 1000);
+ break;
+ case 'l':
+ ts->loops = atoi(cur + 2);
+ break;
+ case 'L':
+ if (!LOOPING) {
+ ts->LOOPS = atoi(cur + 2);
+ }
+ LOOPING++;
+ break;
+ }
+ } else {
+ while (*cur) {
+ char *p = NULL, *e = NULL;
+ teletone_tone_map_t mymap, *mapp = NULL;
+
+ if (*cur == ' ' || *cur == '\r' || *cur == '\n') {
+ cur++;
+ continue;
+ }
+
+ ts->tmp_duration = -1;
+ ts->tmp_wait = -1;
+
+ memset(&mymap, 0, sizeof(mymap));
+
+ if (*(cur + 1) == '(') {
+ p = cur + 2;
+ if (*cur) {
+ char *next;
+ int i = 0;
+ if ((e = strchr(p, ')')) != 0) {
+ *e++ = '\0';
+ }
+ do {
+ if ((next = strchr(p, ',')) != 0) {
+ *next++ = '\0';
+ }
+ if (i == 0) {
+ ts->tmp_duration = atoi(p) * (ts->rate / 1000);
+ i++;
+ } else if (i == 1) {
+ ts->tmp_wait = atoi(p) * (ts->rate / 1000);
+ i++;
+ } else {
+ mymap.freqs[i++ - 2] = atof(p);
+ }
+ p = next;
+
+ } while (next && (i-2) < TELETONE_MAX_TONES);
+ if (i > 2 && *cur == '%') {
+ mapp = &mymap;
+ } else if ((i != 2 || *cur == '%')) {
+ if (ts->debug && ts->debug_stream) {
+ fprintf(ts->debug_stream, "Syntax Error!\n");
+ }
+ goto bottom;
+ }
+ }
+ }
+
+ if (*cur && !mapp) {
+ if (*cur > 0 && *cur < TELETONE_TONE_RANGE) {
+ mapp = &ts->TONES[(int)*cur];
+ } else if (ts->debug && ts->debug_stream) {
+ fprintf(ts->debug_stream, "Map [%c] Out Of Range!\n", *cur);
+ }
+ }
+
+ if (mapp) {
+ if (mapp->freqs[0]) {
+ if (ts->handler) {
+ do {
+ ts->handler(ts, mapp);
+ if (ts->loops > 0) {
+ ts->loops--;
+ }
+ } while (ts->loops);
+ }
+ } else if (ts->debug && ts->debug_stream) {
+ fprintf(ts->debug_stream, "Ignoring Empty Map [%c]!\n", *cur);
+ }
+ }
+
+ if (e) {
+ cur = e;
+ } else {
+ cur++;
+ }
+ }
+ }
+
+ if (end) {
+ cur = end;
+ } else if (*cur){
+ cur++;
+ }
+ }
+ bottom:
+ ftdm_safe_free(data);
+ data = NULL;
+ if (ts->LOOPS > 0) {
+ ts->LOOPS--;
+ }
+
+ } while (ts->LOOPS);
+
+ return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/m3ua/mstm3ua.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/m3ua/mstm3ua.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/m3ua/mstm3ua.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,62 @@
+/* WARNING WORK IN PROGRESS
+ * mstm3ua.c
+ * mstss7d port
+ *
+ * Created by Shane Burrell on 2/2/08.
+ * Copyright 2008 Shane Burrell. 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.
+ */
+
+#include "mstm3ua.h"
+
+
+
+
+
+int build_m3ua_hdr(unsigned char len,unsigned char *bytemsg)
+
+{
+
+ *bytemsg++ = M_VERSION_REL1; // 1 Verison
+ //bytemsg[1] = 0x00; // 2 RESERVED
+ //bytemsg[2] = M_CLASS_XFER; // 3 Msg Class
+ //SS7 BOX Kludge
+ *bytemsg++ = 0x01; // 2 RESERVED
+ *bytemsg++ = 0x00; // 2 RESERVED
+
+ *bytemsg++ = M_TYPE_DATA ; // 4 Msg Type
+
+ *bytemsg++ = len; // 5 Msg LENGTH 81 32bit field
+ *bytemsg++ = 0x00; // 6
+ *bytemsg++ = 0x00; // 7
+ *bytemsg++ = 0x00; // 8
+ return(0);
+
+};
\ No newline at end of file
Added: freeswitch/trunk/libs/freetdm/src/m3ua/mstm3ua.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/m3ua/mstm3ua.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/m3ua/mstm3ua.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,96 @@
+/*
+ * mstm3ua.h
+ * mstss7d
+ *
+ * Created by Shane Burrell on 3/2/08.
+ * Copyright 2008 Shane Burrell. 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.
+ */
+typedef unsigned long m3ua_ulong;
+typedef unsigned short m3ua_ushort;
+typedef unsigned char m3ua_uchar;
+
+typedef unsigned char u8;
+typedef unsigned short u16; /* Note: multi-byte values are little-endian */
+typedef unsigned long u32;
+
+
+
+
+#define M_TAG_NETWORK_APPEARANCE 1
+#define M_TAG_PROTOCOL_DATA 3
+#define M_TAG_INFO_STRING 4
+#define M_TAG_AFFECTED_DPC 5
+#define M_TAG_ROUTING_CONTEXT 6
+#define M_TAG_DIAGNOSTIC_INFORMATION 7
+#define M_TAG_HEARTBEAT_DATA 8
+#define M_TAG_UNAVAILABILITY_CAUSE 9
+#define M_TAG_REASON 10
+#define M_TAG_TRAFFIC_MODE_TYPE 11
+#define M_TAG_ERROR_CODE 12
+#define M_TAG_STATUS_TYPE 13
+#define M_TAG_CONGESTED_INDICATIONS 14
+
+#define M_VERSION_REL1 1
+
+#define M_CLASS_MGMT 0x00
+#define M_CLASS_XFER 0x01
+#define M_CLASS_SSNM 0x02
+#define M_CLASS_ASPSM 0x03
+#define M_CLASS_ASPTM 0x04
+#define M_CLASS_RKM 0x09
+
+#define M_TYPE_ERR (0|M_CLASS_MGMT
+
+#define M_TYPE_NTFY (1|M_CLASS_XFER)
+#define M_TYPE_DATA (1|M_CLASS_XFER)
+
+#define M_TYPE_DUNA (1|M_CLASS_SSNM)
+#define M_TYPE_DAVA (2|M_CLASS_SSNM)
+#define M_TYPE_DUAD (3|M_CLASS_SSNM)
+#define M_TYPE_SCON (4|M_CLASS_SSNM)
+#define M_TYPE_DUPU (5|M_CLASS_SSNM)
+
+#define M_TYPE_UP (1|M_CLASS_ASPSM)
+#define M_TYPE_DOWN (2|M_CLASS_ASPSM)
+#define M_TYPE_BEAT (3|M_CLASS_ASPSM)
+#define M_TYPE_UP_ACK (4|M_CLASS_ASPSM)
+#define M_TYPE_DOWN_ACK (5|M_CLASS_ASPSM)
+#define M_TYPE_BEAT_ACK (6|M_CLASS_ASPSM)
+
+#define M_TYPE_ACTIVE (1|M_CLASS_ASPTM)
+#define M_TYPE_INACTIVE (2|M_CLASS_ASPTM)
+#define M_TYPE_ACTIVE_ACK (3|M_CLASS_ASPTM)
+#define M_TYPE_INACTIVE_ACK (4|M_CLASS_ASPTM)
+
+#define M_CLASS_MASK 0xff00
+#define M_TYPE_MASK 0x00ff
+
Added: freeswitch/trunk/libs/freetdm/src/m3ua_client.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/m3ua_client.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/m3ua_client.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,333 @@
+/*
+ * m3ua_client.c
+ * freetdm
+ *
+ * Created by Shane Burrell on 4/3/08.
+ * Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ *
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ * 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.
+ */
+
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include "freetdm.h"
+#include <m3ua_client.h>
+
+
+#ifndef HAVE_GETHOSTBYNAME_R
+extern int gethostbyname_r (const char *__name,
+ struct hostent *__result_buf,
+ char *__buf, size_t __buflen,
+ struct hostent **__result,
+ int *__h_errnop);
+#endif
+
+struct m3uac_map {
+ uint32_t event_id;
+ const char *name;
+};
+
+static struct m3uac_map m3uac_table[] = {
+ {M3UA_EVENT_CALL_START, "CALL_START"},
+ {M3UA_EVENT_CALL_START_ACK, "CALL_START_ACK"},
+ {M3UA_EVENT_CALL_START_NACK, "CALL_START_NACK"},
+ {M3UA_EVENT_CALL_START_NACK_ACK, "CALL_START_NACK_ACK"},
+ {M3UA_EVENT_CALL_ANSWERED, "CALL_ANSWERED"},
+ {M3UA_EVENT_CALL_STOPPED, "CALL_STOPPED"},
+ {M3UA_EVENT_CALL_STOPPED_ACK, "CALL_STOPPED_ACK"},
+ {M3UA_EVENT_SYSTEM_RESTART, "SYSTEM_RESTART"},
+ {M3UA_EVENT_SYSTEM_RESTART_ACK, "SYSTEM_RESTART_ACK"},
+ {M3UA_EVENT_HEARTBEAT, "HEARTBEAT"},
+ {M3UA_EVENT_INSERT_CHECK_LOOP, "LOOP START"},
+ {M3UA_EVENT_REMOVE_CHECK_LOOP, "LOOP STOP"}
+};
+
+
+
+static int create_conn_socket(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
+{
+ int rc;
+ struct hostent *result, *local_result;
+ char buf[512], local_buf[512];
+ int err = 0;
+
+ memset(&mcon->remote_hp, 0, sizeof(mcon->remote_hp));
+ memset(&mcon->local_hp, 0, sizeof(mcon->local_hp));
+ mcon->socket = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+ ftdm_log(FTDM_LOG_DEBUG, "Creating L=%s:%d R=%s:%d\n",
+ local_ip,local_port,ip,port);
+
+ if (mcon->socket >= 0) {
+ int flag;
+
+ flag = 1;
+ gethostbyname_r(ip, &mcon->remote_hp, buf, sizeof(buf), &result, &err);
+ gethostbyname_r(local_ip, &mcon->local_hp, local_buf, sizeof(local_buf), &local_result, &err);
+ if (result && local_result) {
+ mcon->remote_addr.sin_family = mcon->remote_hp.h_addrtype;
+ memcpy((char *) &mcon->remote_addr.sin_addr.s_addr, mcon->remote_hp.h_addr_list[0], mcon->remote_hp.h_length);
+ mcon->remote_addr.sin_port = htons(port);
+
+ mcon->local_addr.sin_family = mcon->local_hp.h_addrtype;
+ memcpy((char *) &mcon->local_addr.sin_addr.s_addr, mcon->local_hp.h_addr_list[0], mcon->local_hp.h_length);
+ mcon->local_addr.sin_port = htons(local_port);
+
+
+ setsockopt(mcon->socket, IPPROTO_SCTP, SCTP_NODELAY, (char *)&flag, sizeof(int));
+
+ rc=listen(mcon->socket,100);
+ if (rc) {
+ close(mcon->socket);
+ mcon->socket = -1;
+
+ }
+ }
+ }
+
+ ftdm_mutex_create(&mcon->mutex);
+
+ return mcon->socket;
+}
+
+int m3uac_connection_close(m3uac_connection_t *mcon)
+{
+ if (mcon->socket > -1) {
+ close(mcon->socket);
+ }
+
+ ftdm_mutex_lock(mcon->mutex);
+ ftdm_mutex_unlock(mcon->mutex);
+ ftdm_mutex_destroy(&mcon->mutex);
+ memset(mcon, 0, sizeof(*mcon));
+ mcon->socket = -1;
+
+ return 0;
+}
+
+int m3uac_connection_open(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
+{
+ create_conn_socket(mcon, local_ip, local_port, ip, port);
+ return mcon->socket;
+}
+
+
+int m3uac_exec_command(m3uac_connection_t *mcon, int span, int chan, int id, int cmd, int cause)
+{
+ m3uac_event_t oevent;
+ int retry = 5;
+
+ m3uac_event_init(&oevent, cmd, chan, span);
+ oevent.release_cause = cause;
+
+ if (cmd == SIGBOOST_EVENT_SYSTEM_RESTART) {
+ mcon->rxseq_reset = 1;
+ mcon->txseq = 0;
+ mcon->rxseq = 0;
+ mcon->txwindow = 0;
+ }
+
+ if (id >= 0) {
+ oevent.call_setup_id = id;
+ }
+
+ while (m3uac_connection_write(mcon, &oevent) <= 0) {
+ if (--retry <= 0) {
+ ftdm_log(FTDM_LOG_CRIT, "Failed to tx on M3UA socket: %s\n", strerror(errno));
+ return -1;
+ } else {
+ ftdm_log(FTDM_LOG_WARNING, "Failed to tx on M3UA socket: %s :retry %i\n", strerror(errno), retry);
+ ftdm_sleep(1);
+ }
+ }
+
+ return 0;
+}
+
+
+
+m3uac_event_t *m3uac_connection_read(m3uac_connection_t *mcon, int iteration)
+{
+ unsigned int fromlen = sizeof(struct sockaddr_in);
+ int bytes = 0;
+
+ bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT,
+ (struct sockaddr *) &mcon->local_addr, &fromlen);
+
+ if (bytes == sizeof(mcon->event) || bytes == (sizeof(mcon->event)-sizeof(uint32_t))) {
+
+ if (mcon->rxseq_reset) {
+ if (mcon->event.event_id == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
+ ftdm_log(FTDM_LOG_DEBUG, "Rx sync ok\n");
+ mcon->rxseq = mcon->event.fseqno;
+ return &mcon->event;
+ }
+ errno=EAGAIN;
+ ftdm_log(FTDM_LOG_DEBUG, "Waiting for rx sync...\n");
+ return NULL;
+ }
+
+ mcon->txwindow = mcon->txseq - mcon->event.bseqno;
+ mcon->rxseq++;
+
+ if (mcon->rxseq != mcon->event.fseqno) {
+ ftdm_log(FTDM_LOG_CRIT, "Invalid Sequence Number Expect=%i Rx=%i\n", mcon->rxseq, mcon->event.fseqno);
+ return NULL;
+ }
+
+ return &mcon->event;
+ } else {
+ if (iteration == 0) {
+ ftdm_log(FTDM_LOG_CRIT, "Invalid Event length from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+m3uac_event_t *m3uac_connection_readp(m3uac_connection_t *mcon, int iteration)
+{
+ unsigned int fromlen = sizeof(struct sockaddr_in);
+ int bytes = 0;
+
+ bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT, (struct sockaddr *) &mcon->local_addr, &fromlen);
+
+ if (bytes == sizeof(mcon->event) || bytes == (sizeof(mcon->event)-sizeof(uint32_t))) {
+ return &mcon->event;
+ } else {
+ if (iteration == 0) {
+ ftdm_log(FTDM_LOG_CRIT, "Critical Error: PQ Invalid Event lenght from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+
+int m3uac_connection_write(m3uac_connection_t *mcon, ss7bc_event_t *event)
+{
+ int err;
+
+ if (!event || mcon->socket < 0 || !mcon->mutex) {
+ ftdm_log(FTDM_LOG_DEBUG, "Critical Error: No Event Device\n");
+ return -EINVAL;
+ }
+
+ if (event->span > 16 || event->chan > 31) {
+ ftdm_log(FTDM_LOG_CRIT, "Critical Error: TX Cmd=%s Invalid Span=%i Chan=%i\n", m3uac_event_id_name(event->event_id), event->span,event->chan);
+ return -1;
+ }
+
+ gettimeofday(&event->tv,NULL);
+
+ ftdm_mutex_lock(mcon->mutex);
+ event->fseqno = mcon->txseq++;
+ event->bseqno = mcon->rxseq;
+ err = sendto(mcon->socket, event, sizeof(m3uac_event_t), 0, (struct sockaddr *) &mcon->remote_addr, sizeof(mcon->remote_addr));
+ ftdm_mutex_unlock(mcon->mutex);
+
+ if (err != sizeof(m3uac_event_t)) {
+ err = -1;
+ }
+
+ ftdm_log(FTDM_LOG_DEBUG, "TX EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n",
+ m3uac_event_id_name(event->event_id),
+ event->event_id,
+ event->span+1,
+ event->chan+1,
+ event->release_cause,
+ event->call_setup_id,
+ event->fseqno,
+ (event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
+ (event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A")
+ );
+
+ return err;
+}
+
+void m3uac_call_init(m3uac_event_t *event, const char *calling, const char *called, int setup_id)
+{
+ memset(event, 0, sizeof(m3uac_event_t));
+ event->event_id = M3UA_EVENT_CALL_START;
+
+ if (calling) {
+ strncpy((char*)event->calling_number_digits, calling, sizeof(event->calling_number_digits)-1);
+ event->calling_number_digits_count = strlen(calling);
+ }
+
+ if (called) {
+ strncpy((char*)event->called_number_digits, called, sizeof(event->called_number_digits)-1);
+ event->called_number_digits_count = strlen(called);
+ }
+
+ event->call_setup_id = setup_id;
+
+}
+
+void m3uac_event_init(m3uac_event_t *event, m3uac_event_id_t event_id, int chan, int span)
+{
+ memset(event, 0, sizeof(ss7bc_event_t));
+ event->event_id = event_id;
+ event->chan = chan;
+ event->span = span;
+}
+
+const char *m3uac_event_id_name(uint32_t event_id)
+{
+ unsigned int x;
+ const char *ret = NULL;
+
+ for (x = 0 ; x < sizeof(m3uac_table)/sizeof(struct m3uac_map); x++) {
+ if (m3uac_table[x].event_id == event_id) {
+ ret = m3uac_table[x].name;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
+
Added: freeswitch/trunk/libs/freetdm/src/m3ua_client.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/m3ua_client.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/m3ua_client.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,164 @@
+/*
+ * m3ua_client.h
+ * freetdm
+ *
+ * Created by Shane Burrell on 4/3/08.
+ * Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ *
+ * 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.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+// Fix this for portability
+#include <sctp.h>
+//#include <netinet/sctp.h>
+#include <arpa/inet.h>
+#include <stdarg.h>
+#include <netdb.h>
+//#include <sigboost.h>
+#include <sys/time.h>
+
+#define MAX_DIALED_DIGITS 31
+#define MAX_CALLING_NAME 31
+
+/* Next two defines are used to create the range of values for call_setup_id
+ * in the t_sigboost structure.
+ * 0..((CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN) - 1) */
+#define CORE_MAX_SPANS 200
+#define CORE_MAX_CHAN_PER_SPAN 30
+#define MAX_PENDING_CALLS CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN
+/* 0..(MAX_PENDING_CALLS-1) is range of call_setup_id below */
+#define SIZE_RDNIS 80
+
+//#undef MSGWINDOW
+#define MSGWINDOW
+
+
+typedef struct
+{
+ uint32_t event_id;
+ uint32_t fseqno;
+#ifdef MSGWINDOW
+ uint32_t bseqno;
+#endif
+ uint16_t call_setup_id;
+ uint32_t trunk_group;
+ uint32_t span;
+ uint32_t chan;
+ uint8_t called_number_digits_count;
+ char called_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
+ uint8_t calling_number_digits_count; /* it's an array */
+ char calling_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
+ uint8_t release_cause;
+ struct timeval tv;
+ /* ref. Q.931 Table 4-11 and Q.951 Section 3 */
+ uint8_t calling_number_screening_ind;
+ uint8_t calling_number_presentation;
+ char redirection_string [SIZE_RDNIS]; /* it's a null terminated string */
+
+} t_m3ua;
+
+typedef t_m3ua m3uac_event_t;
+typedef uint32_t m3uac_event_id_t;
+
+
+typedef struct m3uac_ip_cfg
+{
+ char local_ip[25];
+ int local_port;
+ char remote_ip[25];
+ int remote_port;
+}m3uac_ip_cfg_t;
+
+struct m3uac_connection {
+ ftdm_socket_t socket;
+ struct sockaddr_in local_addr;
+ struct sockaddr_in remote_addr;
+ m3uac_event_t event;
+ struct hostent remote_hp;
+ struct hostent local_hp;
+ unsigned int flags;
+ ftdm_mutex_t *mutex;
+ FILE *log;
+ unsigned int txseq;
+ unsigned int rxseq;
+ unsigned int txwindow;
+ unsigned int rxseq_reset;
+ m3uac_ip_cfg_t cfg;
+ uint32_t hb_elapsed;
+ int up;
+};
+
+typedef enum {
+ MSU_FLAG_EVENT = (1 << 0)
+} m3uac_flag_t;
+
+typedef struct m3uac_connection m3uac_connection_t;
+
+static inline void sctp_no_nagle(int socket)
+{
+ //int flag = 1;
+ //setsockopt(socket, IPPROTO_SCTP, SCTP_NODELAY, (char *) &flag, sizeof(int));
+}
+
+int m3uac_connection_close(m3uac_connection_t *mcon);
+int m3uac_connection_open(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port);
+m3uac_event_t *m3uac_connection_read(m3uac_connection_t *mcon, int iteration);
+m3uac_event_t *m3uac_connection_readp(m3uac_connection_t *mcon, int iteration);
+int m3uac_connection_write(m3uac_connection_t *mcon, m3uac_event_t *event);
+void m3uac_event_init(m3uac_event_t *event, m3uac_event_id_t event_id, int chan, int span);
+void m3uac_call_init(m3uac_event_t *event, const char *calling, const char *called, int setup_id);
+const char *m3uac_event_id_name(uint32_t event_id);
+int m3uac_exec_command(m3uac_connection_t *mcon, int span, int chan, int id, int cmd, int cause);
+
+
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/priserver.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/priserver.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/priserver.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,328 @@
+/*****************************************************************************
+ * priserver.c Refactoring of pritest.c
+ *
+ * Author(s): Anthony Minessale II <anthmct@yahoo.com>
+ * Nenad Corbic <ncorbic@sangoma.com>
+ *
+ * Copyright: (c) 2005 Anthony Minessale II
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ * ============================================================================
+ */
+
+#include "freetdm.h"
+#include <sangoma_pri.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+typedef struct {
+ int pid;
+ q931_call call;
+ void *pri;
+ int ready;
+}call_info_t;
+
+
+#define SANGOMA_MAX_CHAN_PER_SPAN 32
+
+static call_info_t pidmap[SANGOMA_MAX_CHAN_PER_SPAN];
+
+FIO_EVENT_CB_FUNCTION(my_ftdm_event_handler)
+{
+ if (event->e_type = FTDM_EVENT_DTMF) {
+ char *dtmf = event->data;
+ printf("DTMF %s\n", dtmf);
+ }
+}
+
+/* Stupid runtime process to play a file to a b channel*/
+#define BYTES 320
+#define MAX_BYTES 1000
+
+static int ready = 1;
+
+static void handle_SIGINT(int sig)
+{
+ if (sig) {
+ ready = 0;
+ }
+
+ return;
+}
+
+static void launch_channel(struct sangoma_pri *spri, int channo)
+{
+ pid_t pid;
+ int fd = 0, file = 0, inlen = 0, outlen = 0;
+ unsigned char inframe[MAX_BYTES], outframe[MAX_BYTES];
+ fd_set readfds;
+ int mtu_mru=BYTES / 2;
+ int err;
+ ftdm_channel_t *chan;
+ ftdm_codec_t codec = FTDM_CODEC_SLIN;
+ unsigned ms = 20;
+ unsigned int lead = 50;
+ int ifd = -1;
+ ftdm_tone_type_t tt = FTDM_TONE_DTMF;
+ char dtmf[] = "1234567890";
+ int loops = 0;
+
+ pid = fork();
+
+ if (pid) {
+ pidmap[channo-1].pid = pid;
+ printf("-- Launching process %d to handle channel %d\n", pid, channo);
+ return;
+ }
+
+ signal(SIGINT, handle_SIGINT);
+
+ //ifd = open("/nfs/sounds/ptest.raw", O_WRONLY|O_CREAT|O_TRUNC, 777);
+
+ memset(inframe, 0, MAX_BYTES);
+ memset(outframe, 0, MAX_BYTES);
+
+ if (ftdm_channel_open(spri->span, channo, &chan) != FTDM_SUCCESS) {
+ printf("DEBUG cant open fd!\n");
+ }
+
+
+
+#if 1
+ if (ftdm_channel_command(chan, FTDM_COMMAND_SET_CODEC, &codec) != FTDM_SUCCESS) {
+ printf("Critical Error: Failed to set driver codec!\n");
+ ftdm_channel_close(&chan);
+ exit(-1);
+ }
+#endif
+
+#if 1
+ if (ftdm_channel_command(chan, FTDM_COMMAND_ENABLE_DTMF_DETECT, &tt) != FTDM_SUCCESS) {
+ printf("Critical Error: Failed to set dtmf detect!\n");
+ ftdm_channel_close(&chan);
+ exit(-1);
+ }
+ ftdm_channel_set_event_callback(chan, my_ftdm_event_handler);
+#endif
+
+
+ if (ftdm_channel_command(chan, FTDM_COMMAND_SET_INTERVAL, &ms) != FTDM_SUCCESS) {
+ printf("Critical Error: Failed to set codec interval!\n");
+ ftdm_channel_close(&chan);
+ exit(-1);
+ }
+
+ file = open("sound.raw", O_RDONLY);
+ if (file < 0){
+ printf("Critical Error: Failed to open sound file!\n");
+ ftdm_channel_close(&chan);
+ exit(-1);
+ }
+
+
+ while(ready) {
+ ftdm_wait_flag_t flags = FTDM_READ;
+ ftdm_size_t len;
+ loops++;
+
+ if (lead) {
+ lead--;
+ }
+
+ if (!lead && loops == 300) {
+#if 1
+ if (ftdm_channel_command(chan, FTDM_COMMAND_SEND_DTMF, dtmf) != FTDM_SUCCESS) {
+ printf("Critical Error: Failed to send dtmf\n");
+ ftdm_channel_close(&chan);
+ exit(-1);
+ }
+#endif
+
+ }
+
+ if (ftdm_channel_wait(chan, &flags, 2000) != FTDM_SUCCESS) {
+ printf("wait FAIL! [%s]\n", chan->last_error);
+ break;
+ }
+
+ if (flags & FTDM_READ) {
+ len = MAX_BYTES;
+ if (ftdm_channel_read(chan, inframe, &len) == FTDM_SUCCESS) {
+ //printf("READ: %d\n", len);
+ //write(ifd, inframe, len);
+ if(!lead && (outlen = read(file, outframe, len)) <= 0) {
+ break;
+ }
+
+ } else {
+ printf("READ FAIL! %d [%s]\n", len, chan->last_error);
+ break;
+ }
+ if (lead) {
+ continue;
+ }
+ ftdm_channel_write(chan, outframe, sizeof(outframe), &len);
+ } else {
+ printf("BREAK");
+ break;
+ }
+ }
+
+ printf("loop done\n");
+
+ //sangoma_get_full_cfg(fd, &tdm_api);
+ close(file);
+ //close(ifd);
+
+ pri_hangup(spri->pri, channo, 16);
+ if (ftdm_channel_close(&chan) != FTDM_SUCCESS) {
+ printf("Critical Error: Failed to close channel [%s]\n", chan->last_error);
+ }
+
+ printf("Call Handler: Process Finished\n");
+ exit(0);
+}
+
+
+/* Event Handlers */
+
+static int on_info(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event)
+{
+ printf( "number is: %s\n", event->ring.callednum);
+ if(strlen(event->ring.callednum) > 3) {
+ printf( "final number is: %s\n", event->ring.callednum);
+ pri_answer(spri->pri, event->ring.call, 0, 1);
+ }
+ return 0;
+}
+
+static int on_hangup(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event)
+{
+ //pri_hangup(spri->pri, event->hangup.call, event->hangup.cause);
+ printf("-- Hanging up channel %d\n", event->hangup.channel);
+ if(pidmap[event->hangup.channel-1].pid) {
+ pri_hangup(spri->pri, event->hangup.call, 16);
+ pri_destroycall(spri->pri, event->hangup.call);
+ kill(pidmap[event->hangup.channel-1].pid, SIGINT);
+ pidmap[event->hangup.channel-1].pid = 0;
+ }
+ return 0;
+}
+
+static int on_ring(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event)
+{
+ printf("-- Ring on channel %d (from %s to %s), answering...\n", event->ring.channel, event->ring.callingnum, event->ring.callednum);
+ pri_answer(spri->pri, event->ring.call, event->ring.channel, 1);
+ memcpy(&pidmap[event->ring.channel-1].call, event->ring.call, sizeof(q931_call));
+ pidmap[event->ring.channel-1].pri=spri->pri;
+ pidmap[event->ring.channel-1].call = *event->ring.call;
+ launch_channel(spri, event->ring.channel);
+ return 0;
+}
+
+static int on_restart(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event)
+{
+ printf("-- Restarting channel %d\n", event->restart.channel);
+ return 0;
+}
+
+static int on_anything(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event)
+{
+ printf("%s: Caught Event %d (%s)\n", __FUNCTION__, event_type, sangoma_pri_event_str(event_type));
+ return 0;
+}
+
+/* Generic Reaper */
+static void chan_ended(int sig)
+{
+ int status;
+ int x;
+ struct rusage rusage;
+ pid_t pid;
+ pid = wait4(-1, &status, WNOHANG, &rusage);
+
+ printf("-- PID %d ended\n", pid);
+
+ for (x=0;x<SANGOMA_MAX_CHAN_PER_SPAN;x++) {
+ if (pid == pidmap[x].pid) {
+ pidmap[x].pid = 0;
+ if (pidmap[x].pri){
+ int err=pri_hangup(pidmap[x].pri, &pidmap[x].call, 16);
+ //pri_destroycall(pidmap[x].pri, &pidmap[x].call);
+ printf("Hanging up on PID %i Err=%i\n",pid,err);
+ }
+
+ pidmap[x].pri=NULL;
+ signal(SIGCHLD, chan_ended);
+ return;
+ }
+ }
+
+ if (pid > -1) {
+ fprintf(stderr, "--!! Unknown PID %d exited\n", pid);
+ signal(SIGCHLD, chan_ended);
+ return;
+ }
+}
+
+/* Our Program */
+int main(int argc, char *argv[])
+{
+ struct sangoma_pri spri;
+ int debug = 0;
+ if (argv[1]) {
+ debug = atoi(argv[1]);
+ }
+
+ ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
+ if (ftdm_global_init() != FTDM_SUCCESS) {
+ fprintf(stderr, "Error loading FreeTDM\n");
+ exit(-1);
+ }
+
+ printf("FreeTDM loaded\n");
+
+
+ debug = PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE;
+ printf("WTF %d\n", debug);
+
+ if (sangoma_init_pri(&spri,
+ 1, // span
+ 24, // dchan
+ SANGOMA_PRI_SWITCH_DMS100,
+ SANGOMA_PRI_CPE,
+ debug) < 0) {
+ return -1;
+ }
+ //spri.pri->debug = (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE);
+
+ //pri_set_debug(&spri.pri, (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE));
+
+ SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_ANY, on_anything);
+ SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_RING, on_ring);
+ SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_HANGUP, on_hangup);
+ SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_HANGUP_REQ, on_hangup);
+ SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_INFO_RECEIVED, on_info);
+ SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_RESTART, on_restart);
+
+ signal(SIGCHLD, chan_ended);
+ sangoma_run_pri(&spri);
+ return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/sangoma_pri.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/sangoma_pri.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/sangoma_pri.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,251 @@
+/*****************************************************************************
+ * sangoma_pri.c libpri Sangoma integration
+ *
+ * Author(s): Anthony Minessale II <anthmct@yahoo.com>
+ * Nenad Corbic <ncorbic@sangoma.com>
+ *
+ * Copyright: (c) 2005 Anthony Minessale II
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ * ============================================================================
+ */
+
+#include "freetdm.h"
+#include <sangoma_pri.h>
+#ifndef HAVE_GETTIMEOFDAY
+
+#ifdef WIN32
+#include <mmsystem.h>
+
+static __inline int gettimeofday(struct timeval *tp, void *nothing)
+{
+#ifdef WITHOUT_MM_LIB
+ SYSTEMTIME st;
+ time_t tt;
+ struct tm tmtm;
+ /* mktime converts local to UTC */
+ GetLocalTime (&st);
+ tmtm.tm_sec = st.wSecond;
+ tmtm.tm_min = st.wMinute;
+ tmtm.tm_hour = st.wHour;
+ tmtm.tm_mday = st.wDay;
+ tmtm.tm_mon = st.wMonth - 1;
+ tmtm.tm_year = st.wYear - 1900; tmtm.tm_isdst = -1;
+ tt = mktime (&tmtm);
+ tp->tv_sec = tt;
+ tp->tv_usec = st.wMilliseconds * 1000;
+#else
+ /**
+ ** The earlier time calculations using GetLocalTime
+ ** had a time resolution of 10ms.The timeGetTime, part
+ ** of multimedia apis offer a better time resolution
+ ** of 1ms.Need to link against winmm.lib for this
+ **/
+ unsigned long Ticks = 0;
+ unsigned long Sec =0;
+ unsigned long Usec = 0;
+ Ticks = timeGetTime();
+
+ Sec = Ticks/1000;
+ Usec = (Ticks - (Sec*1000))*1000;
+ tp->tv_sec = Sec;
+ tp->tv_usec = Usec;
+#endif /* WITHOUT_MM_LIB */
+ (void)nothing;
+ return 0;
+}
+#endif /* WIN32 */
+#endif /* HAVE_GETTIMEOFDAY */
+
+static struct sangoma_pri_event_list SANGOMA_PRI_EVENT_LIST[] = {
+ {0, SANGOMA_PRI_EVENT_ANY, "ANY"},
+ {1, SANGOMA_PRI_EVENT_DCHAN_UP, "DCHAN_UP"},
+ {2, SANGOMA_PRI_EVENT_DCHAN_DOWN, "DCHAN_DOWN"},
+ {3, SANGOMA_PRI_EVENT_RESTART, "RESTART"},
+ {4, SANGOMA_PRI_EVENT_CONFIG_ERR, "CONFIG_ERR"},
+ {5, SANGOMA_PRI_EVENT_RING, "RING"},
+ {6, SANGOMA_PRI_EVENT_HANGUP, "HANGUP"},
+ {7, SANGOMA_PRI_EVENT_RINGING, "RINGING"},
+ {8, SANGOMA_PRI_EVENT_ANSWER, "ANSWER"},
+ {9, SANGOMA_PRI_EVENT_HANGUP_ACK, "HANGUP_ACK"},
+ {10, SANGOMA_PRI_EVENT_RESTART_ACK, "RESTART_ACK"},
+ {11, SANGOMA_PRI_EVENT_FACNAME, "FACNAME"},
+ {12, SANGOMA_PRI_EVENT_INFO_RECEIVED, "INFO_RECEIVED"},
+ {13, SANGOMA_PRI_EVENT_PROCEEDING, "PROCEEDING"},
+ {14, SANGOMA_PRI_EVENT_SETUP_ACK, "SETUP_ACK"},
+ {15, SANGOMA_PRI_EVENT_HANGUP_REQ, "HANGUP_REQ"},
+ {16, SANGOMA_PRI_EVENT_NOTIFY, "NOTIFY"},
+ {17, SANGOMA_PRI_EVENT_PROGRESS, "PROGRESS"},
+ {18, SANGOMA_PRI_EVENT_KEYPAD_DIGIT, "KEYPAD_DIGIT"}
+};
+
+#define LINE "--------------------------------------------------------------------------------"
+
+char *sangoma_pri_event_str(sangoma_pri_event_t event_id)
+{
+ return SANGOMA_PRI_EVENT_LIST[event_id].name;
+}
+
+static int __pri_sangoma_read(struct pri *pri, void *buf, int buflen)
+{
+ struct sangoma_pri *spri = (struct sangoma_pri *) pri->userdata;
+ ftdm_size_t len = buflen;
+ int res;
+ char bb[4096] = "";
+
+
+ if (ftdm_channel_read(spri->zdchan, buf, &len) != FTDM_SUCCESS) {
+ printf("D-READ FAIL! [%s]\n", spri->zdchan->last_error);
+ return 0;
+ }
+ res = (int)len;
+ memset(&((unsigned char*)buf)[res],0,2);
+ res+=2;
+
+ //print_bits(buf, res-2, bb, sizeof(bb), 1, 0);
+ //ftdm_log(FTDM_LOG_DEBUG, "READ %d\n%s\n%s\n\n", res-2, LINE, bb);
+
+ return res;
+}
+
+static int __pri_sangoma_write(struct pri *pri, void *buf, int buflen)
+{
+ struct sangoma_pri *spri = (struct sangoma_pri *) pri->userdata;
+ int res;
+ ftdm_size_t len = buflen -2;
+ char bb[4096] = "";
+
+ if (ftdm_channel_write(spri->zdchan, buf, buflen, &len) != FTDM_SUCCESS) {
+ printf("D-WRITE FAIL! [%s]\n", spri->zdchan->last_error);
+ return 0;
+ }
+
+ //print_bits(buf, (int)buflen-2, bb, sizeof(bb), 1, 0);
+ //ftdm_log(FTDM_LOG_DEBUG, "WRITE %d\n%s\n%s\n\n", (int)buflen-2, LINE, bb);
+
+ return (int) buflen;
+}
+
+int sangoma_init_pri(struct sangoma_pri *spri, int span, int dchan, int swtype, int node, int debug)
+{
+ int ret = -1;
+ ftdm_socket_t dfd = 0;
+
+ memset(spri, 0, sizeof(struct sangoma_pri));
+
+ if (ftdm_channel_open(span, dchan, &spri->zdchan) != FTDM_SUCCESS) {
+ fprintf(stderr, "Unable to open DCHAN %d for span %d (%s)\n", dchan, span, strerror(errno));
+ } else {
+ if ((spri->pri = pri_new_cb(spri->zdchan->sockfd, node, swtype, __pri_sangoma_read, __pri_sangoma_write, spri))){
+ spri->span = span;
+ pri_set_debug(spri->pri, debug);
+ ret = 0;
+ } else {
+ fprintf(stderr, "Unable to create PRI\n");
+ }
+ }
+ return ret;
+}
+
+
+int sangoma_one_loop(struct sangoma_pri *spri)
+{
+ fd_set rfds, efds;
+ struct timeval now = {0,0}, *next;
+ pri_event *event;
+ int sel;
+
+ if (spri->on_loop) {
+ spri->on_loop(spri);
+ }
+
+ FD_ZERO(&rfds);
+ FD_ZERO(&efds);
+
+#ifdef _MSC_VER
+ //Windows macro for FD_SET includes a warning C4127: conditional expression is constant
+#pragma warning(push)
+#pragma warning(disable:4127)
+#endif
+
+ FD_SET(spri->pri->fd, &rfds);
+ FD_SET(spri->pri->fd, &efds);
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+ if ((next = pri_schedule_next(spri->pri))) {
+ gettimeofday(&now, NULL);
+ now.tv_sec = next->tv_sec - now.tv_sec;
+ now.tv_usec = next->tv_usec - now.tv_usec;
+ if (now.tv_usec < 0) {
+ now.tv_usec += 1000000;
+ now.tv_sec -= 1;
+ }
+ if (now.tv_sec < 0) {
+ now.tv_sec = 0;
+ now.tv_usec = 0;
+ }
+ }
+
+ sel = select(spri->pri->fd + 1, &rfds, NULL, &efds, next ? &now : NULL);
+ event = NULL;
+
+ if (!sel) {
+ event = pri_schedule_run(spri->pri);
+ } else if (sel > 0) {
+ event = pri_check_event(spri->pri);
+ }
+
+ if (event) {
+ event_handler handler;
+ /* 0 is catchall event handler */
+ if ((handler = spri->eventmap[event->e] ? spri->eventmap[event->e] : spri->eventmap[0] ? spri->eventmap[0] : NULL)) {
+ handler(spri, event->e, event);
+ } else {
+ fprintf(stderr,"No event handler found for event %d.\n", event->e);
+ }
+ }
+
+ return sel;
+}
+
+int sangoma_run_pri(struct sangoma_pri *spri)
+{
+ int ret = 0;
+
+ for (;;){
+ ret=sangoma_one_loop(spri);
+ if (ret < 0){
+
+#ifndef WIN32 //This needs to be adressed fror WIN32 still
+ if (errno == EINTR){
+ /* Igonore an interrupted system call */
+ continue;
+ }
+#endif
+ printf("Error = %i\n",ret);
+ perror("Sangoma Run Pri: ");
+ break;
+ }
+ }
+
+ return ret;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/freetdm/src/sangoma_pri.h (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/sangoma_pri.h (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/sangoma_pri.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,100 @@
+/*****************************************************************************
+ * libsangoma.c AFT T1/E1: HDLC API Code Library
+ *
+ * Author(s): Anthony Minessale II <anthmct@yahoo.com>
+ * Nenad Corbic <ncorbic@sangoma.com>
+ *
+ * Copyright: (c) 2005 Anthony Minessale II
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ * ============================================================================
+ */
+
+#ifndef _SANGOMA_PRI_H
+#define _SANGOMA_PRI_H
+#include <libpri.h>
+#include <pri_internal.h>
+
+
+#define SANGOMA_MAX_CHAN_PER_SPAN 32
+
+typedef enum {
+ SANGOMA_PRI_EVENT_ANY = 0,
+ SANGOMA_PRI_EVENT_DCHAN_UP = PRI_EVENT_DCHAN_UP,
+ SANGOMA_PRI_EVENT_DCHAN_DOWN = PRI_EVENT_DCHAN_DOWN,
+ SANGOMA_PRI_EVENT_RESTART = PRI_EVENT_RESTART,
+ SANGOMA_PRI_EVENT_CONFIG_ERR = PRI_EVENT_CONFIG_ERR,
+ SANGOMA_PRI_EVENT_RING = PRI_EVENT_RING,
+ SANGOMA_PRI_EVENT_HANGUP = PRI_EVENT_HANGUP,
+ SANGOMA_PRI_EVENT_RINGING = PRI_EVENT_RINGING,
+ SANGOMA_PRI_EVENT_ANSWER = PRI_EVENT_ANSWER,
+ SANGOMA_PRI_EVENT_HANGUP_ACK = PRI_EVENT_HANGUP_ACK,
+ SANGOMA_PRI_EVENT_RESTART_ACK = PRI_EVENT_RESTART_ACK,
+ SANGOMA_PRI_EVENT_FACNAME = PRI_EVENT_FACNAME,
+ SANGOMA_PRI_EVENT_INFO_RECEIVED = PRI_EVENT_INFO_RECEIVED,
+ SANGOMA_PRI_EVENT_PROCEEDING = PRI_EVENT_PROCEEDING,
+ SANGOMA_PRI_EVENT_SETUP_ACK = PRI_EVENT_SETUP_ACK,
+ SANGOMA_PRI_EVENT_HANGUP_REQ = PRI_EVENT_HANGUP_REQ,
+ SANGOMA_PRI_EVENT_NOTIFY = PRI_EVENT_NOTIFY,
+ SANGOMA_PRI_EVENT_PROGRESS = PRI_EVENT_PROGRESS,
+ SANGOMA_PRI_EVENT_KEYPAD_DIGIT = PRI_EVENT_KEYPAD_DIGIT
+} sangoma_pri_event_t;
+
+typedef enum {
+ SANGOMA_PRI_NETWORK = PRI_NETWORK,
+ SANGOMA_PRI_CPE = PRI_CPE
+} sangoma_pri_node_t;
+
+typedef enum {
+ SANGOMA_PRI_SWITCH_UNKNOWN = PRI_SWITCH_UNKNOWN,
+ SANGOMA_PRI_SWITCH_NI2 = PRI_SWITCH_NI2,
+ SANGOMA_PRI_SWITCH_DMS100 = PRI_SWITCH_DMS100,
+ SANGOMA_PRI_SWITCH_LUCENT5E = PRI_SWITCH_LUCENT5E,
+ SANGOMA_PRI_SWITCH_ATT4ESS = PRI_SWITCH_ATT4ESS,
+ SANGOMA_PRI_SWITCH_EUROISDN_E1 = PRI_SWITCH_EUROISDN_E1,
+ SANGOMA_PRI_SWITCH_EUROISDN_T1 = PRI_SWITCH_EUROISDN_T1,
+ SANGOMA_PRI_SWITCH_NI1 = PRI_SWITCH_NI1,
+ SANGOMA_PRI_SWITCH_GR303_EOC = PRI_SWITCH_GR303_EOC,
+ SANGOMA_PRI_SWITCH_GR303_TMC = PRI_SWITCH_GR303_TMC,
+ SANGOMA_PRI_SWITCH_QSIG = PRI_SWITCH_QSIG
+} sangoma_pri_switch_t;
+
+typedef enum {
+ SANGOMA_PRI_READY = (1 << 0)
+} sangoma_pri_flag_t;
+
+struct sangoma_pri;
+typedef int (*event_handler)(struct sangoma_pri *, sangoma_pri_event_t, pri_event *);
+typedef int (*loop_handler)(struct sangoma_pri *);
+#define MAX_EVENT 18
+
+struct sangoma_pri {
+ struct pri *pri;
+ int span;
+ int dchan;
+ unsigned int flags;
+ void *private_info;
+ event_handler eventmap[MAX_EVENT+1];
+ loop_handler on_loop;
+ ftdm_channel_t *zdchan;
+};
+
+struct sangoma_pri_event_list {
+ int event_id;
+ int pri_event;
+ char *name;
+};
+
+
+
+#define SANGOMA_MAP_PRI_EVENT(spri, event, func) spri.eventmap[event] = func;
+
+char *sangoma_pri_event_str(sangoma_pri_event_t event_id);
+int sangoma_one_loop(struct sangoma_pri *spri);
+int sangoma_init_pri(struct sangoma_pri *spri, int span, int dchan, int swtype, int node, int debug);
+int sangoma_run_pri(struct sangoma_pri *spri);
+
+#endif
Added: freeswitch/trunk/libs/freetdm/src/ss7/README (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/ss7/README (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ss7/README 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3 @@
+SS7 Coming soon
+
+-Shane Burrell-
Added: freeswitch/trunk/libs/freetdm/src/testanalog.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/testanalog.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testanalog.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,133 @@
+#include "freetdm.h"
+
+
+static void *test_call(ftdm_thread_t *me, void *obj)
+{
+ ftdm_channel_t *chan = (ftdm_channel_t *) obj;
+ uint8_t frame[1024];
+ ftdm_size_t len;
+ char *number = strdup("5551212");
+
+ ftdm_sleep(10 * 1000);
+
+ ftdm_log(FTDM_LOG_DEBUG, "answer call and start echo test\n");
+
+ ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_UP);
+ ftdm_channel_command(chan, FTDM_COMMAND_SEND_DTMF, number);
+
+ while (chan->state == FTDM_CHANNEL_STATE_UP) {
+ ftdm_wait_flag_t flags = FTDM_READ;
+
+ if (ftdm_channel_wait(chan, &flags, -1) == FTDM_FAIL) {
+ break;
+ }
+ len = sizeof(frame);
+ if (flags & FTDM_READ) {
+ if (ftdm_channel_read(chan, frame, &len) == FTDM_SUCCESS) {
+ //ftdm_log(FTDM_LOG_DEBUG, "WRITE %d\n", len);
+ ftdm_channel_write(chan, frame, sizeof(frame), &len);
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (chan->state == FTDM_CHANNEL_STATE_UP) {
+ ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_BUSY);
+ }
+
+ ftdm_log(FTDM_LOG_DEBUG, "call over\n");
+ free(number);
+ return NULL;
+}
+
+static FIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+ ftdm_log(FTDM_LOG_DEBUG, "got sig [%s]\n", ftdm_signal_event2str(sigmsg->event_id));
+
+ switch(sigmsg->event_id) {
+ case FTDM_SIGEVENT_START:
+ ftdm_set_state_locked(sigmsg->channel, FTDM_CHANNEL_STATE_RING);
+ ftdm_log(FTDM_LOG_DEBUG, "launching thread and indicating ring\n");
+ ftdm_thread_create_detached(test_call, sigmsg->channel);
+ break;
+ default:
+ break;
+ }
+
+ return FTDM_SUCCESS;
+}
+
+static int R = 0;
+#if 0
+static void handle_SIGINT(int sig)
+{
+ if (sig);
+ R = 0;
+ return;
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+ ftdm_span_t *span;
+ int span_id;
+ int digit_timeout = 2000;
+ int max_dialstr = 11;
+
+ if (argc < 2) {
+ printf("usage %s <spanno>\n", argv[0]);
+ exit(-1);
+ }
+
+ span_id = atoi(argv[1]);
+
+ ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
+
+ if (ftdm_global_init() != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error loading FreeTDM\n");
+ exit(-1);
+ }
+
+ ftdm_log(FTDM_LOG_DEBUG, "FreeTDM loaded\n");
+
+ if (ftdm_span_find(span_id, &span) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span\n");
+ goto done;
+ }
+
+
+ if (ftdm_configure_span("analog", span, on_signal,
+ "tonemap", "us",
+ "digit_timeout", &digit_timeout,
+ "max_dialstr", &max_dialstr,
+ TAG_END
+ ) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error configuring FreeTDM span\n");
+ goto done;
+ }
+ ftdm_span_start(span);
+
+ R = 1;
+
+ while(ftdm_running() && R) {
+ ftdm_sleep(1 * 1000);
+ }
+
+done:
+
+ ftdm_global_destroy();
+ return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/freetdm/src/testapp.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/testapp.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testapp.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,83 @@
+#include "freetdm.h"
+
+int main(int argc, char *argv[])
+{
+ ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
+ ftdm_channel_t *chan;
+ unsigned ms = 20;
+ ftdm_codec_t codec = FTDM_CODEC_SLIN;
+ unsigned runs = 1;
+
+
+ if (ftdm_global_init() != FTDM_SUCCESS) {
+ fprintf(stderr, "Error loading FreeTDM\n");
+ exit(-1);
+ }
+
+ printf("FreeTDM loaded\n");
+
+ top:
+ //if (ftdm_channel_open_any("wanpipe", 0, FTDM_TOP_DOWN, &chan) == FTDM_SUCCESS) {
+ if (ftdm_channel_open(1, 1, &chan) == FTDM_SUCCESS) {
+ int x = 0;
+ printf("opened channel %d:%d\n", chan->span_id, chan->chan_id);
+
+#if 1
+ if (ftdm_channel_command(chan, FTDM_COMMAND_SET_INTERVAL, &ms) == FTDM_SUCCESS) {
+ ms = 0;
+ ftdm_channel_command(chan, FTDM_COMMAND_GET_INTERVAL, &ms);
+ printf("interval set to %u\n", ms);
+ } else {
+ printf("set interval failed [%s]\n", chan->last_error);
+ }
+#endif
+ if (ftdm_channel_command(chan, FTDM_COMMAND_SET_CODEC, &codec) == FTDM_SUCCESS) {
+ codec = 1;
+ ftdm_channel_command(chan, FTDM_COMMAND_GET_CODEC, &codec);
+ printf("codec set to %u\n", codec);
+ } else {
+ printf("set codec failed [%s]\n", chan->last_error);
+ }
+
+ for(x = 0; x < 25; x++) {
+ unsigned char buf[2048];
+ ftdm_size_t len = sizeof(buf);
+ ftdm_wait_flag_t flags = FTDM_READ;
+
+ if (ftdm_channel_wait(chan, &flags, -1) == FTDM_FAIL) {
+ printf("wait FAIL! %u [%s]\n", (unsigned)len, chan->last_error);
+ }
+ if (flags & FTDM_READ) {
+ if (ftdm_channel_read(chan, buf, &len) == FTDM_SUCCESS) {
+ printf("READ: %u\n", (unsigned)len);
+ } else {
+ printf("READ FAIL! %u [%s]\n", (unsigned)len, chan->last_error);
+ break;
+ }
+ } else {
+ printf("wait fail [%s]\n", chan->last_error);
+ }
+ }
+ ftdm_channel_close(&chan);
+ } else {
+ printf("open fail [%s]\n", chan->last_error);
+ }
+
+ if(--runs) {
+ goto top;
+ }
+
+ ftdm_global_destroy();
+ return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/testboost.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/testboost.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testboost.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,82 @@
+#include "freetdm.h"
+
+static FIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+ return FTDM_FAIL;
+}
+
+static int R = 0;
+#if 0
+static void handle_SIGINT(int sig)
+{
+ if (sig);
+ R = 0;
+ return;
+}
+#endif
+int main(int argc, char *argv[])
+{
+ ftdm_conf_parameter_t parameters[20];
+ ftdm_span_t *span;
+ int local_port, remote_port;
+
+ local_port = remote_port = 53000;
+
+ ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
+#if 0
+ if (argc < 2) {
+ printf("invalid arguments\n");
+ exit(-1);
+ }
+#endif
+
+ if (ftdm_global_init() != FTDM_SUCCESS) {
+ fprintf(stderr, "Error loading FreeTDM\n");
+ exit(-1);
+ }
+ if (ftdm_global_configuration() != FTDM_SUCCESS) {
+ fprintf(stderr, "Error configuring FreeTDM\n");
+ exit(-1);
+ }
+
+ printf("FreeTDM loaded\n");
+
+ if (ftdm_span_find_by_name("wp1", &span) != FTDM_SUCCESS) {
+ fprintf(stderr, "Error finding FreeTDM span %s\n", argv[1]);
+ goto done;
+ }
+ parameters[0].var = "sigmod";
+ parameters[0].val = "sangoma_prid";
+ parameters[1].var = "switchtype";
+ parameters[1].val = "euroisdn";
+ parameters[1].var = "signalling";
+ parameters[1].val = "pri_cpe";
+ parameters[2].var = NULL;
+ if (ftdm_configure_span_signaling("sangoma_boost", span, on_signal, parameters) == FTDM_SUCCESS) {
+ ftdm_span_start(span);
+ } else {
+ fprintf(stderr, "Error starting SS7_BOOST\n");
+ goto done;
+ }
+
+ while(ftdm_running() && R) {
+ ftdm_sleep(1 * 1000);
+ }
+
+ done:
+
+ ftdm_global_destroy();
+
+ return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/testcid.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/testcid.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testcid.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,108 @@
+#include "freetdm.h"
+ftdm_status_t my_write_sample(int16_t *buf, ftdm_size_t buflen, void *user_data);
+
+struct helper {
+ int fd;
+ int wrote;
+};
+
+ftdm_status_t my_write_sample(int16_t *buf, ftdm_size_t buflen, void *user_data)
+{
+ struct helper *foo = (struct helper *) user_data;
+ size_t len;
+ len = write(foo->fd, buf, buflen * 2);
+ if (!len) return FTDM_FAIL;
+ foo->wrote += buflen * 2;
+ return FTDM_SUCCESS;
+}
+
+int main(int argc, char *argv[])
+{
+ struct ftdm_fsk_modulator fsk_trans;
+ ftdm_fsk_data_state_t fsk_data = {0};
+ int fd = -1;
+ int16_t buf[160] = {0};
+ ssize_t len = 0;
+ size_t type, mlen;
+ char *sp;
+ char str[128] = "";
+ char fbuf[256];
+ uint8_t databuf[1024] = "";
+ struct helper foo = {0};
+ // int x, bytes, start_bits = 180, stop_bits = 5, sbits = 300;
+ char time_str[9];
+ struct tm tm;
+ time_t now;
+
+ if (argc < 2) {
+ int x;
+ const char *url = "sip:cool@rad.com";
+
+ if ((fd = open("tone.raw", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
+ fprintf(stderr, "File Error! [%s]\n", strerror(errno));
+ exit(-1);
+ }
+
+
+ time(&now);
+ localtime_r(&now, &tm);
+ strftime(time_str, sizeof(time_str), "%m%d%H%M", &tm);
+
+ ftdm_fsk_data_init(&fsk_data, databuf, sizeof(databuf));
+#if 1
+
+ ftdm_fsk_data_add_mdmf(&fsk_data, MDMF_DATETIME, (uint8_t *)time_str, strlen(time_str));
+ //ftdm_fsk_data_add_mdmf(&fsk_data, MDMF_DATETIME, "06091213", 8);
+ ftdm_fsk_data_add_mdmf(&fsk_data, MDMF_PHONE_NUM, (uint8_t *)"14149361212", 7);
+ ftdm_fsk_data_add_mdmf(&fsk_data, MDMF_PHONE_NAME, (uint8_t *)"Fred Smith", 10);
+ for(x = 0; x < 0; x++)
+ ftdm_fsk_data_add_mdmf(&fsk_data, MDMF_ALT_ROUTE, (uint8_t *)url, strlen(url));
+#else
+ ftdm_fsk_data_add_sdmf(&fsk_data, "06061234", "0");
+ //ftdm_fsk_data_add_sdmf(&state, "06061234", "5551212");
+#endif
+ ftdm_fsk_data_add_checksum(&fsk_data);
+
+ foo.fd = fd;
+
+
+ ftdm_fsk_modulator_init(&fsk_trans, FSK_BELL202, 8000, &fsk_data, -14, 180, 5, 300, my_write_sample, &foo);
+ ftdm_fsk_modulator_send_all((&fsk_trans));
+
+ printf("%u %d %d\n", (unsigned) fsk_data.dlen, foo.wrote, fsk_trans.est_bytes);
+
+ if (fd > -1) {
+ close (fd);
+ }
+
+ return 0;
+ }
+
+ if (ftdm_fsk_demod_init(&fsk_data, 8000, (uint8_t *)fbuf, sizeof(fbuf))) {
+ printf("wtf\n");
+ return 0;
+ }
+
+ if ((fd = open(argv[1], O_RDONLY)) < 0) {
+ fprintf(stderr, "cant open file %s\n", argv[1]);
+ exit (-1);
+ }
+
+ while((len = read(fd, buf, sizeof(buf))) > 0) {
+ if (ftdm_fsk_demod_feed(&fsk_data, buf, len / 2) != FTDM_SUCCESS) {
+ break;
+ }
+ }
+
+ while(ftdm_fsk_data_parse(&fsk_data, &type, &sp, &mlen) == FTDM_SUCCESS) {
+ ftdm_copy_string(str, sp, mlen+1);
+ *(str+mlen) = '\0';
+ ftdm_clean_string(str);
+ printf("TYPE %u (%s) LEN %u VAL [%s]\n", (unsigned)type, ftdm_mdmf_type2str(type), (unsigned)mlen, str);
+ }
+
+ ftdm_fsk_demod_destroy(&fsk_data);
+
+ close(fd);
+ return 0;
+}
Added: freeswitch/trunk/libs/freetdm/src/testisdn.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/testisdn.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testisdn.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,74 @@
+#include "freetdm.h"
+#include <signal.h>
+
+
+static FIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+ return FTDM_FAIL;
+}
+
+static int R = 0;
+static void handle_SIGINT(int sig)
+{
+ if (sig);
+ R = 0;
+ return;
+}
+
+int main(int argc, char *argv[])
+{
+ ftdm_span_t *span;
+
+ ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
+
+ if (argc < 2) {
+ printf("umm no\n");
+ exit(-1);
+ }
+
+ if (ftdm_global_init() != FTDM_SUCCESS) {
+ fprintf(stderr, "Error loading FreeTDM\n");
+ exit(-1);
+ }
+
+ printf("FreeTDM loaded\n");
+
+ if (ftdm_span_find(atoi(argv[1]), &span) != FTDM_SUCCESS) {
+ fprintf(stderr, "Error finding FreeTDM span\n");
+ goto done;
+ }
+
+ if (ftdm_configure_span("isdn", span, on_signal,
+ "mode", "te",
+ "dialect", "national",
+ TAG_END) == FTDM_SUCCESS) {
+ ftdm_span_start(span);
+ } else {
+ fprintf(stderr, "Error starting ISDN D-Channel\n");
+ goto done;
+ }
+
+ signal(SIGINT, handle_SIGINT);
+ R = 1;
+ while(R) {
+ ftdm_sleep(1 * 1000);
+ }
+
+ done:
+
+ ftdm_global_destroy();
+
+ return 1;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/testm3ua.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/testm3ua.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testm3ua.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,60 @@
+/*
+ * testm3ua.c
+ * freetdm
+ *
+ * Created by Shane Burrell on 4/8/08.
+ * Copyright 2008 __MyCompanyName__. All rights reserved.
+ *
+ */
+
+#include "testm3ua.h"
+#include "freetdm.h"
+#include "ftdm_m3ua.h"
+
+static FIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+ return FTDM_FAIL;
+}
+
+int main(int argc, char *argv[])
+{
+ ftdm_span_t *span;
+ //m3ua_data_t *data;
+
+ ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
+
+ if (argc < 5) {
+ printf("more args needed\n");
+ exit(-1);
+ }
+
+ if (ftdm_global_init() != FTDM_SUCCESS) {
+ fprintf(stderr, "Error loading FreeTDM\n");
+ exit(-1);
+ }
+
+ printf("FreeTDM loaded\n");
+
+ if (ftdm_span_find(atoi(argv[1]), &span) != FTDM_SUCCESS) {
+ fprintf(stderr, "Error finding FreeTDM span\n");
+ goto done;
+ }
+
+
+ if (ftdm_m3ua_configure_span(span) == FTDM_SUCCESS) {
+ //data = span->signal_data;
+ ftdm_m3ua_start(span);
+ } else {
+ fprintf(stderr, "Error starting M3UA\n");
+ goto done;
+ }
+
+ //while(ftdm_test_flag(data, FTDM_M3UA_RUNNING)) {
+ // ftdm_sleep(1 * 1000);
+ //}
+
+ done:
+
+ ftdm_global_destroy();
+
+}
Added: freeswitch/trunk/libs/freetdm/src/testpri.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/testpri.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testpri.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,162 @@
+#include "freetdm.h"
+#include <signal.h>
+
+static int THREADS[4][31] = { {0} };
+static int R = 0;
+static int T = 0;
+static ftdm_mutex_t *mutex = NULL;
+
+
+static void *channel_run(ftdm_thread_t *me, void *obj)
+{
+ ftdm_channel_t *ftdmchan = obj;
+ int fd = -1;
+ short buf[160];
+
+ ftdm_mutex_lock(mutex);
+ T++;
+ ftdm_mutex_unlock(mutex);
+
+ ftdm_set_state_locked_wait(ftdmchan, FTDM_CHANNEL_STATE_UP);
+
+ if ((fd = open("test.raw", O_RDONLY, 0)) < 0) {
+ goto end;
+ }
+
+ while(R == 1 && THREADS[ftdmchan->span_id][ftdmchan->chan_id] == 1) {
+ ssize_t bytes = read(fd, buf, sizeof(buf));
+ size_t bbytes;
+
+ if (bytes <= 0) {
+ break;
+ }
+
+ bbytes = (size_t) bytes;
+
+ fio_slin2alaw(buf, sizeof(buf), &bbytes);
+
+ if (ftdm_channel_write(ftdmchan, buf, sizeof(buf), &bbytes) != FTDM_SUCCESS) {
+ break;
+ }
+ }
+
+ close(fd);
+
+ end:
+
+ ftdm_set_state_locked_wait(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+
+ THREADS[ftdmchan->span_id][ftdmchan->chan_id] = 0;
+
+ ftdm_mutex_lock(mutex);
+ T = 0;
+ ftdm_mutex_unlock(mutex);
+
+ return NULL;
+}
+
+static FIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+ ftdm_log(FTDM_LOG_DEBUG, "got sig %d:%d [%s]\n", sigmsg->channel->span_id, sigmsg->channel->chan_id, ftdm_signal_event2str(sigmsg->event_id));
+
+ switch(sigmsg->event_id) {
+
+ case FTDM_SIGEVENT_STOP:
+ THREADS[sigmsg->channel->span_id][sigmsg->channel->chan_id] = -1;
+ break;
+
+ case FTDM_SIGEVENT_START:
+ if (!THREADS[sigmsg->channel->span_id][sigmsg->channel->chan_id]) {
+ THREADS[sigmsg->channel->span_id][sigmsg->channel->chan_id] = 1;
+ ftdm_thread_create_detached(channel_run, sigmsg->channel);
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ return FTDM_SUCCESS;
+}
+
+
+static void handle_SIGINT(int sig)
+{
+ if (sig);
+
+ ftdm_mutex_lock(mutex);
+ R = 0;
+ ftdm_mutex_unlock(mutex);
+
+ return;
+}
+
+int main(int argc, char *argv[])
+{
+ ftdm_span_t *span;
+ ftdm_mutex_create(&mutex);
+
+ ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
+
+ if (argc < 2) {
+ printf("umm no\n");
+ exit(-1);
+ }
+
+ if (ftdm_global_init() != FTDM_SUCCESS) {
+ fprintf(stderr, "Error loading FreeTDM\n");
+ exit(-1);
+ }
+
+ printf("FreeTDM loaded\n");
+
+ if (ftdm_span_find(atoi(argv[1]), &span) != FTDM_SUCCESS) {
+ fprintf(stderr, "Error finding FreeTDM span\n");
+ goto done;
+ }
+
+
+
+ if (ftdm_configure_span(
+ "libpri", span, on_signal,
+ "node", "cpe",
+ "switch", "euroisdn",
+ "dp", "unknown",
+ "l1", "alaw",
+ "debug", NULL,
+ "opts", 0,
+ TAG_END) == FTDM_SUCCESS) {
+
+
+ ftdm_span_start(span);
+ } else {
+ fprintf(stderr, "Error starting ISDN D-Channel\n");
+ goto done;
+ }
+
+ signal(SIGINT, handle_SIGINT);
+ ftdm_mutex_lock(mutex);
+ R = 1;
+ ftdm_mutex_unlock(mutex);
+ while(R || T) {
+ ftdm_sleep(1 * 1000);
+ }
+
+ done:
+
+ ftdm_global_destroy();
+
+ return 1;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/testr2.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/testr2.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testr2.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,86 @@
+#include "freetdm.h"
+#include <signal.h>
+
+static int R = 0;
+static ftdm_mutex_t *mutex = NULL;
+
+static FIO_SIGNAL_CB_FUNCTION(on_r2_signal)
+{
+ ftdm_log(FTDM_LOG_DEBUG, "Got R2 channel sig [%s] in channel\n", ftdm_signal_event2str(sigmsg->event_id), sigmsg->channel->physical_chan_id);
+ return FTDM_SUCCESS;
+}
+
+static void handle_SIGINT(int sig)
+{
+ ftdm_mutex_lock(mutex);
+ R = 0;
+ ftdm_mutex_unlock(mutex);
+ return;
+}
+
+int main(int argc, char *argv[])
+{
+ ftdm_span_t *span;
+ ftdm_mutex_create(&mutex);
+
+ ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
+
+ if (argc < 2) {
+ printf("umm no\n");
+ exit(-1);
+ }
+
+ if (ftdm_global_init() != FTDM_SUCCESS) {
+ fprintf(stderr, "Error loading FreeTDM\n");
+ exit(-1);
+ }
+
+ printf("FreeTDM loaded\n");
+
+ if (ftdm_span_find(atoi(argv[1]), &span) != FTDM_SUCCESS) {
+ fprintf(stderr, "Error finding FreeTDM span\n");
+ goto done;
+ }
+
+
+
+ if (ftdm_configure_span("r2", span, on_r2_signal,
+ "variant", "mx",
+ "max_ani", 10,
+ "max_dnis", 4,
+ "logging", "all",
+ TAG_END) == FTDM_SUCCESS) {
+
+
+ ftdm_span_start(span);
+ } else {
+ fprintf(stderr, "Error starting R2 span\n");
+ goto done;
+ }
+
+ signal(SIGINT, handle_SIGINT);
+ ftdm_mutex_lock(mutex);
+ R = 1;
+ ftdm_mutex_unlock(mutex);
+ while(R) {
+ ftdm_sleep(1 * 1000);
+ }
+
+ done:
+
+ ftdm_global_destroy();
+
+ return 1;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/testsangomaboost.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/testsangomaboost.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testsangomaboost.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2010, Sangoma Technologies
+ * Moises Silva <moy@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.
+ */
+
+/**
+ * Sample program for the boost signaling absraction.
+ * Usage: boostsample <span name>
+ * The span name must be a valid span defined in freetdm.conf
+ * compile this program linking to the freetdm library (ie -lfreetdm)
+ **/
+
+#ifndef __linux__
+#define _CRT_SECURE_NO_WARNINGS 1
+#endif
+
+#include <signal.h>
+
+#include "freetdm.h"
+
+
+/* arbitrary limit for max calls in this sample program */
+#define MAX_CALLS 255
+
+/* some timers (in seconds) to fake responses in incoming calls */
+#define PROGRESS_TIMER 1
+#define ANSWER_TIMER 5
+#define HANGUP_TIMER 15
+
+/* simple variable used to stop the application */
+static int app_running = 0;
+
+typedef void (*expired_function_t)(ftdm_channel_t *channel);
+typedef struct dummy_timer_s {
+ int time;
+ ftdm_channel_t *channel;
+ expired_function_t expired;
+} dummy_timer_t;
+
+/* dummy second resolution timers */
+static dummy_timer_t g_timers[MAX_CALLS];
+
+/* mutex to protect the timers (both, the test thread and the signaling thread may modify them) */
+static ftdm_mutex_t *g_schedule_mutex;
+
+/* unique outgoing channel */
+static ftdm_channel_t *g_outgoing_channel = NULL;
+
+static void interrupt_requested(int signal)
+{
+ app_running = 0;
+}
+
+static void schedule_timer(ftdm_channel_t *channel, int sec, expired_function_t expired)
+{
+ int i;
+ ftdm_mutex_lock(g_schedule_mutex);
+ for (i = 0; i < sizeof(g_timers)/sizeof(g_timers[0]); i++) {
+ /* check the timer slot is free to use */
+ if (!g_timers[i].time) {
+ g_timers[i].time = sec;
+ g_timers[i].channel = channel;
+ g_timers[i].expired = expired;
+ ftdm_mutex_unlock(g_schedule_mutex);
+ return;
+ }
+ }
+ ftdm_log(FTDM_LOG_ERROR, "Failed to schedule timer\n");
+ ftdm_mutex_unlock(g_schedule_mutex);
+}
+
+static void run_timers(void)
+{
+ int i;
+ void *channel;
+ expired_function_t expired_func = NULL;
+ ftdm_mutex_lock(g_schedule_mutex);
+ for (i = 0; i < sizeof(g_timers)/sizeof(g_timers[0]); i++) {
+ /* if there's time left, decrement */
+ if (g_timers[i].time) {
+ g_timers[i].time--;
+ }
+
+ /* if time expired and we have an expired function, call it */
+ if (!g_timers[i].time && g_timers[i].expired) {
+ expired_func = g_timers[i].expired;
+ channel = g_timers[i].channel;
+ memset(&g_timers[i], 0, sizeof(g_timers[i]));
+ expired_func(channel);
+ }
+ }
+ ftdm_mutex_unlock(g_schedule_mutex);
+}
+
+static void release_timers(ftdm_channel_t *channel)
+{
+ int i;
+ ftdm_mutex_lock(g_schedule_mutex);
+ for (i = 0; i < sizeof(g_timers)/sizeof(g_timers[0]); i++) {
+ /* clear any timer belonging to the given channel */
+ if (g_timers[i].channel == channel) {
+ memset(&g_timers[i], 0, sizeof(g_timers[i]));
+ }
+ }
+ ftdm_mutex_unlock(g_schedule_mutex);
+}
+
+/* hangup the call */
+static void send_hangup(ftdm_channel_t *channel)
+{
+ ftdm_log(FTDM_LOG_NOTICE, "-- Requesting hangup in channel %d:%d\n", channel->span_id, channel->chan_id);
+ ftdm_set_state_locked(channel, FTDM_CHANNEL_STATE_HANGUP);
+}
+
+/* send answer for an incoming call */
+static void send_answer(ftdm_channel_t *channel)
+{
+ /* we move the channel signaling state machine to UP (answered) */
+ ftdm_log(FTDM_LOG_NOTICE, "-- Requesting answer in channel %d:%d\n", channel->span_id, channel->chan_id);
+ ftdm_set_state_locked(channel, FTDM_CHANNEL_STATE_UP);
+ schedule_timer(channel, HANGUP_TIMER, send_hangup);
+}
+
+/* send progress for an incoming */
+static void send_progress(ftdm_channel_t *channel)
+{
+ /* we move the channel signaling state machine to UP (answered) */
+ ftdm_log(FTDM_LOG_NOTICE, "-- Requesting progress\n", channel->span_id, channel->chan_id);
+ ftdm_set_state_locked(channel, FTDM_CHANNEL_STATE_PROGRESS);
+ schedule_timer(channel, ANSWER_TIMER, send_answer);
+}
+
+/* This function will be called in an undetermined signaling thread, you must not do
+ * any blocking operations here or the signaling stack may delay other call event processing
+ * The arguments for this function are defined in FIO_SIGNAL_CB_FUNCTION prototype, I just
+ * name them here for your convenience:
+ * ftdm_sigmsg_t *sigmsg
+ * - The sigmsg structure contains the ftdm_channel structure that represents the channel where
+ * the event occurred and the event_id of the signaling event that just occurred.
+ * */
+static FIO_SIGNAL_CB_FUNCTION(on_signaling_event)
+{
+ switch (sigmsg->event_id) {
+ /* This event signals the start of an incoming call */
+ case FTDM_SIGEVENT_START:
+ ftdm_log(FTDM_LOG_NOTICE, "Incoming call received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id);
+ schedule_timer(sigmsg->channel, PROGRESS_TIMER, send_progress);
+ break;
+ /* This event signals progress on an outgoing call */
+ case FTDM_SIGEVENT_PROGRESS_MEDIA:
+ ftdm_log(FTDM_LOG_NOTICE, "Progress message received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id);
+ break;
+ /* This event signals answer in an outgoing call */
+ case FTDM_SIGEVENT_UP:
+ ftdm_log(FTDM_LOG_NOTICE, "Answer received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id);
+ /* now the channel is answered and we can use
+ * ftdm_channel_wait() to wait for input/output in a channel (equivalent to poll() or select())
+ * ftdm_channel_read() to read available data in a channel
+ * ftdm_channel_write() to write to the channel */
+ break;
+ /* This event signals hangup from the other end */
+ case FTDM_SIGEVENT_STOP:
+ ftdm_log(FTDM_LOG_NOTICE, "Hangup received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id);
+ if (g_outgoing_channel == sigmsg->channel) {
+ g_outgoing_channel = NULL;
+ }
+ /* release any timer for this channel */
+ release_timers(sigmsg->channel);
+ /* acknowledge the hangup */
+ ftdm_set_state_locked(sigmsg->channel, FTDM_CHANNEL_STATE_HANGUP);
+ break;
+ default:
+ ftdm_log(FTDM_LOG_WARNING, "Unhandled event %s in channel %d:%d\n", ftdm_signal_event2str(sigmsg->event_id),
+ sigmsg->span_id, sigmsg->chan_id);
+ break;
+ }
+ return FTDM_SUCCESS;
+}
+
+static void place_call(const ftdm_span_t *span, const char *number)
+{
+ ftdm_channel_t *ftdmchan = NULL;
+ ftdm_caller_data_t caller_data = {{ 0 }};
+ ftdm_status_t status = FTDM_FAIL;
+
+ /* set destiny number */
+ ftdm_set_string(caller_data.dnis.digits, number);
+
+ /* set callerid */
+ ftdm_set_string(caller_data.cid_name, "testsangomaboost");
+ ftdm_set_string(caller_data.cid_num.digits, "1234");
+
+ /* request to search for an outgoing channel top down with the given caller data.
+ * it is also an option to use ftdm_channel_open_by_group to let freetdm hunt
+ * an available channel in a given group instead of per span
+ * */
+ status = ftdm_channel_open_by_span(span->span_id, FTDM_TOP_DOWN, &caller_data, &ftdmchan);
+ if (status != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to originate call\n");
+ return;
+ }
+
+ g_outgoing_channel = ftdmchan;
+
+ /* set the caller data for the outgoing channel */
+ memcpy(&ftdmchan->caller_data, &caller_data, sizeof(caller_data));
+
+ status = ftdm_channel_outgoing_call(ftdmchan);
+ if (status != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to originate call\n");
+ return;
+ }
+
+ /* this is required to initialize the outgoing channel */
+ ftdm_channel_init(ftdmchan);
+}
+
+int main(int argc, char *argv[])
+{
+ ftdm_conf_parameter_t parameters[20];
+ ftdm_span_t *span;
+ char *todial = NULL;
+ int32_t ticks = 0;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s <span name> [number to dial if any]\n", argv[0]);
+ exit(-1);
+ }
+
+ /* register a handler to shutdown things properly */
+ if (signal(SIGINT, interrupt_requested) == SIG_ERR) {
+ fprintf(stderr, "Could not set the SIGINT signal handler: %s\n", strerror(errno));
+ exit(-1);
+ }
+
+ if (argc >= 3) {
+ todial = argv[2];
+ if (!strlen(todial)) {
+ todial = NULL;
+ }
+ }
+
+ /* clear any outstanding timers */
+ memset(&g_timers, 0, sizeof(g_timers));
+
+ /* set the logging level to use */
+ ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
+
+ /* Initialize the FTDM library */
+ if (ftdm_global_init() != FTDM_SUCCESS) {
+ fprintf(stderr, "Error loading FreeTDM\n");
+ exit(-1);
+ }
+
+ /* create the schedule mutex */
+ ftdm_mutex_create(&g_schedule_mutex);
+
+ /* Load the FreeTDM configuration */
+ if (ftdm_global_configuration() != FTDM_SUCCESS) {
+ fprintf(stderr, "Error configuring FreeTDM\n");
+ exit(-1);
+ }
+
+ /* At this point FreeTDM is ready to be used, the spans defined in freetdm.conf have the basic I/O board configuration
+ * but no telephony signaling configuration at all. */
+ printf("FreeTDM loaded ...\n");
+
+ /* Retrieve a span by name (according to freetdm.conf) */
+ if (ftdm_span_find_by_name(argv[1], &span) != FTDM_SUCCESS) {
+ fprintf(stderr, "Error finding FreeTDM span %s\n", argv[1]);
+ goto done;
+ }
+
+ /* prepare the configuration parameters that will be sent down to the signaling stack, the array of paramters must be terminated by an
+ * array element with a null .var member */
+
+ /* for sangoma_boost signaling (abstraction signaling used by Sangoma for PRI, BRI and SS7) the first parameter you must send
+ * is sigmod, which must be either sangoma_prid, if you have the PRI stack available, or sangoma_brid for the BRI stack */
+ parameters[0].var = "sigmod";
+ parameters[0].val = "sangoma_prid";
+
+ /* following parameters are signaling stack specific, this ones are for PRI */
+ parameters[1].var = "switchtype";
+ parameters[1].val = "national";
+
+ parameters[2].var = "signalling";
+ parameters[2].val = "pri_cpe";
+
+ /*
+ * parameters[3].var = "nfas_primary";
+ * parameters[3].val = "4"; //span number
+ *
+ * parameters[4].var = "nfas_secondary";
+ * parameters[4].val = "2"; //span number
+ *
+ * parameters[5].var = "nfas_group";
+ * parameters[5].val = "1";
+ * */
+
+ /* the last parameter .var member must be NULL! */
+ parameters[3].var = NULL;
+
+ /* send the configuration values down to the stack */
+ if (ftdm_configure_span_signaling("sangoma_boost", span, on_signaling_event, parameters) != FTDM_SUCCESS) {
+ fprintf(stderr, "Error configuring sangoma_boost signaling abstraction in span %s\n", span->name);
+ goto done;
+ }
+
+ /* configuration succeeded, we can proceed now to start the span
+ * This step will launch at least 1 background (may be more, depending on the signaling stack used)
+ * to handle *ALL* signaling events for this span, your on_signaling_event callback will be called always
+ * in one of those infraestructure threads and you MUST NOT block in that handler to avoid delays and errors
+ * in the signaling processing for any call.
+ * */
+ ftdm_span_start(span);
+
+ app_running = 1;
+
+ /* The application thread can go on and do anything else, like waiting for a shutdown signal */
+ while(ftdm_running() && app_running) {
+ ftdm_sleep(1000);
+ run_timers();
+ ticks++;
+ if (!(ticks % 10) && todial && !g_outgoing_channel) {
+ ftdm_log(FTDM_LOG_NOTICE, "Originating call to number %s\n", todial);
+ place_call(span, todial);
+ }
+ }
+ printf("Shutting down FreeTDM ...\n");
+ done:
+
+ ftdm_mutex_destroy(&g_schedule_mutex);
+
+ /* whenever you're done, this function will shutdown the signaling threads in any span that was started */
+ ftdm_global_destroy();
+
+ return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/freetdm/src/testtones.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/testtones.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testtones.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,76 @@
+#include "freetdm.h"
+
+struct ttmp {
+ int fd;
+};
+
+static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+ struct ttmp *tmp = ts->user_data;
+ int wrote;
+ size_t len;
+
+ wrote = teletone_mux_tones(ts, map);
+ len = write(tmp->fd, ts->buffer, wrote * 2);
+
+ if (!len) return -1;
+
+ return 0;
+}
+
+#if 1
+int main(int argc, char *argv[])
+{
+ teletone_generation_session_t ts;
+ struct ttmp tmp;
+
+ if (argc < 3) {
+ fprintf(stderr, "Arg Error! <file> <tones>\n");
+ exit(-1);
+ }
+
+ if ((tmp.fd = open(argv[1], O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
+ fprintf(stderr, "File Error! [%s]\n", strerror(errno));
+ exit(-1);
+ }
+
+ teletone_init_session(&ts, 0, teletone_handler, &tmp);
+ ts.rate = 8000;
+ ts.debug = 1;
+ ts.debug_stream = stdout;
+ teletone_run(&ts, argv[2]);
+ close(tmp.fd);
+
+ return 0;
+}
+#else
+int32_t main(int argc, char *argv[])
+{
+ int32_t j, i, fd = -1;
+ int32_t rate = 8000;
+ /* SIT tones and durations */
+ float tones[] = { 913.8, 1370.6, 1776.7, 0 };
+ int32_t durations[] = {274, 274, 380, 0};
+ teletone_dds_state_t dds = {0};
+ int16_t sample;
+ size_t len = 1;
+
+ if (argc < 2 || (fd = open(argv[1], O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
+ fprintf(stderr, "File Error!\n", strerror(errno));
+ exit(-1);
+ }
+
+ for (j = 0; tones[j] && durations[j]; j++) {
+
+ teletone_dds_state_set_tone(&dds, tones[j], rate, -50);
+
+ for(i = 0; (i < durations[j] * rate / 1000) && len != 0; i++) {
+ sample = teletone_dds_modulate_sample(&dds) * 20;
+ len = write(fd, &sample, sizeof(sample));
+ }
+
+ }
+
+ close(fd);
+}
+#endif
Added: freeswitch/trunk/libs/freetdm/src/uart.c (0 => 17141)
--- freeswitch/trunk/libs/freetdm/src/uart.c (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/uart.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,125 @@
+
+/*
+ * uart.c
+ *
+ * Copyright (c) 2005 Robert Krten. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * This module contains a simple 8-bit UART, which performs a callback
+ * with the decoded byte value.
+ *
+ * 2005 06 11 R. Krten created
+*/
+
+#include <freetdm.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "uart.h"
+
+/*
+ * dsp_uart_attr_init
+ *
+ * Initializes the attributes structure; this must be done before the
+ * attributes structure is used.
+*/
+
+void dsp_uart_attr_init (dsp_uart_attr_t *attr)
+{
+ memset (attr, 0, sizeof (*attr));
+}
+
+/*
+ * dsp_uart_attr_get_bytehandler
+ * dsp_uart_attr_set_bytehandler
+ *
+ * These functions get and set their respective elements from the
+ * attributes structure. If an error code is returned, it is just
+ * zero == ok, -1 == fail.
+*/
+
+bytehandler_func_t dsp_uart_attr_get_bytehandler(dsp_uart_attr_t *attr, void **bytehandler_arg)
+{
+ *bytehandler_arg = attr->bytehandler_arg;
+ return attr->bytehandler;
+}
+
+void dsp_uart_attr_set_bytehandler(dsp_uart_attr_t *attr, bytehandler_func_t bytehandler, void *bytehandler_arg)
+{
+ attr->bytehandler = bytehandler;
+ attr->bytehandler_arg = bytehandler_arg;
+}
+
+dsp_uart_handle_t *dsp_uart_create(dsp_uart_attr_t *attr)
+{
+ dsp_uart_handle_t *handle;
+
+ handle = ftdm_malloc(sizeof (*handle));
+ if (handle) {
+ memset(handle, 0, sizeof (*handle));
+
+ /* fill the attributes member */
+ memcpy(&handle->attr, attr, sizeof (*attr));
+ }
+ return handle;
+}
+
+void dsp_uart_destroy(dsp_uart_handle_t **handle)
+{
+ if (*handle) {
+ ftdm_safe_free(*handle);
+ *handle = NULL;
+ }
+}
+
+
+void dsp_uart_bit_handler(void *x, int bit)
+{
+ dsp_uart_handle_t *handle = (dsp_uart_handle_t *) x;
+
+ if (!handle->have_start) {
+ if (bit) {
+ return; /* waiting for start bit (0) */
+ }
+ handle->have_start = 1;
+ handle->data = 0;
+ handle->nbits = 0;
+ return;
+ }
+
+ handle->data >>= 1;
+ handle->data |= 0x80 * !!bit;
+ handle->nbits++;
+
+ if (handle->nbits == 8) {
+ handle->attr.bytehandler(handle->attr.bytehandler_arg, handle->data);
+ handle->nbits = 0;
+ handle->data = 0;
+ handle->have_start = 0;
+ }
+/* might consider handling errors in the future... */
+}
+
Added: freeswitch/trunk/libs/openzap/.gitignore (0 => 17141)
--- freeswitch/trunk/libs/openzap/.gitignore (rev 0)
+++ freeswitch/trunk/libs/openzap/.gitignore 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,13 @@
+*.o
+*.lo
+*.so
+*.a
+*.orig
+*.rej
+*.log
+
+Makefile
+config.*
+configure
+libtool
+aclocal.m4
Added: freeswitch/trunk/libs/openzap/.update (0 => 17141)
--- freeswitch/trunk/libs/openzap/.update (rev 0)
+++ freeswitch/trunk/libs/openzap/.update 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1 @@
+Fri Oct 3 17:54:41 EDT 2008
Added: freeswitch/trunk/libs/openzap/AUTHORS ( => )
Added: freeswitch/trunk/libs/openzap/ChangeLog
===================================================================
Added: freeswitch/trunk/libs/openzap/Makefile.am (0 => 17141)
--- freeswitch/trunk/libs/openzap/Makefile.am (rev 0)
+++ freeswitch/trunk/libs/openzap/Makefile.am 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,272 @@
+# Copyright (c) 2007, Anthony Minessale II
+# 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.
+
+PREFIX = $(prefix)
+SRC = src
+
+moddir = @modinstdir@
+libdir = @libdir@
+library_includedir = $(PREFIX)/include
+
+INCS = -I$(OZ_SRCDIR)/$(SRC)/include -I$(OZ_SRCDIR)/$(SRC)/isdn/include
+if HAVE_SCTP
+INCS += -I$(OZ_SRCDIR)/$(SRC)/ozmod/ozmod_sangoma_boost
+endif
+MY_CFLAGS = $(INCS) $(ZAP_CFLAGS) -DZAP_CONFIG_DIR=\"@confdir@\" -DZAP_MOD_DIR=\"$(moddir)\" @COMP_VENDOR_CFLAGS@ @DEFS@
+COMPILE = $(CC) $(MY_CFLAGS) $(INCS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(COMPILE)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CC) $(MY_CFLAGS) $(LDFLAGS) -o $@
+
+
+#
+# GNU pkgconfig file
+#
+EXTRA_DIST = openzap.pc.in
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = openzap.pc
+
+
+#
+# libopenzap
+#
+libopenzap_la_SOURCES = \
+$(SRC)/hashtable.c \
+$(SRC)/hashtable_itr.c \
+$(SRC)/zap_io.c \
+$(SRC)/zap_config.c \
+$(SRC)/zap_callerid.c \
+$(SRC)/fsk.c \
+$(SRC)/uart.c \
+$(SRC)/g711.c \
+$(SRC)/libteletone_detect.c \
+$(SRC)/libteletone_generate.c \
+$(SRC)/zap_buffer.c \
+$(SRC)/zap_threadmutex.c \
+$(SRC)/zap_dso.c \
+$(SRC)/zap_cpu_monitor.c
+
+library_include_HEADERS = \
+$(SRC)/include/fsk.h \
+$(SRC)/include/g711.h \
+$(SRC)/include/hashtable.h \
+$(SRC)/include/hashtable_itr.h \
+$(SRC)/include/hashtable_private.h \
+$(SRC)/include/libteletone_detect.h \
+$(SRC)/include/libteletone_generate.h \
+$(SRC)/include/libteletone.h \
+$(SRC)/include/openzap.h \
+$(SRC)/include/sangoma_tdm_api.h \
+$(SRC)/include/uart.h \
+$(SRC)/include/zap_buffer.h \
+$(SRC)/include/zap_config.h \
+$(SRC)/include/zap_threadmutex.h \
+$(SRC)/include/zap_dso.h \
+$(SRC)/include/zap_types.h \
+$(SRC)/include/zap_cpu_monitor.h
+
+lib_LTLIBRARIES = libopenzap.la
+libopenzap_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+libopenzap_la_LDFLAGS = -version-info 1:0:0 $(AM_LDFLAGS)
+libopenzap_la_LIBADD = $(LIBS)
+
+MYLIB = libopenzap.la
+
+core: libopenzap.la
+core-install: install-libLTLIBRARIES
+
+#
+# tools & test programs
+#
+noinst_PROGRAMS = testtones detect_tones detect_dtmf testisdn testpri testr2 testanalog testapp testcid
+if HAVE_SCTP
+noinst_PROGRAMS += testboost
+endif
+
+testapp_SOURCES = $(SRC)/testapp.c
+testapp_LDADD = libopenzap.la
+testapp_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testcid_SOURCES = $(SRC)/testcid.c
+testcid_LDADD = libopenzap.la
+testcid_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testtones_SOURCES = $(SRC)/testtones.c
+testtones_LDADD = libopenzap.la
+testtones_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+
+detect_tones_SOURCES = $(SRC)/detect_tones.c
+detect_tones_LDADD = libopenzap.la
+detect_tones_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+
+detect_dtmf_SOURCES = $(SRC)/detect_dtmf.c
+detect_dtmf_LDADD = libopenzap.la
+detect_dtmf_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testisdn_SOURCES = $(SRC)/testisdn.c
+testisdn_LDADD = libopenzap.la
+testisdn_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testpri_SOURCES = $(SRC)/testpri.c
+testpri_LDADD = libopenzap.la
+testpri_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testr2_SOURCES = $(SRC)/testr2.c
+testr2_LDADD = libopenzap.la
+testr2_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+
+if HAVE_SCTP
+testboost_SOURCES = $(SRC)/testboost.c
+testboost_LDADD = libopenzap.la
+testboost_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+endif
+
+testanalog_SOURCES = $(SRC)/testanalog.c
+testanalog_LDADD = libopenzap.la
+testanalog_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+
+#
+# ozmod modules
+#
+mod_LTLIBRARIES = ozmod_zt.la ozmod_skel.la ozmod_isdn.la ozmod_analog.la ozmod_analog_em.la
+
+
+if HAVE_SCTP
+mod_LTLIBRARIES += ozmod_sangoma_boost.la
+endif
+
+if LIBSANGOMA
+mod_LTLIBRARIES += ozmod_wanpipe.la
+endif
+
+if LIBPRI
+mod_LTLIBRARIES += ozmod_libpri.la
+endif
+
+if OPENR2
+mod_LTLIBRARIES += ozmod_r2.la
+endif
+
+ozmod_zt_la_SOURCES = $(SRC)/ozmod/ozmod_zt/ozmod_zt.c
+ozmod_zt_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+ozmod_zt_la_LDFLAGS = -module -avoid-version
+ozmod_zt_la_LIBADD = $(MYLIB)
+
+ozmod_skel_la_SOURCES = $(SRC)/ozmod/ozmod_skel/ozmod_skel.c
+ozmod_skel_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+ozmod_skel_la_LDFLAGS = -module -avoid-version
+ozmod_skel_la_LIBADD = $(MYLIB)
+
+if LIBSANGOMA
+ozmod_wanpipe_la_SOURCES = $(SRC)/ozmod/ozmod_wanpipe/ozmod_wanpipe.c
+ozmod_wanpipe_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) -D__LINUX__ -I/usr/include/wanpipe
+ozmod_wanpipe_la_LDFLAGS = -module -avoid-version -lsangoma
+ozmod_wanpipe_la_LIBADD = $(MYLIB)
+endif
+
+ozmod_isdn_la_SOURCES = \
+$(SRC)/isdn/EuroISDNStateNT.c \
+$(SRC)/isdn/EuroISDNStateTE.c \
+$(SRC)/isdn/mfifo.c \
+$(SRC)/isdn/Q921.c \
+$(SRC)/isdn/Q931api.c \
+$(SRC)/isdn/Q931.c \
+$(SRC)/isdn/Q931ie.c \
+$(SRC)/isdn/Q931mes.c \
+$(SRC)/isdn/Q931StateNT.c \
+$(SRC)/isdn/Q931StateTE.c \
+$(SRC)/isdn/nationalmes.c \
+$(SRC)/isdn/nationalStateNT.c \
+$(SRC)/isdn/nationalStateTE.c \
+$(SRC)/isdn/DMSmes.c \
+$(SRC)/isdn/DMSStateNT.c \
+$(SRC)/isdn/DMSStateTE.c \
+$(SRC)/isdn/5ESSmes.c \
+$(SRC)/isdn/5ESSStateNT.c \
+$(SRC)/isdn/5ESSStateTE.c \
+$(SRC)/isdn/Q932mes.c \
+$(SRC)/ozmod/ozmod_isdn/ozmod_isdn.c
+
+ozmod_isdn_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) -D_GNU_SOURCE
+ozmod_isdn_la_LDFLAGS = $(PCAP_LIB_FLAGS) -module -avoid-version
+ozmod_isdn_la_LIBADD = $(MYLIB)
+
+ozmod_analog_la_SOURCES = $(SRC)/ozmod/ozmod_analog/ozmod_analog.c
+ozmod_analog_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+ozmod_analog_la_LDFLAGS = -module -avoid-version
+ozmod_analog_la_LIBADD = $(MYLIB)
+
+ozmod_analog_em_la_SOURCES = $(SRC)/ozmod/ozmod_analog_em/ozmod_analog_em.c
+ozmod_analog_em_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+ozmod_analog_em_la_LDFLAGS = -module -avoid-version
+ozmod_analog_em_la_LIBADD = $(MYLIB)
+
+if HAVE_SCTP
+ozmod_sangoma_boost_la_SOURCES = $(SRC)/ozmod/ozmod_sangoma_boost/sangoma_boost_client.c $(SRC)/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c
+ozmod_sangoma_boost_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+ozmod_sangoma_boost_la_LDFLAGS = -module -avoid-version
+ozmod_sangoma_boost_la_LIBADD = $(MYLIB)
+endif
+
+if LIBPRI
+ozmod_libpri_la_SOURCES = $(SRC)/ozmod/ozmod_libpri/ozmod_libpri.c $(SRC)/ozmod/ozmod_libpri/lpwrap_pri.c
+ozmod_libpri_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+ozmod_libpri_la_LDFLAGS = -module -avoid-version -lpri
+ozmod_libpri_la_LIBADD = $(MYLIB)
+endif
+
+if OPENR2
+ozmod_r2_la_SOURCES = $(SRC)/ozmod/ozmod_r2/ozmod_r2.c
+ozmod_r2_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+ozmod_r2_la_LDFLAGS = -module -avoid-version -lopenr2
+ozmod_r2_la_LIBADD = $(MYLIB)
+endif
+
+
+dox doxygen:
+ cd docs && doxygen $(OZ_SRCDIR)/docs/Doxygen.conf
+
+mod_openzap/mod_openzap.$(DYNAMIC_LIB_EXTEN): $(MYLIB) mod_openzap/mod_openzap.c
+ cd mod_openzap && make
+
+mod_openzap: mod_openzap/mod_openzap.$(DYNAMIC_LIB_EXTEN)
+
+mod_openzap-install: mod_openzap
+ cd mod_openzap && make install
+
+mod_openzap-clean:
+ @if [ -f mod_openzap/mod_openzap.$(DYNAMIC_LIB_EXTEN) ] ; then cd mod_openzap && make clean ; fi
+
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(PREFIX)
+ $(mkinstalldirs) $(DESTDIR)@confdir@
+ @[ -f "$(DESTDIR)@confdir@/openzap.conf" ] || ( cp conf/*.conf $(DESTDIR)@confdir@)
+ @echo OpenZAP Installed
Added: freeswitch/trunk/libs/openzap/NEWS ( => )
Added: freeswitch/trunk/libs/openzap/README
===================================================================
--- freeswitch/trunk/libs/openzap/README (rev 0)
+++ freeswitch/trunk/libs/openzap/README 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3 @@
+OPENZAP (WORK IN PROGRESS)
+
+*shrug*
Added: freeswitch/trunk/libs/openzap/acinclude.m4 (0 => 17141)
--- freeswitch/trunk/libs/openzap/acinclude.m4 (rev 0)
+++ freeswitch/trunk/libs/openzap/acinclude.m4 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1 @@
+m4_include([build/libpcap.m4])
Added: freeswitch/trunk/libs/openzap/bootstrap (0 => 17141)
--- freeswitch/trunk/libs/openzap/bootstrap (rev 0)
+++ freeswitch/trunk/libs/openzap/bootstrap 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,6 @@
+#!/bin/bash
+autoheader
+libtoolize --force --copy
+aclocal
+automake -f --copy --add-missing
+autoconf
Property changes on: freeswitch/trunk/libs/openzap/bootstrap
___________________________________________________________________
Name: svn:executable
+ *
Added: freeswitch/trunk/libs/openzap/build/libpcap.m4 (0 => 17141)
--- freeswitch/trunk/libs/openzap/build/libpcap.m4 (rev 0)
+++ freeswitch/trunk/libs/openzap/build/libpcap.m4 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,144 @@
+dnl libpcap.m4--PCAP libraries and includes
+dnl Derrick Brashear
+dnl from KTH krb and Arla
+dnl $Id: libpcap.m4,v 1.4 2006/01/20 20:21:09 snsimon Exp $
+
+AC_DEFUN([PCAP_INC_WHERE1], [
+ac_cv_found_pcap_inc=no
+if test -f "$1/pcap.h" ; then
+ ac_cv_found_pcap_inc=yes
+fi
+])
+
+AC_DEFUN([PCAP_INC_WHERE], [
+ for i in $1; do
+ AC_MSG_CHECKING(for pcap header in $i)
+ PCAP_INC_WHERE1($i)
+ if test "$ac_cv_found_pcap_inc" = "yes"; then
+ ac_cv_pcap_where_inc=$i
+ AC_MSG_RESULT(found)
+ break
+ else
+ AC_MSG_RESULT(no found)
+ fi
+ done
+])
+
+AC_DEFUN([PCAP_LIB_WHERE1], [
+saved_LIBS=$LIBS
+LIBS="$saved_LIBS -L$1 -lpcap"
+AC_TRY_LINK(,
+[pcap_lookupdev("");],
+[ac_cv_found_pcap_lib=yes],
+ac_cv_found_pcap_lib=no)
+LIBS=$saved_LIBS
+])
+
+AC_DEFUN([TEST_LIBPATH], [
+changequote(<<, >>)
+define(<<AC_CV_FOUND>>, translit(ac_cv_found_$2_lib, <<- *>>, <<__p>>))
+changequote([, ])
+if test "$AC_CV_FOUND" = "yes"; then
+ if test \! -r "$1/lib$2.a" -a \! -r "$1/lib$2.so" -a \! -r "$1/lib$2.sl" -a \! -r "$1/lib$2.dylib"; then
+ AC_CV_FOUND=no
+ fi
+fi
+])
+
+
+AC_DEFUN([PCAP_LIB_WHERE], [
+ for i in $1; do
+ AC_MSG_CHECKING(for pcap library in $i)
+ PCAP_LIB_WHERE1($i)
+ TEST_LIBPATH($i, pcap)
+ if test "$ac_cv_found_pcap_lib" = "yes" ; then
+ ac_cv_pcap_where_lib=$i
+ AC_MSG_RESULT(found)
+ break
+ else
+ AC_MSG_RESULT(no found)
+ fi
+ done
+])
+
+AC_DEFUN([FIND_LIB_SUBDIR],
+[dnl
+AC_ARG_WITH([lib-subdir], AC_HELP_STRING([--with-lib-subdir=DIR],[Find libraries in DIR instead of lib]))
+AC_CHECK_SIZEOF(long)
+AC_CACHE_CHECK([what directory libraries are found in], [ac_cv_cmu_lib_subdir],
+[test "X$with_lib_subdir" = "Xyes" && with_lib_subdir=
+test "X$with_lib_subdir" = "Xno" && with_lib_subdir=
+ if test "X$with_lib_subdir" = "X" ; then
+ ac_cv_cmu_lib_subdir=lib
+ if test $ac_cv_sizeof_long -eq 4 ; then
+ test -d /usr/lib32 && ac_cv_cmu_lib_subdir=lib32
+ test -r /usr/lib/libpcap.so && ac_cv_cmu_lib_subdir=lib
+ fi
+ if test $ac_cv_sizeof_long -eq 8 ; then
+ test -d /usr/lib64 && ac_cv_cmu_lib_subdir=lib64
+ fi
+ else
+ ac_cv_cmu_lib_subdir=$with_lib_subdir
+ fi])
+ AC_SUBST(LIB_SUBDIR, $ac_cv_cmu_lib_subdir)
+ ])
+
+
+AC_DEFUN([AX_LIB_PCAP], [
+AC_REQUIRE([FIND_LIB_SUBDIR])
+AC_ARG_WITH(pcap,
+ [ --with-pcap=PREFIX Compile with PCAP support],
+ [if test "X$with_pcap" = "X"; then
+ with_pcap=yes
+ fi])
+AC_ARG_WITH(pcap-lib,
+ [ --with-pcap-lib=dir use pcap libraries in dir],
+ [if test "$withval" = "yes" -o "$withval" = "no"; then
+ AC_MSG_ERROR([No argument for --with-pcap-lib])
+ fi])
+AC_ARG_WITH(pcap-include,
+ [ --with-pcap-include=dir use pcap headers in dir],
+ [if test "$withval" = "yes" -o "$withval" = "no"; then
+ AC_MSG_ERROR([No argument for --with-pcap-include])
+ fi])
+
+ if test "X$with_pcap" != "X"; then
+ if test "$with_pcap" != "yes"; then
+ ac_cv_pcap_where_lib=$with_pcap
+ ac_cv_pcap_where_inc=$with_pcap/include
+ fi
+ fi
+
+ if test "X$with_pcap_lib" != "X"; then
+ ac_cv_pcap_where_lib=$with_pcap_lib
+ fi
+ if test "X$ac_cv_pcap_where_lib" = "X"; then
+ PCAP_LIB_WHERE(/usr/$LIB_SUBDIR /usr/local/$LIB_SUBDIR)
+ fi
+
+ if test "X$with_pcap_include" != "X"; then
+ ac_cv_pcap_where_inc=$with_pcap_include
+ fi
+ if test "X$ac_cv_pcap_where_inc" = "X"; then
+ PCAP_INC_WHERE(/usr/ng/include /usr/include /usr/local/include)
+ fi
+
+ AC_MSG_CHECKING(whether to include pcap)
+ if test "X$ac_cv_pcap_where_lib" != "X" -a "X$ac_cv_pcap_where_inc" != "X"; then
+ ac_cv_found_pcap=yes
+ AC_MSG_RESULT(yes)
+ PCAP_INC_DIR=$ac_cv_pcap_where_inc
+ PCAP_LIB_DIR=$ac_cv_pcap_where_lib
+ PCAP_INC_FLAGS="-I${PCAP_INC_DIR}"
+ PCAP_LIB_FLAGS="-L${PCAP_LIB_DIR} -lpcap"
+ AC_SUBST(PCAP_INC_DIR)
+ AC_SUBST(PCAP_LIB_DIR)
+ AC_SUBST(PCAP_INC_FLAGS)
+ AC_SUBST(PCAP_LIB_FLAGS)
+ AC_DEFINE([HAVE_LIBPCAP],[1],[libpcap])
+ else
+ ac_cv_found_pcap=no
+ AC_MSG_RESULT(no)
+ fi
+ ])
+
Added: freeswitch/trunk/libs/openzap/conf/m3ua.conf (0 => 17141)
--- freeswitch/trunk/libs/openzap/conf/m3ua.conf (rev 0)
+++ freeswitch/trunk/libs/openzap/conf/m3ua.conf 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,38 @@
+;M3UA SS7 Links Config
+;
+;ss7box-m3ua_mode => true
+;local_sctp_ip => localhost
+;local sctp_port => 30000
+;remote_sctp_ip => localhost
+;remote_sctp_port => 30001
+;opc => 0-0-0
+;dpc => 0-0-0
+
+
+; AP Specific Stuff. This will likely move later.
+
+; CNAM Gateways
+cnam1_dpc => 0-0-0
+cnam1_ssn => 253
+cnam2_dpc => 0-0-0
+cnam2_ssn => 253
+cnam3_dpc => 0-0-0
+cnam3_ssn => 253
+
+;LNP Gateways
+lnp1_dpc => 0-0-0
+lnp1_ssn => 253
+lnp2_dpc => 0-0-0
+lnp2_ssn => 253
+lnp3_dpc => 0-0-0
+lnp3_ssn => 253
+
+;LNP Gateways
+sms8001_dpc => 0-0-0
+sms8001_ssn => 253
+sms8002_dpc => 0-0-0
+sms8002_ssn => 253
+sms8003_dpc => 0-0-0
+sms8003_ssn => 253
+
+
Added: freeswitch/trunk/libs/openzap/conf/openzap.conf (0 => 17141)
--- freeswitch/trunk/libs/openzap/conf/openzap.conf (rev 0)
+++ freeswitch/trunk/libs/openzap/conf/openzap.conf 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,19 @@
+[span wanpipe]
+name => OpenZAP
+number => 1
+fxs-channel => 1:3-4
+
+[span wanpipe]
+fxo-channel => 1:1-2
+
+[span zt]
+name => OpenZAP
+number => 2
+fxs-channel => 1
+
+[span zt]
+name => OpenZAP
+number => 2
+fxo-channel => 3
+
+
Added: freeswitch/trunk/libs/openzap/conf/openzap.conf.xml (0 => 17141)
--- freeswitch/trunk/libs/openzap/conf/openzap.conf.xml (rev 0)
+++ freeswitch/trunk/libs/openzap/conf/openzap.conf.xml 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,45 @@
+<configuration name="openzap.conf" description="OpenZAP Configuration">
+ <settings>
+ <param name="debug" value="0"/>
+ <!--<param name="hold-music" value="$${moh_uri}"/>-->
+ <!--<param name="enable-analog-option" value="call-swap"/>-->
+ <!--<param name="enable-analog-option" value="3-way"/>-->
+ </settings>
+ <pri_spans>
+ <span name="PRI_1">
+ <!-- Log Levels: none, alert, crit, err, warning, notice, info, debug -->
+ <param name="q921loglevel" value="alert"/>
+ <param name="q931loglevel" value="alert"/>
+ <param name="mode" value="user"/>
+ <param name="dialect" value="5ess"/>
+ <param name="dialplan" value="XML"/>
+ <param name="context" value="default"/>
+ </span>
+ <span name="PRI_2">
+ <param name="q921loglevel" value="alert"/>
+ <param name="q931loglevel" value="alert"/>
+ <param name="mode" value="user"/>
+ <param name="dialect" value="5ess"/>
+ <param name="dialplan" value="XML"/>
+ <param name="context" value="default"/>
+ </span>
+ </pri_spans>
+ <!-- one entry here per openzap span -->
+ <analog_spans>
+ <span id="1">
+ <!--<param name="hold-music" value="$${moh_uri}"/>-->
+ <!--<param name="enable-analog-option" value="call-swap"/>-->
+ <!--<param name="enable-analog-option" value="3-way"/>-->
+ <param name="tonegroup" value="us"/>
+ <param name="digit-timeout" value="2000"/>
+ <param name="max-digits" value="11"/>
+ <param name="dialplan" value="XML"/>
+ <param name="context" value="default"/>
+ <param name="enable-callerid" value="true"/>
+ <!-- regex to stop dialing when it matches -->
+ <!--<param name="dial-regex" value="5555"/>-->
+ <!-- regex to stop dialing when it does not match -->
+ <!--<param name="fail-dial-regex" value="^5"/>-->
+ </span>
+ </analog_spans>
+</configuration>
Added: freeswitch/trunk/libs/openzap/conf/pika.conf (0 => 17141)
--- freeswitch/trunk/libs/openzap/conf/pika.conf (rev 0)
+++ freeswitch/trunk/libs/openzap/conf/pika.conf 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,41 @@
+; each category is a config profile
+; to apply the profile append it to a channel def in
+; openzap.conf with @<profile_name>
+; e.g.
+; [span pika]
+; name => pika
+; number => pika
+; fxs-channel => 1:0:1-12@default
+
+[default]
+; region is na or eu
+;region => na
+;rx-gain => 0.00
+;rx-agc-enabled => false
+;rx-agc-targetPower => -15.00
+;rx-agc-minGain => -6.00
+;rx-agc-maxGain => 18.00
+;rx-agc-attackRate => 170
+;rx-agc-decayRate => 750
+;rx-agc-speechThreshold => -36.00
+;rx-vad-enabled => false
+;rx-vad-activationThreshold => -40.00
+;rx-vad-activationDebounceTime => 72
+;rx-vad-deactivationThreshold => -40.00
+;rx-vad-deactivationDebounceTime => 984
+;rx-vad-preSpeechBufferSize => 240
+;tx-gain => 0.00
+;tx-agc-enabled => true
+;tx-agc-targetPower => -15.00
+;tx-agc-minGain => -6.00
+;tx-agc-maxGain => 18.00
+;tx-agc-attackRate => 170
+;tx-agc-decayRate => 750
+;tx-agc-speechThreshold => -36.00
+;ec-enabled => false
+;ec-doubleTalkerThreshold => -6.00
+;ec-speechPresentThreshold => -40.00
+;ec-echoSuppressionThreshold => -18.00
+;ec-echoSuppressionEnabled => true
+;ec-comfortNoiseEnabled => true
+;ec-adaptationModeEnabled => true
Added: freeswitch/trunk/libs/openzap/conf/tones.conf (0 => 17141)
--- freeswitch/trunk/libs/openzap/conf/tones.conf (rev 0)
+++ freeswitch/trunk/libs/openzap/conf/tones.conf 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,63 @@
+[us]
+generate-dial => v=-7;%(1000,0,350,440)
+detect-dial => 350,440
+
+generate-ring => v=-7;%(2000,4000,440,480)
+detect-ring => 440,480
+
+generate-busy => v=-7;%(500,500,480,620)
+detect-busy => 480,620
+
+generate-attn => v=0;%(100,100,1400,2060,2450,2600)
+detect-attn => 1400,2060,2450,2600
+
+generate-callwaiting-sas => v=0;%(300,0,440)
+detect-callwaiting-sas => 440
+
+generate-callwaiting-cas => v=0;%(80,0,2750,2130)
+detect-callwaiting-cas => 2750,2130
+
+detect-fail1 => 913.8
+detect-fail2 => 1370.6
+detect-fail3 => 1776.7
+
+
+[sg]
+generate-dial => v=-7;%(1000,0,425)
+detect-dial => 425
+
+generate-ring => v=-7;%(2000,4000,425)
+detect-ring => 425
+
+generate-busy => v=-7;%(750,750,425)
+detect-busy => 425
+
+generate-attn => v=0;%(100,100,1400,2060,2450,2600)
+detect-attn => 1400,2060,2450,2600
+
+generate-callwaiting-sas => v=0;%(300,0,440)
+detect-callwaiting-sas => 440
+
+generate-callwaiting-cas => v=0;%(80,0,2750,2130)
+detect-callwaiting-cas => 2750,2130
+
+detect-fail1 => 913.8
+detect-fail2 => 1370.6
+detect-fail3 => 1776.7
+
+[ru]
+generate-dial => v=-7;%(1000,425)
+detect-dial => 0
+generate-ring => v=-7;%(800,5000,425,0)
+detect-ring => 425,0
+generate-busy => v=-7;%(350,350,425,0)
+detect-busy => 425,0
+generate-attn => v=0;%(100,100,1400,2060,2450,2600)
+detect-attn => 1400,2060,2450,2600
+generate-callwaiting-sas => v=0;%(300,0,440)
+detect-callwaiting-sas => 440,480
+generate-callwaiting-cas => v=0;%(80,0,2750,2130)
+detect-callwaiting-cas => 2750,2130
+detect-fail1 => 913.8
+detect-fail2 => 1370.6
+detect-fail3 => 1776.7
Added: freeswitch/trunk/libs/openzap/conf/wanpipe.conf (0 => 17141)
--- freeswitch/trunk/libs/openzap/conf/wanpipe.conf (rev 0)
+++ freeswitch/trunk/libs/openzap/conf/wanpipe.conf 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,4 @@
+[defaults]
+codec_ms => 20
+wink_ms => 150
+flash_ms => 750
Added: freeswitch/trunk/libs/openzap/conf/zt.conf (0 => 17141)
--- freeswitch/trunk/libs/openzap/conf/zt.conf (rev 0)
+++ freeswitch/trunk/libs/openzap/conf/zt.conf 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,8 @@
+[defaults]
+codec_ms => 20
+wink_ms => 150
+flash_ms => 750
+echo_cancel_level => 64
+rxgain => 0.0
+txgain => 0.0
+
Added: freeswitch/trunk/libs/openzap/configure.ac (0 => 17141)
--- freeswitch/trunk/libs/openzap/configure.ac (rev 0)
+++ freeswitch/trunk/libs/openzap/configure.ac 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,181 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.59)
+AC_INIT([openzap],[pre-alpha],[bugs@freeswitch.org])
+AC_CONFIG_SRCDIR([src/zap_io.c])
+
+AC_CONFIG_AUX_DIR(build)
+AM_INIT_AUTOMAKE(libopenzap,0.1)
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_MAKE_SET
+AM_PROG_CC_C_O
+
+AC_PREFIX_DEFAULT(/usr/local/openzap)
+# AC_PREFIX_DEFAULT does not get expanded until too late so we need to do this to use prefix in this script
+if test "x$prefix" = "xNONE" ; then
+ prefix='/usr/local/openzap'
+fi
+
+# Absolute source/build directory
+OZ_SRCDIR=`(cd $srcdir && pwd)`
+oz_builddir=`pwd`
+AC_SUBST(OZ_SRCDIR)
+AC_SUBST(oz_builddir)
+
+if test "$sysconfdir" = "\${prefix}/etc" ; then
+ confdir="$prefix/conf"
+else
+ confdir="$sysconfdir"
+fi
+
+AC_SUBST(confdir)
+
+#override some default libtool behavior and invoke AC_PROG_LIBTOOL (see http://lists.gnu.org/archive/html/libtool/2007-03/msg00000.html)
+m4_defun([_LT_AC_LANG_F77_CONFIG], [:])
+m4_defun([_LT_AC_LANG_GCJ_CONFIG], [:])
+m4_defun([_LT_AC_LANG_RC_CONFIG], [:])
+#AM_PROG_CC_C_O
+AC_PROG_LIBTOOL
+AC_PROG_INSTALL
+
+# Check for com;iler type
+AC_DEFUN([AX_COMPILER_VENDOR],
+[
+AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor,
+ [ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=unknown
+ # note: don't check for GCC first, since some other compilers define __GNUC__
+ for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do
+ vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")"
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[
+#if !($vencpp)
+ thisisanerror;
+#endif
+])], [ax_cv_]_AC_LANG_ABBREV[_compiler_vendor=`echo $ventest | cut -d: -f1`; break])
+ done
+ ])
+])
+AC_ARG_ENABLE([enable_64], [AS_HELP_STRING([--enable-64], [Enable 64bit compilation])], [enable_64="$enableval"], [enable_64="no"])
+
+AX_COMPILER_VENDOR
+
+case "${ax_cv_c_compiler_vendor}" in
+gnu)
+ COMP_VENDOR_CFLAGS="-ffast-math -Wall -Werror -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -O0"
+ ;;
+sun)
+ COMP_VENDOR_CFLAGS="-xc99=all -mt -xCC -D__FUNCTION__=__func__ -xvpara"
+ if test "$enable_64" = "yes" ; then
+ COMP_VENDOR_CFLAGS="-m64 $COMP_VENDOR_CFLAGS"
+ fi
+ ;;
+*)
+ COMP_VENDOR_CFLAGS="-std=c99 -Wall -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes"
+ ;;
+esac
+
+
+#set SOLINK variable based on compiler and host
+if test "x${ax_cv_c_compiler_vendor}" = "xsun" ; then
+ SOLINK="-Bdynamic -dy -G"
+elif test "x${ax_cv_c_compiler_vendor}" = "xgnu" ; then
+ case "$host" in
+ *darwin*)
+ SOLINK="-dynamic -bundle -force-flat-namespace"
+ ;;
+ *-solaris2*)
+ SOLINK="-shared -Xlinker"
+ ;;
+ *)
+ SOLINK="-shared -Xlinker -x"
+ ;;
+ esac
+else
+ AC_ERROR([Please update configure.in with SOLINK values for your compiler])
+fi
+
+# set DYNAMIC_LIB_EXTEN
+# we should really be using libtool so we don't need to do this
+case "$host" in
+ *cygwin* | *mingw*)
+ DYNAMIC_LIB_EXTEN="dll"
+ ;;
+ *)
+ DYNAMIC_LIB_EXTEN="so"
+ ;;
+esac
+
+AC_SUBST(SOLINK)
+AC_SUBST(DYNAMIC_LIB_EXTEN)
+
+AC_CHECK_LIB([dl], [dlopen])
+AC_CHECK_LIB([pthread], [pthread_create])
+AC_CHECK_LIB([m], [cos])
+AX_LIB_PCAP
+
+AC_CHECK_HEADERS([netinet/sctp.h netdb.h sys/select.h])
+AM_CONDITIONAL([HAVE_SCTP],[test "${ac_cv_header_netinet_sctp_h}" = "yes"])
+
+AC_CHECK_FUNC([gethostbyname_r],
+ [], [AC_CHECK_LIB([nsl], [gethostbyname_r])]
+)
+if test "$ac_cv_func_gethostbyname_r" = "yes" -o "$ac_cv_lib_nsl_gethostbyname_r" = "yes" ; then
+
+AC_MSG_CHECKING([whether gethostbyname_r requires five arguments])
+
+ac_cv_func_gethostbyname_r_five_args="no"
+
+AC_TRY_COMPILE([#include <netdb.h>],
+ [char *name;
+ struct hostent *he, *res;
+ char buffer[2048];
+ int buflen = 2048;
+ (void)gethostbyname_r(name, he, buffer, buflen, &res)],
+ [ac_cv_func_gethostbyname_r_five_args="yes"
+ AC_DEFINE([HAVE_GETHOSTBYNAME_R_FIVE], [1], [gethostbyname_r has five arguments])]
+)
+
+ AC_MSG_RESULT([$ac_cv_func_gethostbyname_r_five_args])
+ AC_DEFINE([HAVE_GETHOSTBYNAME_R],[1],[threadsafe gethostbyname])
+fi
+
+# Enable debugging
+AC_ARG_ENABLE(debug,
+[AC_HELP_STRING([--enable-debug],[build with debug information])],[enable_debug="$enableval"],[enable_debug="yes"])
+
+if test "${enable_debug}" = "yes"; then
+ AC_DEFINE([DEBUG],[],[Enable extra debugging.])
+
+ if test "x${ax_cv_c_compiler_vendor}" = "xgnu" ; then
+ COMP_VENDOR_CFLAGS="$COMP_VENDOR_CFLAGS -g -ggdb"
+ fi
+fi
+
+# Where to install the modules
+AC_ARG_WITH([modinstdir],
+ [AS_HELP_STRING([--with-modinstdir=DIR], [Install modules into this location (default: $prefix/mod)])], [modinstdir="$withval"], [modinstdir="${prefix}/mod"])
+
+AC_SUBST(modinstdir)
+
+
+# libpri?
+AC_ARG_WITH([libpri],
+ [AS_HELP_STRING([--with-libpri], [Install ozmod_libpri])], [enable_libpri="yes"], [enable_libpri="no"])
+AC_SUBST(enable_libpri)
+
+AC_CHECK_LIB([sangoma], [sangoma_span_chan_toif], [have_libsangoma="yes"])
+AM_CONDITIONAL([LIBSANGOMA],[test "${have_libsangoma}" = "yes"])
+
+AM_CONDITIONAL([LIBPRI],[test "${enable_libpri}" = "yes"])
+
+AC_CHECK_LIB([openr2], [openr2_context_set_io_type], [have_openr2="yes"])
+AM_CONDITIONAL([OPENR2],[test "${have_openr2}" = "yes"])
+
+COMP_VENDOR_CFLAGS="$COMP_VENDOR_CFLAGS"
+AC_SUBST(COMP_VENDOR_CFLAGS)
+AC_CONFIG_FILES([Makefile
+ openzap.pc
+ mod_openzap/Makefile])
+AC_OUTPUT
Added: freeswitch/trunk/libs/openzap/configure.gnu (0 => 17141)
--- freeswitch/trunk/libs/openzap/configure.gnu (rev 0)
+++ freeswitch/trunk/libs/openzap/configure.gnu 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,4 @@
+#! /bin/sh
+srcpath=$(dirname $0 2>/dev/null ) || srcpath="."
+$srcpath/configure "$@" --with-pic
+
Added: freeswitch/trunk/libs/openzap/docs/Doxygen.conf (0 => 17141)
--- freeswitch/trunk/libs/openzap/docs/Doxygen.conf (rev 0)
+++ freeswitch/trunk/libs/openzap/docs/Doxygen.conf 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,277 @@
+# Doxyfile 1.4.6
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = OpenZAP
+PROJECT_NUMBER =
+OUTPUT_DIRECTORY = .
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = YES
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = NO
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+DISTRIBUTE_GROUP_DOC = NO
+SUBGROUPING = YES
+IGNORE_PREFIX = zap_ ZAP_ Q921 Q931
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = YES
+EXTRACT_STATIC = YES
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = YES
+HIDE_UNDOC_MEMBERS = YES
+HIDE_UNDOC_CLASSES = YES
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = NO
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = YES
+FILE_VERSION_FILTER =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = ../src ../src/include \
+ ../src/isdn ../src/isdn/include \
+ ../mod_openzap ../ \
+ ../src/ozmod \
+ ../src/ozmod/ozmod_analog \
+ ../src/ozmod/ozmod_analog_em \
+ ../src/ozmod/ozmod_isdn \
+ ../src/ozmod/ozmod_pika \
+ ../src/ozmod/ozmod_skel \
+ ../src/ozmod/ozmod_ss7_boost \
+ ../src/ozmod/ozmod_wanpipe \
+ ../src/ozmod/ozmod_zt
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.d \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.idl \
+ *.odl \
+ *.cs \
+ *.php \
+ *.php3 \
+ *.inc \
+ *.m \
+ *.mm \
+ *.dox \
+ *.py
+RECURSIVE = NO
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = YES
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+USE_HTAGS = YES
+VERBATIM_HEADERS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 1
+IGNORE_PREFIX = zap_
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE = freeswitch.chm
+HHC_LOCATION =
+GENERATE_CHI = YES
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = YES
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = YES
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = NO
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS = *.h
+PREDEFINED = ZAP_DECLARE(x)=x \
+ APR_DECLARE(x)=x \
+ ZAP_MOD_DECLARE(x)=x \
+ DoxyDefine(x)=x
+
+EXPAND_AS_DEFINED = NO
+SKIP_FUNCTION_MACROS = NO
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = YES
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = YES
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = YES
+TEMPLATE_RELATIONS = YES
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = YES
+DOT_IMAGE_FORMAT = jpg
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 1000
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
Added: freeswitch/trunk/libs/openzap/mod_openzap/Makefile.in (0 => 17141)
--- freeswitch/trunk/libs/openzap/mod_openzap/Makefile.in (rev 0)
+++ freeswitch/trunk/libs/openzap/mod_openzap/Makefile.in 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,23 @@
+OZ_CFLAGS=@CFLAGS@ @COMP_VENDOR_CFLAGS@ @DEFS@
+
+BASE=../../..
+OZ_DIR=..
+VERBOSE=1
+OZLA=$(OZ_DIR)/libopenzap.la
+LOCAL_CFLAGS=-I$(OZ_DIR)/src/include -I$(OZ_DIR)/src/isdn/include $(OZ_CFLAGS)
+LOCAL_LDFLAGS=-L$(OZ_DIR) -lopenzap
+include $(BASE)/build/modmake.rules
+
+local_depend: $(OZLA)
+
+$(OZLA): $(OZ_DIR)/.update
+ cd $(OZ_DIR) && $(MAKE)
+
+local_install:
+ cd $(OZ_DIR) && $(MAKE) install
+ [ -f $(DESTDIR)@confdir@/autoload_configs/openzap.conf.xml ] || cp -f $(OZ_DIR)/conf/openzap.conf.xml $(DESTDIR)@confdir@/autoload_configs
+
+local_clean:
+ cd $(OZ_DIR) && $(MAKE) clean
+
+
Added: freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.2005.vcproj (0 => 17141)
--- freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.2005.vcproj (rev 0)
+++ freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.2005.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="mod_openzap"
+ ProjectGUID="{FE3540C5-3303-46E0-A69E-D92F775687F1}"
+ RootNamespace="mod_openzap"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="FreeSwitchCore.lib"
+ OutputFile="$(SolutionDir)$(OutDir)/mod/$(InputName).dll"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=""../../../w32/Library/$(OutDir)""
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+ SubSystem="2"
+ ImportLibrary="$(OutDir)/mod_openzap.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="FreeSwitchCore.lib"
+ OutputFile="$(SolutionDir)$(OutDir)/mod/$(InputName).dll"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories=""../../../w32/Library/$(OutDir)""
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ LinkTimeCodeGeneration="1"
+ ImportLibrary="$(OutDir)/mod_openzap.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\mod_openzap.c"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,369 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="mod_openzap"
+ ProjectGUID="{FE3540C5-3303-46E0-A69E-D92F775687F1}"
+ RootNamespace="mod_openzap"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="FreeSwitchCore.lib"
+ OutputFile="$(SolutionDir)$(OutDir)/mod/mod_openzap.dll"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=""../../../w32/Library/$(OutDir)""
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+ SubSystem="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ ImportLibrary="$(OutDir)/mod_openzap.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="FreeSwitchCore.lib"
+ OutputFile="$(SolutionDir)$(OutDir)/mod/mod_openzap.dll"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories=""../../../w32/Library/$(OutDir)""
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ LinkTimeCodeGeneration="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ ImportLibrary="$(OutDir)/mod_openzap.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="FreeSwitchCore.lib"
+ OutputFile="$(SolutionDir)$(OutDir)/mod/mod_openzap.dll"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=""../../../w32/Library/$(OutDir)""
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+ SubSystem="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ ImportLibrary="$(OutDir)/mod_openzap.lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="FreeSwitchCore.lib"
+ OutputFile="$(SolutionDir)$(OutDir)/mod/mod_openzap.dll"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories=""../../../w32/Library/$(OutDir)""
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ LinkTimeCodeGeneration="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ ImportLibrary="$(OutDir)/mod_openzap.lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\mod_openzap.c"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.c (rev 0)
+++ freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3221 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * 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 <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Moises Silva <moy@sangoma.com>
+ *
+ *
+ * mod_openzap.c -- OPENZAP Endpoint Module
+ *
+ */
+#include <switch.h>
+#include "openzap.h"
+
+#ifndef __FUNCTION__
+#define __FUNCTION__ __SWITCH_FUNC__
+#endif
+
+#define OPENZAP_VAR_PREFIX "openzap_"
+#define OPENZAP_VAR_PREFIX_LEN 8
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_openzap_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_openzap_shutdown);
+SWITCH_MODULE_DEFINITION(mod_openzap, mod_openzap_load, mod_openzap_shutdown, NULL);
+
+switch_endpoint_interface_t *openzap_endpoint_interface;
+
+static switch_memory_pool_t *module_pool = NULL;
+
+typedef enum {
+ ANALOG_OPTION_NONE = 0,
+ ANALOG_OPTION_3WAY = (1 << 0),
+ ANALOG_OPTION_CALL_SWAP = (1 << 1)
+} analog_option_t;
+
+struct span_config {
+ zap_span_t *span;
+ char dialplan[80];
+ char context[80];
+ char dial_regex[256];
+ char fail_dial_regex[256];
+ char hold_music[256];
+ char type[256];
+ analog_option_t analog_options;
+};
+
+static struct span_config SPAN_CONFIG[ZAP_MAX_SPANS_INTERFACE] = {{0}};
+
+typedef enum {
+ TFLAG_IO = (1 << 0),
+ TFLAG_DTMF = (1 << 1),
+ TFLAG_CODEC = (1 << 2),
+ TFLAG_BREAK = (1 << 3),
+ TFLAG_HOLD = (1 << 4),
+ TFLAG_DEAD = (1 << 5)
+} TFLAGS;
+
+static struct {
+ int debug;
+ char *dialplan;
+ char *codec_string;
+ char *codec_order[SWITCH_MAX_CODECS];
+ int codec_order_last;
+ char *codec_rates_string;
+ char *codec_rates[SWITCH_MAX_CODECS];
+ int codec_rates_last;
+ unsigned int flags;
+ int fd;
+ int calls;
+ char hold_music[256];
+ switch_mutex_t *mutex;
+ analog_option_t analog_options;
+} globals;
+
+struct private_object {
+ unsigned int flags;
+ switch_codec_t read_codec;
+ switch_codec_t write_codec;
+ switch_frame_t read_frame;
+ unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
+ switch_frame_t cng_frame;
+ unsigned char cng_databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
+ switch_core_session_t *session;
+ switch_caller_profile_t *caller_profile;
+ unsigned int codec;
+ unsigned int codecs;
+ unsigned short samprate;
+ switch_mutex_t *mutex;
+ switch_mutex_t *flag_mutex;
+ zap_channel_t *zchan;
+ uint32_t wr_error;
+};
+
+typedef struct private_object private_t;
+
+
+static switch_status_t channel_on_init(switch_core_session_t *session);
+static switch_status_t channel_on_hangup(switch_core_session_t *session);
+static switch_status_t channel_on_destroy(switch_core_session_t *session);
+static switch_status_t channel_on_routing(switch_core_session_t *session);
+static switch_status_t channel_on_exchange_media(switch_core_session_t *session);
+static switch_status_t channel_on_soft_execute(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_kill_channel(switch_core_session_t *session, int sig);
+zap_status_t zap_channel_from_event(zap_sigmsg_t *sigmsg, switch_core_session_t **sp);
+void dump_chan(zap_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream);
+void dump_chan_xml(zap_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream);
+
+static void zap_set_npi(const char *npi_string, uint8_t *target)
+{
+ if (!strcasecmp(npi_string, "isdn") || !strcasecmp(npi_string, "e164")) {
+ *target = ZAP_NPI_ISDN;
+ } else if (!strcasecmp(npi_string, "data")) {
+ *target = ZAP_NPI_DATA;
+ } else if (!strcasecmp(npi_string, "telex")) {
+ *target = ZAP_NPI_TELEX;
+ } else if (!strcasecmp(npi_string, "national")) {
+ *target = ZAP_NPI_NATIONAL;
+ } else if (!strcasecmp(npi_string, "private")) {
+ *target = ZAP_NPI_PRIVATE;
+ } else if (!strcasecmp(npi_string, "reserved")) {
+ *target = ZAP_NPI_RESERVED;
+ } else if (!strcasecmp(npi_string, "unknown")) {
+ *target = ZAP_NPI_UNKNOWN;
+ } else {
+ zap_log(ZAP_LOG_WARNING, "Invalid NPI value (%s)\n", npi_string);
+ *target = ZAP_NPI_UNKNOWN;
+ }
+}
+
+static void zap_set_ton(const char *ton_string, uint8_t *target)
+{
+ if (!strcasecmp(ton_string, "national")) {
+ *target = ZAP_TON_NATIONAL;
+ } else if (!strcasecmp(ton_string, "international")) {
+ *target = ZAP_TON_INTERNATIONAL;
+ } else if (!strcasecmp(ton_string, "local")) {
+ *target = ZAP_TON_SUBSCRIBER_NUMBER;
+ } else if (!strcasecmp(ton_string, "unknown")) {
+ *target = ZAP_TON_UNKNOWN;
+ } else {
+ zap_log(ZAP_LOG_WARNING, "Invalid TON value (%s)\n", ton_string);
+ *target = ZAP_TON_UNKNOWN;
+ }
+}
+
+static switch_core_session_t *zap_channel_get_session(zap_channel_t *channel, int32_t id)
+{
+ switch_core_session_t *session = NULL;
+
+ if (id > ZAP_MAX_TOKENS) {
+ return NULL;
+ }
+
+ if (!zstr(channel->tokens[id])) {
+ if (!(session = switch_core_session_locate(channel->tokens[id]))) {
+ zap_channel_clear_token(channel, channel->tokens[id]);
+ }
+ }
+
+ return session;
+}
+
+static const char *zap_channel_get_uuid(zap_channel_t *channel, int32_t id)
+{
+ if (id > ZAP_MAX_TOKENS) {
+ return NULL;
+ }
+
+ if (!zstr(channel->tokens[id])) {
+ return channel->tokens[id];
+ }
+ return NULL;
+}
+
+static void stop_hold(switch_core_session_t *session_a, const char *uuid)
+{
+ switch_core_session_t *session;
+ switch_channel_t *channel, *channel_a;
+ ;
+
+ if (!uuid) {
+ return;
+ }
+
+ if ((session = switch_core_session_locate(uuid))) {
+ channel = switch_core_session_get_channel(session);
+
+ if (switch_channel_test_flag(channel, CF_HOLD)) {
+ channel_a = switch_core_session_get_channel(session_a);
+ switch_ivr_unhold(session);
+ switch_channel_clear_flag(channel_a, CF_SUSPEND);
+ switch_channel_clear_flag(channel_a, CF_HOLD);
+ } else {
+ switch_channel_stop_broadcast(channel);
+ switch_channel_wait_for_flag(channel, CF_BROADCAST, SWITCH_FALSE, 2000, NULL);
+ }
+
+ switch_core_session_rwunlock(session);
+ }
+}
+
+static void start_hold(zap_channel_t *zchan, switch_core_session_t *session_a, const char *uuid, const char *stream)
+{
+ switch_core_session_t *session;
+ switch_channel_t *channel, *channel_a;
+
+ if (!uuid) {
+ return;
+ }
+
+
+ if ((session = switch_core_session_locate(uuid))) {
+ channel = switch_core_session_get_channel(session);
+ if (zstr(stream)) {
+ if (!strcasecmp(globals.hold_music, "indicate_hold")) {
+ stream = "indicate_hold";
+ }
+ if (!strcasecmp(SPAN_CONFIG[zchan->span->span_id].hold_music, "indicate_hold")) {
+ stream = "indicate_hold";
+ }
+ }
+
+ if (zstr(stream)) {
+ stream = switch_channel_get_variable(channel, SWITCH_HOLD_MUSIC_VARIABLE);
+ }
+
+ if (zstr(stream)) {
+ stream = SPAN_CONFIG[zchan->span->span_id].hold_music;
+ }
+
+ if (zstr(stream)) {
+ stream = globals.hold_music;
+ }
+
+
+ if (zstr(stream) && !(stream = switch_channel_get_variable(channel, SWITCH_HOLD_MUSIC_VARIABLE))) {
+ stream = globals.hold_music;
+ }
+
+ if (!zstr(stream)) {
+ if (!strcasecmp(stream, "indicate_hold")) {
+ channel_a = switch_core_session_get_channel(session_a);
+ switch_ivr_hold_uuid(uuid, NULL, 0);
+ switch_channel_set_flag(channel_a, CF_SUSPEND);
+ switch_channel_set_flag(channel_a, CF_HOLD);
+ } else {
+ switch_ivr_broadcast(switch_core_session_get_uuid(session), stream, SMF_ECHO_ALEG | SMF_LOOP);
+ }
+ }
+
+ switch_core_session_rwunlock(session);
+ }
+}
+
+
+static void cycle_foreground(zap_channel_t *zchan, int flash, const char *bcast) {
+ uint32_t i = 0;
+ switch_core_session_t *session;
+ switch_channel_t *channel;
+ private_t *tech_pvt;
+
+
+ for (i = 0; i < zchan->token_count; i++) {
+ if ((session = zap_channel_get_session(zchan, i))) {
+ const char *buuid;
+ tech_pvt = switch_core_session_get_private(session);
+ channel = switch_core_session_get_channel(session);
+ buuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
+
+
+ if (zchan->token_count == 1 && flash) {
+ if (switch_test_flag(tech_pvt, TFLAG_HOLD)) {
+ stop_hold(session, buuid);
+ switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+ } else {
+ start_hold(zchan, session, buuid, bcast);
+ switch_set_flag_locked(tech_pvt, TFLAG_HOLD);
+ }
+ } else if (i) {
+ start_hold(zchan, session, buuid, bcast);
+ switch_set_flag_locked(tech_pvt, TFLAG_HOLD);
+ } else {
+ stop_hold(session, buuid);
+ switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+ if (!switch_channel_test_flag(channel, CF_ANSWERED)) {
+ switch_channel_mark_answered(channel);
+ }
+ }
+ switch_core_session_rwunlock(session);
+ }
+ }
+}
+
+
+
+
+static switch_status_t tech_init(private_t *tech_pvt, switch_core_session_t *session, zap_channel_t *zchan)
+{
+ const char *dname = NULL;
+ uint32_t interval = 0, srate = 8000;
+ zap_codec_t codec;
+
+ tech_pvt->zchan = zchan;
+ tech_pvt->read_frame.data = tech_pvt->databuf;
+ tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf);
+ tech_pvt->cng_frame.data = tech_pvt->cng_databuf;
+ tech_pvt->cng_frame.buflen = sizeof(tech_pvt->cng_databuf);
+ tech_pvt->cng_frame.flags = SFF_CNG;
+ tech_pvt->cng_frame.codec = &tech_pvt->read_codec;
+ memset(tech_pvt->cng_frame.data, 255, tech_pvt->cng_frame.buflen);
+ switch_mutex_init(&tech_pvt->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+ switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+ switch_core_session_set_private(session, tech_pvt);
+ tech_pvt->session = session;
+
+ if (ZAP_SUCCESS != zap_channel_command(zchan, ZAP_COMMAND_GET_INTERVAL, &interval)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to retrieve channel interval.\n");
+ return SWITCH_STATUS_GENERR;
+ }
+
+ if (ZAP_SUCCESS != zap_channel_command(zchan, ZAP_COMMAND_GET_CODEC, &codec)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to retrieve channel codec.\n");
+ return SWITCH_STATUS_GENERR;
+ }
+
+ switch(codec) {
+ case ZAP_CODEC_ULAW:
+ {
+ dname = "PCMU";
+ }
+ break;
+ case ZAP_CODEC_ALAW:
+ {
+ dname = "PCMA";
+ }
+ break;
+ case ZAP_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);
+ return SWITCH_STATUS_GENERR;
+ }
+ }
+
+
+ if (switch_core_codec_init(&tech_pvt->read_codec,
+ dname,
+ NULL,
+ srate,
+ 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");
+ return SWITCH_STATUS_GENERR;
+ } else {
+ if (switch_core_codec_init(&tech_pvt->write_codec,
+ dname,
+ NULL,
+ srate,
+ 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);
+ return SWITCH_STATUS_GENERR;
+ }
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set codec %s %dms\n", dname, interval);
+ switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec);
+ switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec);
+ switch_set_flag_locked(tech_pvt, TFLAG_CODEC);
+ tech_pvt->read_frame.codec = &tech_pvt->read_codec;
+ switch_set_flag_locked(tech_pvt, TFLAG_IO);
+
+ return SWITCH_STATUS_SUCCESS;
+
+}
+
+static switch_status_t channel_on_init(switch_core_session_t *session)
+{
+ switch_channel_t *channel;
+ private_t *tech_pvt = NULL;
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ /* Move channel's state machine to ROUTING */
+ switch_channel_set_state(channel, CS_ROUTING);
+ switch_mutex_lock(globals.mutex);
+ globals.calls++;
+ switch_mutex_unlock(globals.mutex);
+
+ zap_channel_init(tech_pvt->zchan);
+
+ //switch_channel_set_flag(channel, CF_ACCEPT_CNG);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_routing(switch_core_session_t *session)
+{
+ switch_channel_t *channel = NULL;
+ private_t *tech_pvt = NULL;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n", switch_channel_get_name(channel));
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_execute(switch_core_session_t *session)
+{
+
+ switch_channel_t *channel = NULL;
+ private_t *tech_pvt = NULL;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL EXECUTE\n", switch_channel_get_name(channel));
+
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_destroy(switch_core_session_t *session)
+{
+ private_t *tech_pvt = NULL;
+
+ if ((tech_pvt = switch_core_session_get_private(session))) {
+
+ if (tech_pvt->read_codec.implementation) {
+ switch_core_codec_destroy(&tech_pvt->read_codec);
+ }
+
+ if (tech_pvt->write_codec.implementation) {
+ switch_core_codec_destroy(&tech_pvt->write_codec);
+ }
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_hangup(switch_core_session_t *session)
+{
+ switch_channel_t *channel = NULL;
+ private_t *tech_pvt = NULL;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ if (!tech_pvt->zchan) {
+ goto end;
+ }
+
+ zap_channel_clear_token(tech_pvt->zchan, switch_core_session_get_uuid(session));
+
+ switch (tech_pvt->zchan->type) {
+ case ZAP_CHAN_TYPE_FXO:
+ case ZAP_CHAN_TYPE_EM:
+ case ZAP_CHAN_TYPE_CAS:
+ {
+ zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ break;
+ case ZAP_CHAN_TYPE_FXS:
+ {
+ if (tech_pvt->zchan->state != ZAP_CHANNEL_STATE_BUSY && tech_pvt->zchan->state != ZAP_CHANNEL_STATE_DOWN) {
+ if (tech_pvt->zchan->token_count) {
+ cycle_foreground(tech_pvt->zchan, 0, NULL);
+ } else {
+ zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ }
+ }
+ break;
+ case ZAP_CHAN_TYPE_B:
+ {
+ if (tech_pvt->zchan->state != ZAP_CHANNEL_STATE_DOWN) {
+ if (tech_pvt->zchan->state != ZAP_CHANNEL_STATE_TERMINATING) {
+ tech_pvt->zchan->caller_data.hangup_cause = switch_channel_get_cause_q850(channel);
+ if (tech_pvt->zchan->caller_data.hangup_cause < 1 || tech_pvt->zchan->caller_data.hangup_cause > 127) {
+ tech_pvt->zchan->caller_data.hangup_cause = ZAP_CAUSE_DESTINATION_OUT_OF_ORDER;
+ }
+ }
+ zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ }
+ break;
+ default:
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Unhandled channel type %d for channel %s\n", tech_pvt->zchan->type,
+ switch_channel_get_name(channel));
+ }
+ break;
+ }
+
+ end:
+
+ switch_clear_flag_locked(tech_pvt, TFLAG_IO);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel));
+ switch_mutex_lock(globals.mutex);
+ globals.calls--;
+ if (globals.calls < 0) {
+ globals.calls = 0;
+ }
+ switch_mutex_unlock(globals.mutex);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig)
+{
+ switch_channel_t *channel = NULL;
+ private_t *tech_pvt = NULL;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ switch (sig) {
+ case SWITCH_SIG_KILL:
+ switch_clear_flag_locked(tech_pvt, TFLAG_IO);
+ switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+ break;
+ case SWITCH_SIG_BREAK:
+ switch_set_flag_locked(tech_pvt, TFLAG_BREAK);
+ break;
+ default:
+ break;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_exchange_media(switch_core_session_t *session)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CHANNEL EXCHANGE_MEDIA\n");
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_soft_execute(switch_core_session_t *session)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CHANNEL SOFT_EXECUTE\n");
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf)
+{
+ private_t *tech_pvt = NULL;
+ char tmp[2] = "";
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ switch_channel_hangup(switch_core_session_get_channel(session), SWITCH_CAUSE_LOSE_RACE);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ tmp[0] = dtmf->digit;
+ zap_channel_command(tech_pvt->zchan, ZAP_COMMAND_SEND_DTMF, tmp);
+
+ 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)
+{
+ switch_channel_t *channel = NULL;
+ private_t *tech_pvt = NULL;
+ zap_size_t len;
+ zap_wait_flag_t wflags = ZAP_READ;
+ char dtmf[128] = "";
+ zap_status_t status;
+ int total_to;
+ int chunk, do_break = 0;
+
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ /* Digium Cards sometimes timeout several times in a row here.
+ Yes, we support digium cards, ain't we nice.......
+ 6 double length intervals should compensate */
+ chunk = tech_pvt->zchan->effective_interval * 2;
+ total_to = chunk * 6;
+
+ top:
+
+ if (switch_channel_test_flag(channel, CF_SUSPEND)) {
+ do_break = 1;
+ }
+
+ if (switch_test_flag(tech_pvt, TFLAG_BREAK)) {
+ switch_clear_flag_locked(tech_pvt, TFLAG_BREAK);
+ do_break = 1;
+ }
+
+ if (switch_test_flag(tech_pvt, TFLAG_HOLD) || do_break) {
+ switch_yield(tech_pvt->zchan->effective_interval * 1000);
+ tech_pvt->cng_frame.datalen = tech_pvt->zchan->packet_len;
+ tech_pvt->cng_frame.samples = tech_pvt->cng_frame.datalen;
+ tech_pvt->cng_frame.flags = SFF_CNG;
+ *frame = &tech_pvt->cng_frame;
+ if (tech_pvt->zchan->effective_codec == ZAP_CODEC_SLIN) {
+ tech_pvt->cng_frame.samples /= 2;
+ }
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
+ goto fail;
+ }
+
+ wflags = ZAP_READ;
+ status = zap_channel_wait(tech_pvt->zchan, &wflags, chunk);
+
+ if (status == ZAP_FAIL) {
+ goto fail;
+ }
+
+ if (status == ZAP_TIMEOUT) {
+ if (!switch_test_flag(tech_pvt, TFLAG_HOLD)) {
+ total_to -= chunk;
+ if (total_to <= 0) {
+ goto fail;
+ }
+ }
+
+ goto top;
+ }
+
+ if (!(wflags & ZAP_READ)) {
+ goto fail;
+ }
+
+ len = tech_pvt->read_frame.buflen;
+ if (zap_channel_read(tech_pvt->zchan, tech_pvt->read_frame.data, &len) != ZAP_SUCCESS) {
+ goto fail;
+ }
+
+ *frame = &tech_pvt->read_frame;
+ tech_pvt->read_frame.datalen = (uint32_t)len;
+ tech_pvt->read_frame.samples = tech_pvt->read_frame.datalen;
+
+ if (tech_pvt->zchan->effective_codec == ZAP_CODEC_SLIN) {
+ tech_pvt->read_frame.samples /= 2;
+ }
+
+ while (zap_channel_dequeue_dtmf(tech_pvt->zchan, dtmf, sizeof(dtmf))) {
+ switch_dtmf_t _dtmf = { 0, SWITCH_DEFAULT_DTMF_DURATION };
+ char *p;
+ for (p = dtmf; p && *p; p++) {
+ if (is_dtmf(*p)) {
+ _dtmf.digit = *p;
+ zap_log(ZAP_LOG_DEBUG, "queue DTMF [%c]\n", *p);
+ switch_channel_queue_dtmf(channel, &_dtmf);
+ }
+ }
+ }
+ return SWITCH_STATUS_SUCCESS;
+
+ fail:
+ switch_clear_flag_locked(tech_pvt, TFLAG_IO);
+ 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)
+{
+ switch_channel_t *channel = NULL;
+ private_t *tech_pvt = NULL;
+ zap_size_t len;
+ unsigned char data[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0};
+ zap_wait_flag_t wflags = ZAP_WRITE;
+ zap_status_t status;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ if (!tech_pvt->zchan) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (switch_test_flag(tech_pvt, TFLAG_HOLD)) {
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
+ goto fail;
+ }
+
+ 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 = ZAP_WRITE;
+ status = zap_channel_wait(tech_pvt->zchan, &wflags, tech_pvt->zchan->effective_interval * 10);
+
+ if (!(wflags & ZAP_WRITE)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Dropping frame! (write not ready)\n");
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ len = frame->datalen;
+ if (zap_channel_write(tech_pvt->zchan, frame->data, frame->buflen, &len) != ZAP_SUCCESS) {
+ if (++tech_pvt->wr_error > 10) {
+ goto fail;
+ }
+ } else {
+ tech_pvt->wr_error = 0;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+
+ fail:
+
+ switch_clear_flag_locked(tech_pvt, TFLAG_IO);
+ return SWITCH_STATUS_GENERR;
+
+}
+
+static switch_status_t channel_receive_message_cas(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+ switch_channel_t *channel;
+ private_t *tech_pvt;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ tech_pvt = (private_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ zap_log(ZAP_LOG_DEBUG, "Got Freeswitch message in R2 channel %d [%d]\n", tech_pvt->zchan->physical_chan_id,
+ msg->message_id);
+
+ switch (msg->message_id) {
+ case SWITCH_MESSAGE_INDICATE_RINGING:
+ {
+ if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
+ } else {
+ zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS);
+ }
+ }
+ break;
+ case SWITCH_MESSAGE_INDICATE_PROGRESS:
+ {
+ if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
+ zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_MEDIA);
+ } else {
+ zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS);
+ zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS_MEDIA);
+ }
+ }
+ break;
+ case SWITCH_MESSAGE_INDICATE_ANSWER:
+ {
+ if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED);
+ } else {
+ /* lets make the ozmod_r2 module life easier by moving thru each
+ * state waiting for completion, clumsy, but does the job
+ */
+ if (tech_pvt->zchan->state < ZAP_CHANNEL_STATE_PROGRESS) {
+ zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS);
+ }
+ if (tech_pvt->zchan->state < ZAP_CHANNEL_STATE_PROGRESS_MEDIA) {
+ zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS_MEDIA);
+ }
+ zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_UP);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message_b(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+ switch_channel_t *channel;
+ private_t *tech_pvt;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ tech_pvt = (private_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (tech_pvt->zchan->state == ZAP_CHANNEL_STATE_TERMINATING) {
+ zap_mutex_unlock(tech_pvt->zchan->mutex);
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ switch (msg->message_id) {
+ case SWITCH_MESSAGE_INDICATE_RINGING:
+ {
+ if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
+ } else {
+ zap_set_state_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS);
+ }
+ }
+ break;
+ case SWITCH_MESSAGE_INDICATE_PROGRESS:
+ {
+ if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
+ zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_MEDIA);
+ } else {
+ /* Don't skip messages in the ISDN call setup
+ * TODO: make the isdn stack smart enough to handle that itself
+ * until then, this is here for safety...
+ */
+ if (tech_pvt->zchan->state < ZAP_CHANNEL_STATE_PROGRESS) {
+ zap_set_state_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS);
+ }
+ zap_set_state_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS_MEDIA);
+ }
+ }
+ break;
+ case SWITCH_MESSAGE_INDICATE_ANSWER:
+ {
+ if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED);
+ } else {
+ /* Don't skip messages in the ISDN call setup
+ * TODO: make the isdn stack smart enough to handle that itself
+ * until then, this is here for safety...
+ */
+ if (tech_pvt->zchan->state < ZAP_CHANNEL_STATE_PROGRESS) {
+ zap_set_state_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS);
+ }
+ if (tech_pvt->zchan->state < ZAP_CHANNEL_STATE_PROGRESS_MEDIA) {
+ zap_set_state_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS_MEDIA);
+ }
+ zap_set_state_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_UP);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message_fxo(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+ switch_channel_t *channel;
+ private_t *tech_pvt;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ tech_pvt = (private_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ switch (msg->message_id) {
+ case SWITCH_MESSAGE_INDICATE_PROGRESS:
+ case SWITCH_MESSAGE_INDICATE_ANSWER:
+ if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED);
+ zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
+ zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_MEDIA);
+ } else {
+ zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_UP);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message_fxs(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+ switch_channel_t *channel;
+ private_t *tech_pvt;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ tech_pvt = (private_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ switch (msg->message_id) {
+ case SWITCH_MESSAGE_INDICATE_PROGRESS:
+ case SWITCH_MESSAGE_INDICATE_ANSWER:
+ if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED);
+ zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
+ zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_MEDIA);
+ zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_UP);
+ switch_channel_mark_answered(channel);
+ }
+ break;
+ case SWITCH_MESSAGE_INDICATE_RINGING:
+ if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
+
+ if (!switch_channel_test_flag(channel, CF_ANSWERED) &&
+ !switch_channel_test_flag(channel, CF_EARLY_MEDIA) &&
+ !switch_channel_test_flag(channel, CF_RING_READY)
+ ) {
+ zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_RING);
+ switch_channel_mark_ring_ready(channel);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+ private_t *tech_pvt;
+ switch_status_t status;
+ switch_channel_t *channel;
+ const char *var;
+ zap_channel_t *zchan = NULL;
+
+ tech_pvt = (private_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ channel = switch_core_session_get_channel(session);
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (!(zchan = tech_pvt->zchan)) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ zap_mutex_lock(zchan->mutex);
+
+ if (!tech_pvt->zchan) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+ status = SWITCH_STATUS_FALSE;
+ goto end;
+ }
+
+ switch (msg->message_id) {
+ case SWITCH_MESSAGE_INDICATE_PROGRESS:
+ case SWITCH_MESSAGE_INDICATE_ANSWER:
+ if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ if ((var = switch_channel_get_variable(channel, "openzap_pre_buffer_size"))) {
+ int tmp = atoi(var);
+ if (tmp > -1) {
+ zap_channel_command(tech_pvt->zchan, ZAP_COMMAND_SET_PRE_BUFFER_SIZE, &tmp);
+ }
+ }
+ }
+ break;
+ case SWITCH_MESSAGE_INDICATE_UUID_CHANGE:
+ {
+ zap_channel_replace_token(tech_pvt->zchan, msg->string_array_arg[0], msg->string_array_arg[1]);
+ }
+ break;
+ default:
+ break;
+ }
+
+ switch (tech_pvt->zchan->type) {
+ case ZAP_CHAN_TYPE_FXS:
+ case ZAP_CHAN_TYPE_EM:
+ status = channel_receive_message_fxs(session, msg);
+ break;
+ case ZAP_CHAN_TYPE_FXO:
+ status = channel_receive_message_fxo(session, msg);
+ break;
+ case ZAP_CHAN_TYPE_B:
+ status = channel_receive_message_b(session, msg);
+ break;
+ case ZAP_CHAN_TYPE_CAS:
+ status = channel_receive_message_cas(session, msg);
+ break;
+ default:
+ status = SWITCH_STATUS_FALSE;
+ break;
+ }
+
+ end:
+
+ zap_mutex_unlock(zchan->mutex);
+
+ return status;
+
+}
+
+switch_state_handler_table_t openzap_state_handlers = {
+ /*.on_init */ channel_on_init,
+ /*.on_routing */ channel_on_routing,
+ /*.on_execute */ channel_on_execute,
+ /*.on_hangup */ channel_on_hangup,
+ /*.on_exchange_media */ channel_on_exchange_media,
+ /*.on_soft_execute */ channel_on_soft_execute,
+ /*.on_consume_media */ NULL,
+ /*.on_hibernate */ NULL,
+ /*.on_reset */ NULL,
+ /*.on_park*/ NULL,
+ /*.on_reporting*/ NULL,
+ /*.on_destroy*/ channel_on_destroy
+
+};
+
+switch_io_routines_t openzap_io_routines = {
+ /*.outgoing_channel */ channel_outgoing_channel,
+ /*.read_frame */ channel_read_frame,
+ /*.write_frame */ channel_write_frame,
+ /*.kill_channel */ channel_kill_channel,
+ /*.send_dtmf */ channel_send_dtmf,
+ /*.receive_message*/ channel_receive_message
+};
+
+/* Make sure when you have 2 sessions in the same scope that you pass the appropriate one to the routines
+that allocate memory or you will have 1 channel with memory allocated from another channel's pool!
+*/
+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 *dest = NULL;
+ char *data = NULL;
+ int span_id = -1, chan_id = 0;
+ zap_channel_t *zchan = NULL;
+ switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ char name[128];
+ zap_status_t status;
+ int direction = ZAP_TOP_DOWN;
+ zap_caller_data_t caller_data = {{ 0 }};
+ char *span_name = NULL;
+ switch_event_header_t *h;
+ char *argv[3];
+ int argc = 0;
+ const char *var;
+ const char *dest_num = NULL, *callerid_num = NULL;
+
+ if (!outbound_profile) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing caller profile\n");
+ return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ }
+
+ if (zstr(outbound_profile->destination_number)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid dial string\n");
+ return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ }
+
+
+ data = switch_core_strdup(outbound_profile->pool, outbound_profile->destination_number);
+
+ if (!zstr(outbound_profile->destination_number)) {
+ dest_num = switch_sanitize_number(switch_core_strdup(outbound_profile->pool, outbound_profile->destination_number));
+ }
+
+ if (!zstr(outbound_profile->caller_id_number)) {
+ callerid_num = switch_sanitize_number(switch_core_strdup(outbound_profile->pool, outbound_profile->caller_id_number));
+ }
+
+ if (!zstr(callerid_num) && !strcmp(callerid_num, "0000000000")) {
+ callerid_num = NULL;
+ }
+
+ if ((argc = switch_separate_string(data, '/', argv, (sizeof(argv) / sizeof(argv[0])))) < 2) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid dial string\n");
+ return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ }
+
+ if (switch_is_number(argv[0])) {
+ span_id = atoi(argv[0]);
+ } else {
+ span_name = argv[0];
+ }
+
+ if (*argv[1] == 'A') {
+ direction = ZAP_BOTTOM_UP;
+ } else if (*argv[1] == 'a') {
+ direction = ZAP_TOP_DOWN;
+ } else {
+ chan_id = atoi(argv[1]);
+ }
+
+ if (!(dest = argv[2])) {
+ dest = "";
+ }
+
+ if (span_id == 0 && chan_id != 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Span 0 is used to pick the first available span, selecting a channel is not supported (and doesn't make sense)\n");
+ return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ }
+
+ if (span_id == -1 && !zstr(span_name)) {
+ zap_span_t *span;
+ zap_status_t zstatus = zap_span_find_by_name(span_name, &span);
+ if (zstatus == ZAP_SUCCESS && span) {
+ span_id = span->span_id;
+ }
+ }
+
+ if (span_id == -1) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing span\n");
+ return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ }
+
+ if (chan_id < 0) {
+ direction = ZAP_BOTTOM_UP;
+ chan_id = 0;
+ }
+
+ if (switch_test_flag(outbound_profile, SWITCH_CPF_SCREEN)) {
+ caller_data.screen = 1;
+ }
+
+ if (switch_test_flag(outbound_profile, SWITCH_CPF_HIDE_NUMBER)) {
+ caller_data.pres = 1;
+ }
+
+ if (!zstr(dest)) {
+ zap_set_string(caller_data.ani.digits, dest);
+ }
+
+ if ((var = switch_event_get_header(var_event, "openzap_outbound_ton")) || (var = switch_core_get_variable("openzap_outbound_ton"))) {
+ if (!strcasecmp(var, "national")) {
+ caller_data.ani.type = ZAP_TON_NATIONAL;
+ } else if (!strcasecmp(var, "international")) {
+ caller_data.ani.type = ZAP_TON_INTERNATIONAL;
+ } else if (!strcasecmp(var, "local")) {
+ caller_data.ani.type = ZAP_TON_SUBSCRIBER_NUMBER;
+ } else if (!strcasecmp(var, "unknown")) {
+ caller_data.ani.type = ZAP_TON_UNKNOWN;
+ }
+ } else {
+ caller_data.ani.type = outbound_profile->destination_number_ton;
+ }
+
+ caller_data.ani.plan = outbound_profile->destination_number_numplan;
+
+ /* blindly copy data from outbound_profile. They will be overwritten
+ * by calling zap_caller_data if needed after */
+ caller_data.cid_num.type = outbound_profile->caller_ton;
+ caller_data.cid_num.plan = outbound_profile->caller_numplan;
+
+ caller_data.rdnis.type = outbound_profile->rdnis_ton;
+ caller_data.rdnis.plan = outbound_profile->rdnis_numplan;
+
+#if 0
+ if (!zstr(outbound_profile->rdnis)) {
+ zap_set_string(caller_data.rdnis.digits, outbound_profile->rdnis);
+ }
+#endif
+
+ zap_set_string(caller_data.cid_name, outbound_profile->caller_id_name);
+ zap_set_string(caller_data.cid_num.digits, switch_str_nil(callerid_num));
+
+ if (chan_id) {
+ status = zap_channel_open(span_id, chan_id, &zchan);
+ } else {
+ status = zap_channel_open_any(span_id, direction, &caller_data, &zchan);
+ }
+
+ if (status != ZAP_SUCCESS) {
+ if (caller_data.hangup_cause == SWITCH_CAUSE_NONE) {
+ caller_data.hangup_cause = SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+ }
+ return caller_data.hangup_cause;
+ }
+
+ if ((var = switch_event_get_header(var_event, "openzap_pre_buffer_size"))) {
+ int tmp = atoi(var);
+ if (tmp > -1) {
+ zap_channel_command(zchan, ZAP_COMMAND_SET_PRE_BUFFER_SIZE, &tmp);
+ }
+ }
+
+ zap_channel_clear_vars(zchan);
+ for (h = var_event->headers; h; h = h->next) {
+ if (!strncasecmp(h->name, OPENZAP_VAR_PREFIX, OPENZAP_VAR_PREFIX_LEN)) {
+ char *v = h->name + OPENZAP_VAR_PREFIX_LEN;
+ if (!zstr(v)) {
+ zap_channel_add_var(zchan, v, h->value);
+ }
+ }
+ }
+
+ if ((*new_session = switch_core_session_request(openzap_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, pool)) != 0) {
+ private_t *tech_pvt;
+ switch_caller_profile_t *caller_profile;
+ switch_channel_t *channel = switch_core_session_get_channel(*new_session);
+
+ switch_core_session_add_stream(*new_session, NULL);
+ if ((tech_pvt = (private_t *) switch_core_session_alloc(*new_session, sizeof(private_t))) != 0) {
+ tech_init(tech_pvt, *new_session, zchan);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Hey where is my memory pool?\n");
+ switch_core_session_destroy(new_session);
+ cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ goto fail;
+ }
+
+ snprintf(name, sizeof(name), "OpenZAP/%u:%u/%s", zchan->span_id, zchan->chan_id, dest);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connect outbound channel %s\n", name);
+ switch_channel_set_name(channel, name);
+ switch_channel_set_variable(channel, "openzap_span_name", zchan->span->name);
+ switch_channel_set_variable_printf(channel, "openzap_span_number", "%d", zchan->span_id);
+ switch_channel_set_variable_printf(channel, "openzap_chan_number", "%d", zchan->chan_id);
+ zap_channel_set_caller_data(zchan, &caller_data);
+ caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
+ caller_profile->destination_number = switch_core_strdup(caller_profile->pool, switch_str_nil(dest_num));
+ caller_profile->caller_id_number = switch_core_strdup(caller_profile->pool, switch_str_nil(callerid_num));
+ switch_channel_set_caller_profile(channel, caller_profile);
+ tech_pvt->caller_profile = caller_profile;
+
+
+ switch_channel_set_flag(channel, CF_OUTBOUND);
+ switch_channel_set_state(channel, CS_INIT);
+ if (zap_channel_add_token(zchan, switch_core_session_get_uuid(*new_session), zchan->token_count) != ZAP_SUCCESS) {
+ switch_core_session_destroy(new_session);
+ cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ goto fail;
+ }
+
+
+ if (zap_channel_outgoing_call(zchan) != ZAP_SUCCESS) {
+ 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);
+ }
+ switch_core_session_destroy(new_session);
+ cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ goto fail;
+ }
+
+ zap_channel_init(zchan);
+
+ return SWITCH_CAUSE_SUCCESS;
+ }
+
+ fail:
+
+ if (zchan) {
+ zap_channel_done(zchan);
+ }
+
+ return cause;
+
+}
+
+zap_status_t zap_channel_from_event(zap_sigmsg_t *sigmsg, switch_core_session_t **sp)
+{
+ switch_core_session_t *session = NULL;
+ private_t *tech_pvt = NULL;
+ switch_channel_t *channel = NULL;
+ char name[128];
+
+ *sp = NULL;
+
+ if (!(session = switch_core_session_request(openzap_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, NULL))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Initilization Error!\n");
+ return ZAP_FAIL;
+ }
+
+ switch_core_session_add_stream(session, NULL);
+
+ tech_pvt = (private_t *) switch_core_session_alloc(session, sizeof(private_t));
+ assert(tech_pvt != NULL);
+ channel = switch_core_session_get_channel(session);
+ if (tech_init(tech_pvt, session, sigmsg->channel) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Initilization Error!\n");
+ switch_core_session_destroy(&session);
+ return ZAP_FAIL;
+ }
+
+ *sigmsg->channel->caller_data.collected = '\0';
+
+ if (zstr(sigmsg->channel->caller_data.cid_name)) {
+ switch_set_string(sigmsg->channel->caller_data.cid_name, sigmsg->channel->chan_name);
+ }
+
+ if (zstr(sigmsg->channel->caller_data.cid_num.digits)) {
+ if (!zstr(sigmsg->channel->caller_data.ani.digits)) {
+ switch_set_string(sigmsg->channel->caller_data.cid_num.digits, sigmsg->channel->caller_data.ani.digits);
+ } else {
+ switch_set_string(sigmsg->channel->caller_data.cid_num.digits, sigmsg->channel->chan_number);
+ }
+ }
+
+ tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
+ "OpenZAP",
+ SPAN_CONFIG[sigmsg->channel->span_id].dialplan,
+ sigmsg->channel->caller_data.cid_name,
+ sigmsg->channel->caller_data.cid_num.digits,
+ NULL,
+ sigmsg->channel->caller_data.ani.digits,
+ sigmsg->channel->caller_data.aniII,
+ sigmsg->channel->caller_data.rdnis.digits,
+ (char *) modname,
+ SPAN_CONFIG[sigmsg->channel->span_id].context,
+ sigmsg->channel->caller_data.dnis.digits);
+
+ assert(tech_pvt->caller_profile != NULL);
+
+ if (sigmsg->channel->caller_data.screen == 1 || sigmsg->channel->caller_data.screen == 3) {
+ switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_SCREEN);
+ }
+
+ tech_pvt->caller_profile->caller_ton = sigmsg->channel->caller_data.cid_num.type;
+ tech_pvt->caller_profile->caller_numplan = sigmsg->channel->caller_data.cid_num.plan;
+ tech_pvt->caller_profile->ani_ton = sigmsg->channel->caller_data.ani.type;
+ tech_pvt->caller_profile->ani_numplan = sigmsg->channel->caller_data.ani.plan;
+ tech_pvt->caller_profile->destination_number_ton = sigmsg->channel->caller_data.dnis.type;
+ tech_pvt->caller_profile->destination_number_numplan = sigmsg->channel->caller_data.dnis.plan;
+ tech_pvt->caller_profile->rdnis_ton = sigmsg->channel->caller_data.rdnis.type;
+ tech_pvt->caller_profile->rdnis_numplan = sigmsg->channel->caller_data.rdnis.plan;
+
+ if (sigmsg->channel->caller_data.pres) {
+ switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER);
+ }
+
+ snprintf(name, sizeof(name), "OpenZAP/%u:%u/%s", sigmsg->channel->span_id, sigmsg->channel->chan_id, tech_pvt->caller_profile->destination_number);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connect inbound channel %s\n", name);
+ switch_channel_set_name(channel, name);
+ switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
+
+ switch_channel_set_variable(channel, "openzap_span_name", sigmsg->channel->span->name);
+ switch_channel_set_variable_printf(channel, "openzap_span_number", "%d", sigmsg->channel->span_id);
+ switch_channel_set_variable_printf(channel, "openzap_chan_number", "%d", sigmsg->channel->chan_id);
+
+ switch_channel_set_state(channel, CS_INIT);
+ if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error spawning thread\n");
+ switch_core_session_destroy(&session);
+ return ZAP_FAIL;
+ }
+
+ if (zap_channel_add_token(sigmsg->channel, switch_core_session_get_uuid(session), 0) != ZAP_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error adding token\n");
+ switch_core_session_destroy(&session);
+ return ZAP_FAIL;
+ }
+ *sp = session;
+
+ return ZAP_SUCCESS;
+}
+
+static ZIO_SIGNAL_CB_FUNCTION(on_common_signal)
+{
+ switch_event_t *event = NULL;
+
+ switch (sigmsg->event_id) {
+
+ case ZAP_SIGEVENT_ALARM_CLEAR:
+ case ZAP_SIGEVENT_ALARM_TRAP:
+ {
+ if (zap_channel_get_alarms(sigmsg->channel) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "failed to retrieve alarms\n");
+ return ZAP_FAIL;
+ }
+ if (switch_event_create(&event, SWITCH_EVENT_TRAP) != SWITCH_STATUS_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "failed to create alarms events\n");
+ return ZAP_FAIL;
+ }
+ if (sigmsg->event_id == ZAP_SIGEVENT_ALARM_CLEAR) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "zap-alarm-clear");
+ } else {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "zap-alarm-trap");
+ }
+ }
+ break;
+ default:
+ return ZAP_SUCCESS;
+ break;
+ }
+
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-name", "%s", sigmsg->channel->span->name);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-number", "%d", sigmsg->channel->span_id);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", sigmsg->channel->chan_id);
+
+ if (zap_test_alarm_flag(sigmsg->channel, ZAP_ALARM_RECOVER)) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "recover");
+ }
+ if (zap_test_alarm_flag(sigmsg->channel, ZAP_ALARM_LOOPBACK)) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "loopback");
+ }
+ if (zap_test_alarm_flag(sigmsg->channel, ZAP_ALARM_YELLOW)) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "yellow");
+ }
+ if (zap_test_alarm_flag(sigmsg->channel, ZAP_ALARM_RED)) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "red");
+ }
+ if (zap_test_alarm_flag(sigmsg->channel, ZAP_ALARM_BLUE)) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "blue");
+ }
+ if (zap_test_alarm_flag(sigmsg->channel, ZAP_ALARM_NOTOPEN)) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "notopen");
+ }
+ if (zap_test_alarm_flag(sigmsg->channel, ZAP_ALARM_AIS)) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "ais");
+ }
+ if (zap_test_alarm_flag(sigmsg->channel, ZAP_ALARM_RAI)) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "rai");
+ }
+ if (zap_test_alarm_flag(sigmsg->channel, ZAP_ALARM_GENERAL)) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "general");
+ }
+ switch_event_fire(&event);
+
+ return ZAP_BREAK;
+}
+
+static ZIO_SIGNAL_CB_FUNCTION(on_fxo_signal)
+{
+ switch_core_session_t *session = NULL;
+ switch_channel_t *channel = NULL;
+ zap_status_t status;
+
+ zap_log(ZAP_LOG_DEBUG, "got FXO sig %d:%d [%s]\n", sigmsg->channel->span_id, sigmsg->channel->chan_id, zap_signal_event2str(sigmsg->event_id));
+
+ switch(sigmsg->event_id) {
+
+ case ZAP_SIGEVENT_PROGRESS_MEDIA:
+ {
+ if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_mark_pre_answered(channel);
+ switch_core_session_rwunlock(session);
+ }
+ }
+ break;
+ case ZAP_SIGEVENT_STOP:
+ {
+ private_t *tech_pvt = NULL;
+ while((session = zap_channel_get_session(sigmsg->channel, 0))) {
+ tech_pvt = switch_core_session_get_private(session);
+ switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+ zap_channel_clear_token(sigmsg->channel, 0);
+ channel = switch_core_session_get_channel(session);
+ switch_channel_hangup(channel, sigmsg->channel->caller_data.hangup_cause);
+ zap_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+ switch_core_session_rwunlock(session);
+ }
+ }
+ break;
+ case ZAP_SIGEVENT_UP:
+ {
+ if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_mark_answered(channel);
+ switch_core_session_rwunlock(session);
+ }
+ }
+ break;
+ case ZAP_SIGEVENT_START:
+ {
+ status = zap_channel_from_event(sigmsg, &session);
+ if (status != ZAP_SUCCESS) {
+ zap_set_state_locked(sigmsg->channel, ZAP_CHANNEL_STATE_DOWN);
+ }
+ }
+ break;
+
+ default:
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled msg type %d for channel %d:%d\n",
+ sigmsg->event_id, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+ }
+ break;
+
+ }
+
+ return ZAP_SUCCESS;
+}
+
+static ZIO_SIGNAL_CB_FUNCTION(on_fxs_signal)
+{
+ switch_core_session_t *session = NULL;
+ switch_channel_t *channel = NULL;
+ zap_status_t status = ZAP_SUCCESS;
+
+ zap_log(ZAP_LOG_DEBUG, "got FXS sig [%s]\n", zap_signal_event2str(sigmsg->event_id));
+
+ switch(sigmsg->event_id) {
+ case ZAP_SIGEVENT_UP:
+ {
+ if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_mark_answered(channel);
+ switch_core_session_rwunlock(session);
+ }
+ }
+ break;
+ case ZAP_SIGEVENT_PROGRESS:
+ {
+ if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_mark_ring_ready(channel);
+ switch_core_session_rwunlock(session);
+ }
+ }
+ break;
+ case ZAP_SIGEVENT_START:
+ {
+ zap_clear_flag_locked(sigmsg->channel, ZAP_CHANNEL_HOLD);
+ status = zap_channel_from_event(sigmsg, &session);
+ if (status != ZAP_SUCCESS) {
+ zap_set_state_locked(sigmsg->channel, ZAP_CHANNEL_STATE_BUSY);
+ }
+ }
+ break;
+ case ZAP_SIGEVENT_STOP:
+ {
+ private_t *tech_pvt = NULL;
+ switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
+ if (sigmsg->channel->token_count) {
+ switch_core_session_t *session_a, *session_b, *session_t = NULL;
+ switch_channel_t *channel_a = NULL, *channel_b = NULL;
+ int digits = !zstr(sigmsg->channel->caller_data.collected);
+ const char *br_a_uuid = NULL, *br_b_uuid = NULL;
+ private_t *tech_pvt = NULL;
+
+
+ if ((session_a = switch_core_session_locate(sigmsg->channel->tokens[0]))) {
+ channel_a = switch_core_session_get_channel(session_a);
+ br_a_uuid = switch_channel_get_variable(channel_a, SWITCH_SIGNAL_BOND_VARIABLE);
+
+ tech_pvt = switch_core_session_get_private(session_a);
+ stop_hold(session_a, switch_channel_get_variable(channel_a, SWITCH_SIGNAL_BOND_VARIABLE));
+ switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+ }
+
+ if ((session_b = switch_core_session_locate(sigmsg->channel->tokens[1]))) {
+ channel_b = switch_core_session_get_channel(session_b);
+ br_b_uuid = switch_channel_get_variable(channel_b, SWITCH_SIGNAL_BOND_VARIABLE);
+
+ tech_pvt = switch_core_session_get_private(session_b);
+ stop_hold(session_a, switch_channel_get_variable(channel_b, SWITCH_SIGNAL_BOND_VARIABLE));
+ switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+ }
+
+ if (channel_a && channel_b && !switch_channel_test_flag(channel_a, CF_OUTBOUND) && !switch_channel_test_flag(channel_b, CF_OUTBOUND)) {
+ cause = SWITCH_CAUSE_ATTENDED_TRANSFER;
+ if (br_a_uuid && br_b_uuid) {
+ switch_ivr_uuid_bridge(br_a_uuid, br_b_uuid);
+ } else if (br_a_uuid && digits) {
+ session_t = switch_core_session_locate(br_a_uuid);
+ } else if (br_b_uuid && digits) {
+ session_t = switch_core_session_locate(br_b_uuid);
+ }
+ }
+
+ if (session_t) {
+ switch_ivr_session_transfer(session_t, sigmsg->channel->caller_data.collected, NULL, NULL);
+ switch_core_session_rwunlock(session_t);
+ }
+
+ if (session_a) {
+ switch_core_session_rwunlock(session_a);
+ }
+
+ if (session_b) {
+ switch_core_session_rwunlock(session_b);
+ }
+
+
+ }
+
+ while((session = zap_channel_get_session(sigmsg->channel, 0))) {
+ tech_pvt = switch_core_session_get_private(session);
+ switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+ channel = switch_core_session_get_channel(session);
+ switch_channel_hangup(channel, cause);
+ zap_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+ switch_core_session_rwunlock(session);
+ }
+ zap_channel_clear_token(sigmsg->channel, NULL);
+
+ }
+ break;
+
+ case ZAP_SIGEVENT_ADD_CALL:
+ {
+ cycle_foreground(sigmsg->channel, 1, NULL);
+ }
+ break;
+ case ZAP_SIGEVENT_FLASH:
+ {
+
+ if (zap_test_flag(sigmsg->channel, ZAP_CHANNEL_HOLD) && sigmsg->channel->token_count == 1) {
+ switch_core_session_t *session;
+ if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+ const char *buuid;
+ switch_channel_t *channel;
+ private_t *tech_pvt;
+
+ tech_pvt = switch_core_session_get_private(session);
+ channel = switch_core_session_get_channel(session);
+ buuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
+ zap_set_state_locked(sigmsg->channel, ZAP_CHANNEL_STATE_UP);
+ stop_hold(session, buuid);
+ switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+ switch_core_session_rwunlock(session);
+ }
+ } else if (sigmsg->channel->token_count == 2 && (SPAN_CONFIG[sigmsg->span_id].analog_options & ANALOG_OPTION_3WAY)) {
+ if (zap_test_flag(sigmsg->channel, ZAP_CHANNEL_3WAY)) {
+ zap_clear_flag(sigmsg->channel, ZAP_CHANNEL_3WAY);
+ if ((session = zap_channel_get_session(sigmsg->channel, 1))) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+ zap_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+ switch_core_session_rwunlock(session);
+ }
+ cycle_foreground(sigmsg->channel, 1, NULL);
+ } else {
+ char *cmd;
+ cmd = switch_mprintf("three_way::%s", sigmsg->channel->tokens[0]);
+ zap_set_flag(sigmsg->channel, ZAP_CHANNEL_3WAY);
+ cycle_foreground(sigmsg->channel, 1, cmd);
+ free(cmd);
+ }
+ } else if ((SPAN_CONFIG[sigmsg->span_id].analog_options & ANALOG_OPTION_CALL_SWAP)
+ || (SPAN_CONFIG[sigmsg->span_id].analog_options & ANALOG_OPTION_3WAY)
+ ) {
+ cycle_foreground(sigmsg->channel, 1, NULL);
+ if (sigmsg->channel->token_count == 1) {
+ zap_set_flag_locked(sigmsg->channel, ZAP_CHANNEL_HOLD);
+ zap_set_state_locked(sigmsg->channel, ZAP_CHANNEL_STATE_DIALTONE);
+ }
+ }
+
+ }
+ break;
+
+ case ZAP_SIGEVENT_COLLECTED_DIGIT:
+ {
+ char *dtmf = sigmsg->raw_data;
+ char *regex = SPAN_CONFIG[sigmsg->channel->span->span_id].dial_regex;
+ char *fail_regex = SPAN_CONFIG[sigmsg->channel->span->span_id].fail_dial_regex;
+
+ if (zstr(regex)) {
+ regex = NULL;
+ }
+
+ if (zstr(fail_regex)) {
+ fail_regex = NULL;
+ }
+
+ zap_log(ZAP_LOG_DEBUG, "got DTMF sig [%s]\n", dtmf);
+ switch_set_string(sigmsg->channel->caller_data.collected, dtmf);
+
+ if ((regex || fail_regex) && !zstr(dtmf)) {
+ switch_regex_t *re = NULL;
+ int ovector[30];
+ int match = 0;
+
+ if (fail_regex) {
+ match = switch_regex_perform(dtmf, fail_regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
+ status = match ? ZAP_SUCCESS : ZAP_BREAK;
+ switch_regex_safe_free(re);
+ }
+
+ if (status == ZAP_SUCCESS && regex) {
+ match = switch_regex_perform(dtmf, regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
+ status = match ? ZAP_BREAK : ZAP_SUCCESS;
+ }
+
+ switch_regex_safe_free(re);
+ }
+
+ }
+ break;
+
+ default:
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled msg type %d for channel %d:%d\n",
+ sigmsg->event_id, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+ }
+ break;
+
+ }
+
+ return status;
+}
+
+static ZIO_SIGNAL_CB_FUNCTION(on_r2_signal)
+{
+ switch_core_session_t *session = NULL;
+ switch_channel_t *channel = NULL;
+ zap_status_t status = ZAP_SUCCESS;
+
+ zap_log(ZAP_LOG_DEBUG, "Got R2 channel sig [%s] in channel %d\n", zap_signal_event2str(sigmsg->event_id), sigmsg->channel->physical_chan_id);
+
+ if (on_common_signal(sigmsg) == ZAP_BREAK) {
+ return ZAP_SUCCESS;
+ }
+
+ switch(sigmsg->event_id) {
+ /* on_call_disconnect from the R2 side */
+ case ZAP_SIGEVENT_STOP:
+ {
+ private_t *tech_pvt = NULL;
+ while((session = zap_channel_get_session(sigmsg->channel, 0))) {
+ tech_pvt = switch_core_session_get_private(session);
+ switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+ channel = switch_core_session_get_channel(session);
+ switch_channel_hangup(channel, sigmsg->channel->caller_data.hangup_cause);
+ zap_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+ switch_core_session_rwunlock(session);
+ }
+ }
+ break;
+
+ /* on_call_offered from the R2 side */
+ case ZAP_SIGEVENT_START:
+ {
+ status = zap_channel_from_event(sigmsg, &session);
+ }
+ break;
+
+ /* on DNIS received from the R2 forward side, return status == ZAP_BREAK to stop requesting DNIS */
+ case ZAP_SIGEVENT_COLLECTED_DIGIT:
+ {
+ char *regex = SPAN_CONFIG[sigmsg->channel->span->span_id].dial_regex;
+ char *fail_regex = SPAN_CONFIG[sigmsg->channel->span->span_id].fail_dial_regex;
+
+ if (zstr(regex)) {
+ regex = NULL;
+ }
+
+ if (zstr(fail_regex)) {
+ fail_regex = NULL;
+ }
+
+ zap_log(ZAP_LOG_DEBUG, "R2 DNIS so far [%s]\n", sigmsg->channel->caller_data.dnis.digits);
+
+ if ((regex || fail_regex) && !zstr(sigmsg->channel->caller_data.dnis.digits)) {
+ switch_regex_t *re = NULL;
+ int ovector[30];
+ int match = 0;
+
+ if (fail_regex) {
+ match = switch_regex_perform(sigmsg->channel->caller_data.dnis.digits, fail_regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
+ status = match ? ZAP_SUCCESS : ZAP_BREAK;
+ switch_regex_safe_free(re);
+ }
+
+ if (status == ZAP_SUCCESS && regex) {
+ match = switch_regex_perform(sigmsg->channel->caller_data.dnis.digits, regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
+ status = match ? ZAP_BREAK : ZAP_SUCCESS;
+ }
+
+ switch_regex_safe_free(re);
+ }
+ }
+ break;
+
+ case ZAP_SIGEVENT_PROGRESS:
+ {
+ if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_mark_ring_ready(channel);
+ switch_core_session_rwunlock(session);
+ }
+ }
+ break;
+
+ case ZAP_SIGEVENT_UP:
+ {
+ if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+ zap_tone_type_t tt = ZAP_TONE_DTMF;
+ channel = switch_core_session_get_channel(session);
+ switch_channel_mark_answered(channel);
+ if (zap_channel_command(sigmsg->channel, ZAP_COMMAND_ENABLE_DTMF_DETECT, &tt) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Failed to enable DTMF detection in R2 channel %d:%d\n", sigmsg->channel->span_id, sigmsg->channel->chan_id);
+ }
+ switch_core_session_rwunlock(session);
+ }
+ }
+ break;
+
+ default:
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled event %d from R2 for channel %d:%d\n",
+ sigmsg->event_id, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+ }
+ break;
+ }
+
+ return status;
+}
+
+static ZIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal)
+{
+ switch_core_session_t *session = NULL;
+ switch_channel_t *channel = NULL;
+
+ zap_log(ZAP_LOG_DEBUG, "got clear channel sig [%s]\n", zap_signal_event2str(sigmsg->event_id));
+
+ if (on_common_signal(sigmsg) == ZAP_BREAK) {
+ return ZAP_SUCCESS;
+ }
+
+ switch(sigmsg->event_id) {
+ case ZAP_SIGEVENT_START:
+ {
+ zap_tone_type_t tt = ZAP_TONE_DTMF;
+
+ if (zap_channel_command(sigmsg->channel, ZAP_COMMAND_ENABLE_DTMF_DETECT, &tt) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "TONE ERROR\n");
+ }
+
+ return zap_channel_from_event(sigmsg, &session);
+ }
+ break;
+ case ZAP_SIGEVENT_STOP:
+ case ZAP_SIGEVENT_RESTART:
+ {
+ private_t *tech_pvt = NULL;
+ while((session = zap_channel_get_session(sigmsg->channel, 0))) {
+ tech_pvt = switch_core_session_get_private(session);
+ switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+ channel = switch_core_session_get_channel(session);
+ switch_channel_hangup(channel, sigmsg->channel->caller_data.hangup_cause);
+ zap_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+ switch_core_session_rwunlock(session);
+ }
+ }
+ break;
+ case ZAP_SIGEVENT_UP:
+ {
+ if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+ zap_tone_type_t tt = ZAP_TONE_DTMF;
+ channel = switch_core_session_get_channel(session);
+ switch_channel_mark_answered(channel);
+ if (zap_channel_command(sigmsg->channel, ZAP_COMMAND_ENABLE_DTMF_DETECT, &tt) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "TONE ERROR\n");
+ }
+ switch_core_session_rwunlock(session);
+ } else {
+ const char *uuid = zap_channel_get_uuid(sigmsg->channel, 0);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Session for channel %d:%d not found [UUID: %s]\n",
+ sigmsg->channel->span_id, sigmsg->channel->chan_id, (uuid) ? uuid : "N/A");
+ }
+ }
+ case ZAP_SIGEVENT_PROGRESS_MEDIA:
+ {
+ if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_mark_pre_answered(channel);
+ switch_core_session_rwunlock(session);
+ } else {
+ const char *uuid = zap_channel_get_uuid(sigmsg->channel, 0);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Session for channel %d:%d not found [UUID: %s]\n",
+ sigmsg->channel->span_id, sigmsg->channel->chan_id, (uuid) ? uuid : "N/A");
+ }
+ }
+ break;
+ case ZAP_SIGEVENT_PROGRESS:
+ {
+ if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_mark_ring_ready(channel);
+ switch_core_session_rwunlock(session);
+ } else {
+ const char *uuid = zap_channel_get_uuid(sigmsg->channel, 0);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Session for channel %d:%d not found [UUID: %s]\n",
+ sigmsg->channel->span_id, sigmsg->channel->chan_id, (uuid) ? uuid : "N/A");
+ }
+ }
+ break;
+
+ default:
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled msg type %d for channel %d:%d\n",
+ sigmsg->event_id, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+ }
+ break;
+ }
+
+ return ZAP_SUCCESS;
+}
+
+
+static ZIO_SIGNAL_CB_FUNCTION(on_analog_signal)
+{
+ switch_status_t status = SWITCH_STATUS_FALSE;
+
+ if (on_common_signal(sigmsg) == ZAP_BREAK) {
+ return ZAP_SUCCESS;
+ }
+
+ switch (sigmsg->channel->type) {
+ case ZAP_CHAN_TYPE_FXO:
+ case ZAP_CHAN_TYPE_EM:
+ {
+ status = on_fxo_signal(sigmsg);
+ }
+ break;
+ case ZAP_CHAN_TYPE_FXS:
+ {
+ status = on_fxs_signal(sigmsg);
+ }
+ break;
+ default:
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled analog channel type %d for channel %d:%d\n",
+ sigmsg->channel->type, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+ }
+ break;
+ }
+
+ return status;
+}
+
+static void zap_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
+{
+ char *data = NULL;
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ if (switch_vasprintf(&data, fmt, ap) != -1) {
+ switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, (char *)func, line, NULL, level, "%s", data);
+ free(data);
+ }
+
+ va_end(ap);
+
+}
+
+static uint32_t enable_analog_option(const char *str, uint32_t current_options)
+{
+ if (!strcasecmp(str, "3-way")) {
+ current_options |= ANALOG_OPTION_3WAY;
+ current_options &= ~ANALOG_OPTION_CALL_SWAP;
+ } else if (!strcasecmp(str, "call-swap")) {
+ current_options |= ANALOG_OPTION_CALL_SWAP;
+ current_options &= ~ANALOG_OPTION_3WAY;
+ }
+
+ return current_options;
+
+}
+
+static switch_status_t load_config(void)
+{
+ const char *cf = "openzap.conf";
+ switch_xml_t cfg, xml, settings, param, spans, myspan;
+
+ memset(&globals, 0, sizeof(globals));
+ switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, module_pool);
+ if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf);
+ return SWITCH_STATUS_TERM;
+ }
+
+ if ((settings = switch_xml_child(cfg, "settings"))) {
+ for (param = switch_xml_child(settings, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+
+ if (!strcasecmp(var, "debug")) {
+ globals.debug = atoi(val);
+ } else if (!strcasecmp(var, "hold-music")) {
+ switch_set_string(globals.hold_music, val);
+ } else if (!strcasecmp(var, "enable-analog-option")) {
+ globals.analog_options = enable_analog_option(val, globals.analog_options);
+ }
+ }
+ }
+
+ if ((spans = switch_xml_child(cfg, "analog_spans"))) {
+ for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+ char *id = (char *) switch_xml_attr(myspan, "id");
+ char *name = (char *) switch_xml_attr(myspan, "name");
+ zap_status_t zstatus = ZAP_FAIL;
+ const char *context = "default";
+ const char *dialplan = "XML";
+ const char *tonegroup = NULL;
+ char *digit_timeout = NULL;
+ char *max_digits = NULL;
+ char *hotline = NULL;
+ char *dial_regex = NULL;
+ char *hold_music = NULL;
+ char *fail_dial_regex = NULL;
+ const char *enable_callerid = "true";
+
+ uint32_t span_id = 0, to = 0, max = 0;
+ zap_span_t *span = NULL;
+ analog_option_t analog_options = ANALOG_OPTION_NONE;
+
+ for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+
+ if (!strcasecmp(var, "tonegroup")) {
+ tonegroup = val;
+ } else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "digit-timeout")) {
+ digit_timeout = val;
+ } else if (!strcasecmp(var, "context")) {
+ context = val;
+ } else if (!strcasecmp(var, "dialplan")) {
+ dialplan = val;
+ } else if (!strcasecmp(var, "dial-regex")) {
+ dial_regex = val;
+ } else if (!strcasecmp(var, "enable-callerid")) {
+ enable_callerid = val;
+ } else if (!strcasecmp(var, "fail-dial-regex")) {
+ fail_dial_regex = val;
+ } else if (!strcasecmp(var, "hold-music")) {
+ hold_music = val;
+ } else if (!strcasecmp(var, "max_digits") || !strcasecmp(var, "max-digits")) {
+ max_digits = val;
+ } else if (!strcasecmp(var, "hotline")) {
+ hotline = val;
+ } else if (!strcasecmp(var, "enable-analog-option")) {
+ analog_options = enable_analog_option(val, analog_options);
+ }
+ }
+
+ if (!id && !name) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+ continue;
+ }
+
+
+
+ if (!tonegroup) {
+ tonegroup = "us";
+ }
+
+ if (digit_timeout) {
+ to = atoi(digit_timeout);
+ }
+
+ if (max_digits) {
+ max = atoi(max_digits);
+ }
+
+ if (name) {
+ zstatus = zap_span_find_by_name(name, &span);
+ } else {
+ if (switch_is_number(id)) {
+ span_id = atoi(id);
+ zstatus = zap_span_find(span_id, &span);
+ }
+
+ if (zstatus != ZAP_SUCCESS) {
+ zstatus = zap_span_find_by_name(id, &span);
+ }
+ }
+
+ if (zstatus != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error finding OpenZAP span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+ continue;
+ }
+
+ if (!span_id) {
+ span_id = span->span_id;
+ }
+
+ if (zap_configure_span("analog", span, on_analog_signal,
+ "tonemap", tonegroup,
+ "digit_timeout", &to,
+ "max_dialstr", &max,
+ "hotline", hotline,
+ "enable_callerid", enable_callerid,
+ TAG_END) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error starting OpenZAP span %d\n", span_id);
+ continue;
+ }
+
+ SPAN_CONFIG[span->span_id].span = span;
+ switch_set_string(SPAN_CONFIG[span->span_id].context, context);
+ switch_set_string(SPAN_CONFIG[span->span_id].dialplan, dialplan);
+ SPAN_CONFIG[span->span_id].analog_options = analog_options | globals.analog_options;
+
+ if (dial_regex) {
+ switch_set_string(SPAN_CONFIG[span->span_id].dial_regex, dial_regex);
+ }
+
+ if (fail_dial_regex) {
+ switch_set_string(SPAN_CONFIG[span->span_id].fail_dial_regex, fail_dial_regex);
+ }
+
+ if (hold_music) {
+ switch_set_string(SPAN_CONFIG[span->span_id].hold_music, hold_music);
+ }
+ switch_copy_string(SPAN_CONFIG[span->span_id].type, "analog", sizeof(SPAN_CONFIG[span->span_id].type));
+ zap_span_start(span);
+ }
+ }
+
+ if ((spans = switch_xml_child(cfg, "analog_em_spans"))) {
+ for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+ char *id = (char *) switch_xml_attr(myspan, "id");
+ char *name = (char *) switch_xml_attr(myspan, "name");
+ zap_status_t zstatus = ZAP_FAIL;
+ const char *context = "default";
+ const char *dialplan = "XML";
+ const char *tonegroup = NULL;
+ char *digit_timeout = NULL;
+ char *max_digits = NULL;
+ char *dial_regex = NULL;
+ char *hold_music = NULL;
+ char *fail_dial_regex = NULL;
+ uint32_t span_id = 0, to = 0, max = 0;
+ zap_span_t *span = NULL;
+ analog_option_t analog_options = ANALOG_OPTION_NONE;
+
+ for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+
+ if (!strcasecmp(var, "tonegroup")) {
+ tonegroup = val;
+ } else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "digit-timeout")) {
+ digit_timeout = val;
+ } else if (!strcasecmp(var, "context")) {
+ context = val;
+ } else if (!strcasecmp(var, "dialplan")) {
+ dialplan = val;
+ } else if (!strcasecmp(var, "dial-regex")) {
+ dial_regex = val;
+ } else if (!strcasecmp(var, "fail-dial-regex")) {
+ fail_dial_regex = val;
+ } else if (!strcasecmp(var, "hold-music")) {
+ hold_music = val;
+ } else if (!strcasecmp(var, "max_digits") || !strcasecmp(var, "max-digits")) {
+ max_digits = val;
+ } else if (!strcasecmp(var, "enable-analog-option")) {
+ analog_options = enable_analog_option(val, analog_options);
+ }
+ }
+
+ if (!id && !name) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+ continue;
+ }
+
+
+ if (!tonegroup) {
+ tonegroup = "us";
+ }
+
+ if (digit_timeout) {
+ to = atoi(digit_timeout);
+ }
+
+ if (max_digits) {
+ max = atoi(max_digits);
+ }
+
+
+ if (name) {
+ zstatus = zap_span_find_by_name(name, &span);
+ } else {
+ if (switch_is_number(id)) {
+ span_id = atoi(id);
+ zstatus = zap_span_find(span_id, &span);
+ }
+
+ if (zstatus != ZAP_SUCCESS) {
+ zstatus = zap_span_find_by_name(id, &span);
+ }
+ }
+
+ if (zstatus != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error finding OpenZAP span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+ continue;
+ }
+
+ if (!span_id) {
+ span_id = span->span_id;
+ }
+
+
+ if (zap_configure_span("analog_em", span, on_analog_signal,
+ "tonemap", tonegroup,
+ "digit_timeout", &to,
+ "max_dialstr", &max,
+ TAG_END) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error starting OpenZAP span %d\n", span_id);
+ continue;
+ }
+
+ SPAN_CONFIG[span->span_id].span = span;
+ switch_set_string(SPAN_CONFIG[span->span_id].context, context);
+ switch_set_string(SPAN_CONFIG[span->span_id].dialplan, dialplan);
+ SPAN_CONFIG[span->span_id].analog_options = analog_options | globals.analog_options;
+
+ if (dial_regex) {
+ switch_set_string(SPAN_CONFIG[span->span_id].dial_regex, dial_regex);
+ }
+
+ if (fail_dial_regex) {
+ switch_set_string(SPAN_CONFIG[span->span_id].fail_dial_regex, fail_dial_regex);
+ }
+
+ if (hold_music) {
+ switch_set_string(SPAN_CONFIG[span->span_id].hold_music, hold_music);
+ }
+ switch_copy_string(SPAN_CONFIG[span->span_id].type, "analog_em", sizeof(SPAN_CONFIG[span->span_id].type));
+ zap_span_start(span);
+ }
+ }
+
+ if ((spans = switch_xml_child(cfg, "pri_spans"))) {
+ for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+ char *id = (char *) switch_xml_attr(myspan, "id");
+ char *name = (char *) switch_xml_attr(myspan, "name");
+ zap_status_t zstatus = ZAP_FAIL;
+ const char *context = "default";
+ const char *dialplan = "XML";
+ //Q921NetUser_t mode = Q931_TE;
+ //Q931Dialect_t dialect = Q931_Dialect_National;
+ char *mode = NULL;
+ char *dialect = NULL;
+ uint32_t span_id = 0;
+ zap_span_t *span = NULL;
+ const char *tonegroup = NULL;
+ char *digit_timeout = NULL;
+ const char *opts = "none";
+ uint32_t to = 0;
+ int q921loglevel = -1;
+ int q931loglevel = -1;
+
+ // quick debug
+ //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ID: '%s', Name:'%s'\n",id,name);
+
+ for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+
+ if (!strcasecmp(var, "tonegroup")) {
+ tonegroup = val;
+ } else if (!strcasecmp(var, "mode")) {
+ mode = val;
+ } else if (!strcasecmp(var, "dialect")) {
+ dialect = val;
+ } else if (!strcasecmp(var, "q921loglevel")) {
+ if ((q921loglevel = switch_log_str2level(val)) == SWITCH_LOG_INVALID) {
+ q921loglevel = -1;
+ }
+ } else if (!strcasecmp(var, "q931loglevel")) {
+ if ((q931loglevel = switch_log_str2level(val)) == SWITCH_LOG_INVALID) {
+ q931loglevel = -1;
+ }
+ } else if (!strcasecmp(var, "context")) {
+ context = val;
+ } else if (!strcasecmp(var, "opts")) {
+ opts = val;
+ } else if (!strcasecmp(var, "dialplan")) {
+ dialplan = val;
+ } else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "digit-timeout")) {
+ digit_timeout = val;
+ }
+ }
+
+ if (!id && !name) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+ continue;
+ }
+
+ if (name) {
+ zstatus = zap_span_find_by_name(name, &span);
+ } else {
+ if (switch_is_number(id)) {
+ span_id = atoi(id);
+ zstatus = zap_span_find(span_id, &span);
+ }
+
+ if (zstatus != ZAP_SUCCESS) {
+ zstatus = zap_span_find_by_name(id, &span);
+ }
+ }
+
+ if (digit_timeout) {
+ to = atoi(digit_timeout);
+ }
+
+ if (zstatus != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error finding OpenZAP span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+ continue;
+ }
+
+ if (!span_id) {
+ span_id = span->span_id;
+ }
+
+ if (!tonegroup) {
+ tonegroup = "us";
+ }
+
+ if (zap_configure_span("isdn", span, on_clear_channel_signal,
+ "mode", mode,
+ "dialect", dialect,
+ "digit_timeout", &to,
+ "opts", opts,
+ "tonemap", tonegroup,
+ "q921loglevel", q921loglevel,
+ "q931loglevel", q931loglevel,
+ TAG_END) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error starting OpenZAP span %d mode: %s dialect: %s error: %s\n", span_id, mode, dialect, span->last_error);
+ continue;
+ }
+
+ SPAN_CONFIG[span->span_id].span = span;
+ switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context));
+ switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan));
+ switch_copy_string(SPAN_CONFIG[span->span_id].type, "isdn", sizeof(SPAN_CONFIG[span->span_id].type));
+
+ zap_span_start(span);
+ }
+ }
+
+
+
+ if ((spans = switch_xml_child(cfg, "libpri_spans"))) {
+ for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+ char *id = (char *) switch_xml_attr(myspan, "id");
+ char *name = (char *) switch_xml_attr(myspan, "name");
+ zap_status_t zstatus = ZAP_FAIL;
+ const char *context = "default";
+ const char *dialplan = "XML";
+
+ const char *o_node = "cpe";
+ const char *o_switch = "dms100";
+ const char *o_dp = "unknown";
+ const char *o_l1 = "ulaw";
+ const char *o_debug = "none";
+ const char* opts = "none";
+
+ uint32_t span_id = 0;
+ zap_span_t *span = NULL;
+
+
+ for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+
+ if (!strcasecmp(var, "node")) {
+ o_node = val;
+ } else if (!strcasecmp(var, "switch")) {
+ o_switch = val;
+ } else if (!strcasecmp(var, "dp")) {
+ o_dp = val;
+ } else if (!strcasecmp(var, "l1")) {
+ o_l1 = val;
+ } else if (!strcasecmp(var, "debug")) {
+ o_debug = val;
+ } else if (!strcasecmp(var, "context")) {
+ context = val;
+ } else if (!strcasecmp(var, "opts")) {
+ opts = val;
+ } else if (!strcasecmp(var, "dialplan")) {
+ dialplan = val;
+ }
+ }
+
+ if (!id && !name) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+ continue;
+ }
+
+ if (name) {
+ zstatus = zap_span_find_by_name(name, &span);
+ } else {
+ if (switch_is_number(id)) {
+ span_id = atoi(id);
+ zstatus = zap_span_find(span_id, &span);
+ }
+
+ if (zstatus != ZAP_SUCCESS) {
+ zstatus = zap_span_find_by_name(id, &span);
+ }
+ }
+
+ if (zstatus != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error finding OpenZAP span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+ continue;
+ }
+
+ if (!span_id) {
+ span_id = span->span_id;
+ }
+
+
+ if (zap_configure_span("libpri", span, on_clear_channel_signal,
+ "node", o_node,
+ "switch", o_switch,
+ "dp", o_dp,
+ "l1", o_l1,
+ "debug", o_debug,
+ "opts", opts,
+ TAG_END) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error starting OpenZAP span %d node: %s switch: %s dp: %s l1: %s debug: %s error: %s\n",
+ span_id, switch_str_nil(o_node), switch_str_nil(o_switch), switch_str_nil(o_dp), switch_str_nil(o_l1), switch_str_nil(o_debug),
+ span->last_error);
+ continue;
+ }
+
+ SPAN_CONFIG[span->span_id].span = span;
+ switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context));
+ switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan));
+ switch_copy_string(SPAN_CONFIG[span->span_id].type, "isdn", sizeof(SPAN_CONFIG[span->span_id].type));
+
+ zap_span_start(span);
+ }
+ }
+
+ if ((spans = switch_xml_child(cfg, "boost_spans"))) {
+ for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+ char *id = (char *) switch_xml_attr(myspan, "id");
+ char *name = (char *) switch_xml_attr(myspan, "name");
+ zap_status_t zstatus = ZAP_FAIL;
+ const char *context = "default";
+ const char *dialplan = "XML";
+ const char *outbound_called_ton = "national";
+ const char *outbound_called_npi = "isdn";
+ const char *outbound_calling_ton = "national";
+ const char *outbound_calling_npi = "isdn";
+ const char *outbound_rdnis_ton = "national";
+ const char *outbound_rdnis_npi = "isdn";
+ uint32_t span_id = 0;
+ zap_span_t *span = NULL;
+ const char *tonegroup = NULL;
+ char *local_ip = NULL;
+ int local_port = 0;
+ char *remote_ip = NULL;
+ int remote_port = 0;
+
+ for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+
+ if (!strcasecmp(var, "tonegroup")) {
+ tonegroup = val;
+ } else if (!strcasecmp(var, "local-ip")) {
+ local_ip = val;
+ } else if (!strcasecmp(var, "local-port")) {
+ local_port = atoi(val);
+ } else if (!strcasecmp(var, "remote-ip")) {
+ remote_ip = val;
+ } else if (!strcasecmp(var, "remote-port")) {
+ remote_port = atoi(val);
+ } else if (!strcasecmp(var, "context")) {
+ context = val;
+ } else if (!strcasecmp(var, "outbound-called-ton")) {
+ outbound_called_ton = val;
+ } else if (!strcasecmp(var, "outbound-called-npi")) {
+ outbound_called_npi = val;
+ } else if (!strcasecmp(var, "outbound-calling-ton")) {
+ outbound_calling_ton = val;
+ } else if (!strcasecmp(var, "outbound-calling-npi")) {
+ outbound_calling_npi = val;
+ } else if (!strcasecmp(var, "outbound-rdnis-ton")) {
+ outbound_rdnis_ton = val;
+ } else if (!strcasecmp(var, "outbound-rdnis-npi")) {
+ outbound_rdnis_npi = val;
+ }
+ }
+
+ if (!id && !name) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param\n");
+ continue;
+ }
+
+ if (!tonegroup) {
+ tonegroup = "us";
+ }
+
+ if (name) {
+ zstatus = zap_span_find_by_name(name, &span);
+ } else {
+ if (switch_is_number(id)) {
+ span_id = atoi(id);
+ zstatus = zap_span_find(span_id, &span);
+ }
+
+ if (zstatus != ZAP_SUCCESS) {
+ zstatus = zap_span_find_by_name(id, &span);
+ }
+ }
+
+ if (zstatus != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error finding OpenZAP span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+ continue;
+ }
+
+ if (!span_id) {
+ span_id = span->span_id;
+ }
+
+ zap_set_npi(outbound_called_npi, &span->default_caller_data.ani.plan);
+ zap_set_npi(outbound_calling_npi, &span->default_caller_data.cid_num.plan);
+ zap_set_npi(outbound_rdnis_npi, &span->default_caller_data.rdnis.plan);
+
+ zap_set_ton(outbound_called_ton, &span->default_caller_data.ani.type);
+ zap_set_ton(outbound_calling_ton, &span->default_caller_data.cid_num.type);
+ zap_set_ton(outbound_rdnis_ton, &span->default_caller_data.rdnis.type);
+
+ if (zap_configure_span("sangoma_boost", span, on_clear_channel_signal,
+ "local_ip", local_ip,
+ "local_port", &local_port,
+ "remote_ip", remote_ip,
+ "remote_port", &remote_port,
+ TAG_END) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error starting OpenZAP span %d error: %s\n", span_id, span->last_error);
+ continue;
+ }
+
+ SPAN_CONFIG[span->span_id].span = span;
+ switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context));
+ switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan));
+
+ zap_span_start(span);
+ switch_copy_string(SPAN_CONFIG[span->span_id].type, "Sangoma (boost)", sizeof(SPAN_CONFIG[span->span_id].type));
+ }
+ }
+
+ if ((spans = switch_xml_child(cfg, "r2_spans"))) {
+ for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+ char *id = (char *) switch_xml_attr(myspan, "id");
+ char *name = (char *) switch_xml_attr(myspan, "name");
+ zap_status_t zstatus = ZAP_FAIL;
+
+ /* strings */
+ const char *variant = "itu";
+ const char *category = "national_subscriber";
+ const char *logdir = "/usr/local/freeswitch/log/"; /* FIXME: get PREFIX variable */
+ const char *logging = "notice,warning,error";
+ const char *advanced_protocol_file = "";
+
+ /* booleans */
+ int call_files = 0;
+ int get_ani_first = -1;
+ int immediate_accept = -1;
+ int double_answer = -1;
+ int skip_category = -1;
+ int forced_release = -1;
+ int charge_calls = -1;
+
+ /* integers */
+ int mfback_timeout = -1;
+ int metering_pulse_timeout = -1;
+ int allow_collect_calls = -1;
+ int max_ani = 10;
+ int max_dnis = 4;
+
+ /* common non r2 stuff */
+ const char *context = "default";
+ const char *dialplan = "XML";
+ char *dial_regex = NULL;
+ char *fail_dial_regex = NULL;
+ uint32_t span_id = 0;
+ zap_span_t *span = NULL;
+
+
+ for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+
+ /* string parameters */
+ if (!strcasecmp(var, "variant")) {
+ variant = val;
+ } else if (!strcasecmp(var, "category")) {
+ category = val;
+ } else if (!strcasecmp(var, "logdir")) {
+ logdir = val;
+ } else if (!strcasecmp(var, "logging")) {
+ logging = val;
+ } else if (!strcasecmp(var, "advanced_protocol_file")) {
+ advanced_protocol_file = val;
+
+ /* booleans */
+ } else if (!strcasecmp(var, "allow_collect_calls")) {
+ allow_collect_calls = switch_true(val);
+ } else if (!strcasecmp(var, "immediate_accept")) {
+ immediate_accept = switch_true(val);
+ } else if (!strcasecmp(var, "double_answer")) {
+ double_answer = switch_true(val);
+ } else if (!strcasecmp(var, "skip_category")) {
+ skip_category = switch_true(var);
+ } else if (!strcasecmp(var, "forced_release")) {
+ forced_release = switch_true(val);
+ } else if (!strcasecmp(var, "charge_calls")) {
+ charge_calls = switch_true(val);
+ } else if (!strcasecmp(var, "get_ani_first")) {
+ get_ani_first = switch_true(val);
+ } else if (!strcasecmp(var, "call_files")) {
+ call_files = switch_true(val);
+
+ /* integers */
+ } else if (!strcasecmp(var, "mfback_timeout")) {
+ mfback_timeout = atoi(val);
+ } else if (!strcasecmp(var, "metering_pulse_timeout")) {
+ metering_pulse_timeout = atoi(val);
+ } else if (!strcasecmp(var, "max_ani")) {
+ max_ani = atoi(val);
+ } else if (!strcasecmp(var, "max_dnis")) {
+ max_dnis = atoi(val);
+
+ /* common non r2 stuff */
+ } else if (!strcasecmp(var, "context")) {
+ context = val;
+ } else if (!strcasecmp(var, "dialplan")) {
+ dialplan = val;
+ } else if (!strcasecmp(var, "dial-regex")) {
+ dial_regex = val;
+ } else if (!strcasecmp(var, "fail-dial-regex")) {
+ fail_dial_regex = val;
+ }
+ }
+
+ if (!id && !name) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+ continue;
+ }
+
+ if (name) {
+ zstatus = zap_span_find_by_name(name, &span);
+ } else {
+ if (switch_is_number(id)) {
+ span_id = atoi(id);
+ zstatus = zap_span_find(span_id, &span);
+ }
+
+ if (zstatus != ZAP_SUCCESS) {
+ zstatus = zap_span_find_by_name(id, &span);
+ }
+ }
+
+ if (zstatus != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error finding OpenZAP span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+ continue;
+ }
+
+ if (!span_id) {
+ span_id = span->span_id;
+ }
+
+ if (zap_configure_span("r2", span, on_r2_signal,
+ "variant", variant,
+ "max_ani", max_ani,
+ "max_dnis", max_dnis,
+ "category", category,
+ "logdir", logdir,
+ "logging", logging,
+ "advanced_protocol_file", advanced_protocol_file,
+ "allow_collect_calls", allow_collect_calls,
+ "immediate_accept", immediate_accept,
+ "double_answer", double_answer,
+ "skip_category", skip_category,
+ "forced_release", forced_release,
+ "charge_calls", charge_calls,
+ "get_ani_first", get_ani_first,
+ "call_files", call_files,
+ "mfback_timeout", mfback_timeout,
+ "metering_pulse_timeout", metering_pulse_timeout,
+ TAG_END) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error configuring R2 OpenZAP span %d, error: %s\n",
+ span_id, span->last_error);
+ continue;
+ }
+
+ if (dial_regex) {
+ switch_set_string(SPAN_CONFIG[span->span_id].dial_regex, dial_regex);
+ }
+
+ if (fail_dial_regex) {
+ switch_set_string(SPAN_CONFIG[span->span_id].fail_dial_regex, fail_dial_regex);
+ }
+
+ SPAN_CONFIG[span->span_id].span = span;
+ switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context));
+ switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan));
+ switch_copy_string(SPAN_CONFIG[span->span_id].type, "r2", sizeof(SPAN_CONFIG[span->span_id].type));
+
+ if (zap_span_start(span) == ZAP_FAIL) {
+ zap_log(ZAP_LOG_ERROR, "Error starting R2 OpenZAP span %d, error: %s\n", span_id, span->last_error);
+ continue;
+ }
+ }
+ }
+
+ switch_xml_free(xml);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+void dump_chan(zap_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream)
+{
+ if (chan_id > span->chan_count) {
+ return;
+ }
+
+ stream->write_function(stream,
+ "span_id: %u\n"
+ "chan_id: %u\n"
+ "physical_span_id: %u\n"
+ "physical_chan_id: %u\n"
+ "type: %s\n"
+ "state: %s\n"
+ "last_state: %s\n"
+ "txgain: %3.2f\n"
+ "rxgain: %3.2f\n"
+ "cid_date: %s\n"
+ "cid_name: %s\n"
+ "cid_num: %s\n"
+ "ani: %s\n"
+ "aniII: %s\n"
+ "dnis: %s\n"
+ "rdnis: %s\n"
+ "cause: %s\n\n",
+ span->channels[chan_id]->span_id,
+ span->channels[chan_id]->chan_id,
+ span->channels[chan_id]->physical_span_id,
+ span->channels[chan_id]->physical_chan_id,
+ zap_chan_type2str(span->channels[chan_id]->type),
+ zap_channel_state2str(span->channels[chan_id]->state),
+ zap_channel_state2str(span->channels[chan_id]->last_state),
+ span->channels[chan_id]->txgain,
+ span->channels[chan_id]->rxgain,
+ span->channels[chan_id]->caller_data.cid_date,
+ span->channels[chan_id]->caller_data.cid_name,
+ span->channels[chan_id]->caller_data.cid_num.digits,
+ span->channels[chan_id]->caller_data.ani.digits,
+ span->channels[chan_id]->caller_data.aniII,
+ span->channels[chan_id]->caller_data.dnis.digits,
+ span->channels[chan_id]->caller_data.rdnis.digits,
+ switch_channel_cause2str(span->channels[chan_id]->caller_data.hangup_cause)
+ );
+}
+
+void dump_chan_xml(zap_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream)
+{
+ if (chan_id > span->chan_count) {
+ return;
+ }
+
+ stream->write_function(stream,
+ " <channel>\n"
+ " <span-id>%u</span-id>\n"
+ " <chan-id>%u</chan-id>>\n"
+ " <physical-span-id>%u</physical-span-id>\n"
+ " <physical-chan-id>%u</physical-chan-id>\n"
+ " <type>%s</type>\n"
+ " <state>%s</state>\n"
+ " <last-state>%s</last-state>\n"
+ " <txgain>%3.2f</txgain>\n"
+ " <rxgain>%3.2f</rxgain>\n"
+ " <cid-date>%s</cid-date>\n"
+ " <cid-name>%s</cid-name>\n"
+ " <cid-num>%s</cid-num>\n"
+ " <ani>%s</ani>\n"
+ " <aniII>%s</aniII>\n"
+ " <dnis>%s</dnis>\n"
+ " <rdnis>%s</rdnis>\n"
+ " <cause>%s</cause>\n"
+ " </channel>\n",
+ span->channels[chan_id]->span_id,
+ span->channels[chan_id]->chan_id,
+ span->channels[chan_id]->physical_span_id,
+ span->channels[chan_id]->physical_chan_id,
+ zap_chan_type2str(span->channels[chan_id]->type),
+ zap_channel_state2str(span->channels[chan_id]->state),
+ zap_channel_state2str(span->channels[chan_id]->last_state),
+ span->channels[chan_id]->txgain,
+ span->channels[chan_id]->rxgain,
+ span->channels[chan_id]->caller_data.cid_date,
+ span->channels[chan_id]->caller_data.cid_name,
+ span->channels[chan_id]->caller_data.cid_num.digits,
+ span->channels[chan_id]->caller_data.ani.digits,
+ span->channels[chan_id]->caller_data.aniII,
+ span->channels[chan_id]->caller_data.dnis.digits,
+ span->channels[chan_id]->caller_data.rdnis.digits,
+ switch_channel_cause2str(span->channels[chan_id]->caller_data.hangup_cause)
+ );
+}
+
+#define OZ_SYNTAX "list || dump <span_id> [<chan_id>] || q931_pcap <span_id> on|off [pcapfilename without suffix] || gains <txgain> <rxgain> <span_id> [<chan_id>]"
+SWITCH_STANDARD_API(oz_function)
+{
+ char *mycmd = NULL, *argv[10] = { 0 };
+ int argc = 0;
+
+ if (!zstr(cmd) && (mycmd = strdup(cmd))) {
+ argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+ }
+
+ if (!argc) {
+ stream->write_function(stream, "%s", OZ_SYNTAX);
+ goto end;
+ }
+
+ if (!strcasecmp(argv[0], "dump")) {
+ if (argc < 2) {
+ stream->write_function(stream, "-ERR Usage: oz dump <span_id> [<chan_id>]\n");
+ goto end;
+ } else {
+ uint32_t chan_id = 0;
+ zap_span_t *span;
+ char *as = NULL;
+
+ zap_span_find_by_name(argv[1], &span);
+
+ if (argc > 2) {
+ if (argv[3] && !strcasecmp(argv[2], "as")) {
+ as = argv[3];
+ } else {
+ chan_id = atoi(argv[2]);
+ }
+ }
+
+ if (argv[4] && !strcasecmp(argv[3], "as")) {
+ as = argv[4];
+ }
+
+ if (!zstr(as) && !strcasecmp(as, "xml")) {
+ stream->write_function(stream, "<channels>\n");
+ if (!span) {
+ stream->write_function(stream, "<error>invalid span</error>\n");
+ } else {
+ if (chan_id) {
+ if(chan_id > span->chan_count) {
+ stream->write_function(stream, "<error>invalid channel</error>\n");
+ } else {
+ dump_chan_xml(span, chan_id, stream);
+ }
+ } else {
+ uint32_t j;
+ for (j = 1; j <= span->chan_count; j++) {
+ dump_chan_xml(span, j, stream);
+ }
+
+ }
+ }
+ stream->write_function(stream, "</channels>\n");
+ } else {
+ if (!span) {
+ stream->write_function(stream, "-ERR invalid span\n");
+ } else {
+ if (chan_id) {
+ if(chan_id > span->chan_count) {
+ stream->write_function(stream, "-ERR invalid channel\n");
+ } else {
+ dump_chan(span, chan_id, stream);
+ }
+ } else {
+ uint32_t j;
+
+ stream->write_function(stream, "+OK\n");
+ for (j = 1; j <= span->chan_count; j++) {
+ dump_chan(span, j, stream);
+ }
+
+ }
+ }
+ }
+ }
+ } else if (!strcasecmp(argv[0], "list")) {
+ int j;
+ for (j = 0 ; j < ZAP_MAX_SPANS_INTERFACE; j++) {
+ if (SPAN_CONFIG[j].span) {
+ const char *flags = "none";
+
+ if (SPAN_CONFIG[j].analog_options & ANALOG_OPTION_3WAY) {
+ flags = "3way";
+ } else if (SPAN_CONFIG[j].analog_options & ANALOG_OPTION_CALL_SWAP) {
+ flags = "call swap";
+ }
+
+ stream->write_function(stream,
+ "+OK\n"
+ "span: %u (%s)\n"
+ "type: %s\n"
+ "chan_count: %u\n"
+ "dialplan: %s\n"
+ "context: %s\n"
+ "dial_regex: %s\n"
+ "fail_dial_regex: %s\n"
+ "hold_music: %s\n"
+ "analog_options %s\n",
+ j,
+ SPAN_CONFIG[j].span->name,
+ SPAN_CONFIG[j].type,
+ SPAN_CONFIG[j].span->chan_count,
+ SPAN_CONFIG[j].dialplan,
+ SPAN_CONFIG[j].context,
+ SPAN_CONFIG[j].dial_regex,
+ SPAN_CONFIG[j].fail_dial_regex,
+ SPAN_CONFIG[j].hold_music,
+ flags
+ );
+ }
+ }
+ } else if (!strcasecmp(argv[0], "stop") || !strcasecmp(argv[0], "start")) {
+ char *span_name = argv[1];
+ zap_span_t *span = NULL;
+ zap_status_t status;
+
+ if (span_name) {
+ zap_span_find_by_name(span_name, &span);
+ }
+
+ if (!span) {
+ stream->write_function(stream, "-ERR no span\n");
+ goto end;
+ }
+
+ if (!strcasecmp(argv[0], "stop")) {
+ status = zap_span_stop(span);
+ } else {
+ status = zap_span_start(span);
+ }
+
+ stream->write_function(stream, status == ZAP_SUCCESS ? "+OK\n" : "-ERR failure\n");
+
+ goto end;
+
+ /*Q931ToPcap enhancement*/
+ } else if (!strcasecmp(argv[0], "q931_pcap")) {
+ int32_t span_id = 0;
+ zap_span_t *span;
+ const char *pcapfn = NULL;
+ char *tmp_path = NULL;
+
+ if (argc < 3) {
+ stream->write_function(stream, "-ERR Usage: oz q931_pcap <span_id> on|off [pcapfilename without suffix]\n");
+ goto end;
+ }
+ span_id = atoi(argv[1]);
+ if (!(span_id && (span = SPAN_CONFIG[span_id].span))) {
+ stream->write_function(stream, "-ERR invalid span\n");
+ goto end;
+ }
+
+ /*Look for a given file name or use default file name*/
+ if (argc > 3) {
+ if(argv[3]){
+ pcapfn=argv[3];
+ }
+ }
+ else {
+ pcapfn="q931";
+ }
+
+ /*Add log directory path to file name*/
+ tmp_path=switch_mprintf("%s%s%s.pcap", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR, pcapfn);
+
+ if(!strcasecmp(argv[2], "on")) {
+ if (zap_configure_span("isdn", span, on_clear_channel_signal, "q931topcap", 1, "pcapfilename", tmp_path, TAG_END) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_WARNING, "Error couldn't (re-)enable Q931-To-Pcap!\n");
+ goto end;
+ } else {
+ stream->write_function(stream, "+OK\n");
+ }
+ } else if(!strcasecmp(argv[2], "off")) {
+ if (zap_configure_span("isdn", span, on_clear_channel_signal, "q931topcap", 0, TAG_END) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error couldn't enable Q931-To-Pcap!\n");
+ goto end;
+ } else {
+ stream->write_function(stream, "+OK\n");
+ }
+ } else {
+ stream->write_function(stream, "-ERR Usage: oz q931_pcap <span_id> on|off [pcapfilename without suffix]\n");
+ goto end;
+ }
+
+ } else if (!strcasecmp(argv[0], "gains")) {
+ int i = 0;
+ float txgain = 0.0;
+ float rxgain = 0.0;
+ uint32_t chan_id = 0;
+ zap_span_t *span = NULL;
+ if (argc < 4) {
+ stream->write_function(stream, "-ERR Usage: oz gains <txgain> <rxgain> <span_id> [<chan_id>]\n");
+ goto end;
+ }
+ zap_span_find_by_name(argv[3], &span);
+ if (!span) {
+ stream->write_function(stream, "-ERR invalid span\n");
+ goto end;
+ }
+ if (argc > 4) {
+ chan_id = atoi(argv[4]);
+ if (chan_id > span->chan_count) {
+ stream->write_function(stream, "-ERR invalid chan\n");
+ goto end;
+ }
+ }
+ i = sscanf(argv[1], "%f", &rxgain);
+ i += sscanf(argv[2], "%f", &txgain);
+ if (i != 2) {
+ stream->write_function(stream, "-ERR invalid gains\n");
+ goto end;
+ }
+ if (chan_id) {
+ zap_channel_command(span->channels[chan_id], ZAP_COMMAND_SET_RX_GAIN, &rxgain);
+ zap_channel_command(span->channels[chan_id], ZAP_COMMAND_SET_TX_GAIN, &txgain);
+ } else {
+ for (i = 1; i < (int)span->chan_count; i++) {
+ zap_channel_command(span->channels[i], ZAP_COMMAND_SET_RX_GAIN, &rxgain);
+ zap_channel_command(span->channels[i], ZAP_COMMAND_SET_TX_GAIN, &txgain);
+ }
+ }
+ stream->write_function(stream, "+OK gains set to Rx %f and Tx %f\n", rxgain, txgain);
+ } else {
+ char *rply = zap_api_execute(cmd, NULL);
+
+ if (rply) {
+ stream->write_function(stream, "%s", rply);
+ free(rply);
+ } else {
+ stream->write_function(stream, "-ERR Usage: %s\n", OZ_SYNTAX);
+ }
+ }
+ /*Q931ToPcap enhancement done*/
+
+ end:
+
+ switch_safe_free(mycmd);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+SWITCH_STANDARD_APP(disable_ec_function)
+{
+ private_t *tech_pvt;
+ int x = 0;
+
+ if (!switch_core_session_check_interface(session, openzap_endpoint_interface)) {
+ zap_log(ZAP_LOG_ERROR, "This application is only for OpenZAP channels.\n");
+ return;
+ }
+
+ tech_pvt = switch_core_session_get_private(session);
+
+ if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+ switch_channel_hangup(switch_core_session_get_channel(session), SWITCH_CAUSE_LOSE_RACE);
+ return;
+ }
+
+ zap_channel_command(tech_pvt->zchan, ZAP_COMMAND_DISABLE_ECHOCANCEL, &x);
+ zap_channel_command(tech_pvt->zchan, ZAP_COMMAND_DISABLE_ECHOTRAIN, &x);
+ zap_log(ZAP_LOG_INFO, "Echo Canceller Disabled\n");
+}
+
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_openzap_load)
+{
+
+ switch_api_interface_t *commands_api_interface;
+ switch_application_interface_t *app_interface;
+
+ module_pool = pool;
+
+ zap_global_set_logger(zap_logger);
+ zap_cpu_monitor_disable();
+
+ if (zap_global_init() != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error loading OpenZAP\n");
+ return SWITCH_STATUS_TERM;
+ }
+
+ if (load_config() != SWITCH_STATUS_SUCCESS) {
+ zap_global_destroy();
+ return SWITCH_STATUS_TERM;
+ }
+
+ *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+ openzap_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
+ openzap_endpoint_interface->interface_name = "openzap";
+ openzap_endpoint_interface->io_routines = &openzap_io_routines;
+ openzap_endpoint_interface->state_handler = &openzap_state_handlers;
+
+ SWITCH_ADD_API(commands_api_interface, "oz", "OpenZAP commands", oz_function, OZ_SYNTAX);
+
+ SWITCH_ADD_APP(app_interface, "disable_ec", "Disable Echo Canceller", "Disable Echo Canceller", disable_ec_function, "", SAF_NONE);
+
+ /* indicate that the module should continue to be loaded */
+ return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_openzap_shutdown)
+{
+ zap_global_destroy();
+
+ // this breaks pika but they are MIA so *shrug*
+ //return SWITCH_STATUS_NOUNLOAD;
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/msvc/openzap.2005.vcproj (0 => 17141)
--- freeswitch/trunk/libs/openzap/msvc/openzap.2005.vcproj (rev 0)
+++ freeswitch/trunk/libs/openzap/msvc/openzap.2005.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,301 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="openzap"
+ ProjectGUID="{93B8812C-3EC4-4F78-8970-FFBFC99E167D}"
+ RootNamespace="openzap"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ BuildLogFile="$(IntDir)\BuildLog-openzap.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;OPENZAP_EXPORTS;TELETONE_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ DisableLanguageExtensions="false"
+ RuntimeTypeInfo="false"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-openzap.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;OPENZAP_EXPORTS;TELETONE_EXPORTS"
+ RuntimeLibrary="2"
+ DisableLanguageExtensions="false"
+ RuntimeTypeInfo="false"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\src\fsk.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\g711.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hashtable.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hashtable_itr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\libteletone_detect.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\libteletone_generate.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\uart.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\zap_buffer.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\zap_callerid.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\zap_config.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\zap_dso.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\zap_io.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\zap_threadmutex.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\src\include\fsk.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\g711.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\hashtable.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\hashtable_itr.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\hashtable_private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\libteletone.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\libteletone_detect.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\libteletone_generate.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\openzap.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\uart.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\zap_buffer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\zap_config.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\zap_dso.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\zap_threadmutex.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\zap_types.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/openzap/msvc/openzap.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/openzap/msvc/openzap.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/openzap/msvc/openzap.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,451 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="openzap"
+ ProjectGUID="{93B8812C-3EC4-4F78-8970-FFBFC99E167D}"
+ RootNamespace="openzap"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ BuildLogFile="$(IntDir)\BuildLog-openzap.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;OPENZAP_EXPORTS;TELETONE_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ DisableLanguageExtensions="false"
+ RuntimeTypeInfo="false"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ GenerateDebugInformation="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-openzap.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;OPENZAP_EXPORTS;TELETONE_EXPORTS"
+ RuntimeLibrary="2"
+ DisableLanguageExtensions="false"
+ RuntimeTypeInfo="false"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ BuildLogFile="$(IntDir)\BuildLog-openzap.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;OPENZAP_EXPORTS;TELETONE_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ DisableLanguageExtensions="false"
+ RuntimeTypeInfo="false"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ GenerateDebugInformation="true"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-openzap.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;OPENZAP_EXPORTS;TELETONE_EXPORTS"
+ RuntimeLibrary="2"
+ DisableLanguageExtensions="false"
+ RuntimeTypeInfo="false"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\src\include\fsk.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\g711.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\hashtable.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\hashtable_itr.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\hashtable_private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\libteletone.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\libteletone_detect.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\libteletone_generate.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\openzap.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\uart.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\zap_buffer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\zap_config.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\zap_dso.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\zap_threadmutex.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\include\zap_types.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\src\fsk.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\g711.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hashtable.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hashtable_itr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\libteletone_detect.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\libteletone_generate.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\uart.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\zap_buffer.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\zap_callerid.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\zap_config.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\zap_dso.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\zap_io.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\zap_threadmutex.c"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/openzap/msvc/testanalog/testanalog.2005.vcproj (0 => 17141)
--- freeswitch/trunk/libs/openzap/msvc/testanalog/testanalog.2005.vcproj (rev 0)
+++ freeswitch/trunk/libs/openzap/msvc/testanalog/testanalog.2005.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="testanalog"
+ ProjectGUID="{BB833648-BAFF-4BE2-94DB-F8BB043C588C}"
+ RootNamespace="testanalog"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\src\testanalog.c"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/openzap/msvc/testanalog/testanalog.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/openzap/msvc/testanalog/testanalog.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/openzap/msvc/testanalog/testanalog.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,349 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="testanalog"
+ ProjectGUID="{BB833648-BAFF-4BE2-94DB-F8BB043C588C}"
+ RootNamespace="testanalog"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\src\testanalog.c"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/openzap/msvc/testisdn/testisdn.2005.vcproj (0 => 17141)
--- freeswitch/trunk/libs/openzap/msvc/testisdn/testisdn.2005.vcproj (rev 0)
+++ freeswitch/trunk/libs/openzap/msvc/testisdn/testisdn.2005.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="testisdn"
+ ProjectGUID="{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}"
+ RootNamespace="testisdn"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\src\testisdn.c"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/openzap/msvc/testisdn/testisdn.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/openzap/msvc/testisdn/testisdn.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/openzap/msvc/testisdn/testisdn.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,349 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="testisdn"
+ ProjectGUID="{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}"
+ RootNamespace="testisdn"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\src\testisdn.c"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/openzap/openzap.2005.sln (0 => 17141)
--- freeswitch/trunk/libs/openzap/openzap.2005.sln (rev 0)
+++ freeswitch/trunk/libs/openzap/openzap.2005.sln 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,82 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openzap", "msvc\openzap.2005.vcproj", "{93B8812C-3EC4-4F78-8970-FFBFC99E167D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testanalog", "msvc\testanalog\testanalog.2005.vcproj", "{BB833648-BAFF-4BE2-94DB-F8BB043C588C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testisdn", "msvc\testisdn\testisdn.2005.vcproj", "{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_openzap", "mod_openzap\mod_openzap.2005.vcproj", "{FE3540C5-3303-46E0-A69E-D92F775687F1}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_analog", "src\ozmod\ozmod_analog\ozmod_analog.2005.vcproj", "{37C94798-6E33-4B4F-8EE0-C72A7DC91157}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_analog_em", "src\ozmod\ozmod_analog_em\ozmod_analog_em.2005.vcproj", "{C539D7C8-26A8-4A94-B938-77672165C130}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_isdn", "src\ozmod\ozmod_isdn\ozmod_isdn.2005.vcproj", "{729344A5-D5E9-434D-8EE8-AF8C6C795D15}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_wanpipe", "src\ozmod\ozmod_wanpipe\ozmod_wanpipe.2005.vcproj", "{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_pika", "src\ozmod\ozmod_pika\ozmod_pika.2005.vcproj", "{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.Build.0 = Debug|Win32
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.ActiveCfg = Release|Win32
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.Build.0 = Release|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.Build.0 = Debug|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.ActiveCfg = Release|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.Build.0 = Release|Win32
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.Build.0 = Debug|Win32
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.ActiveCfg = Release|Win32
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.Build.0 = Release|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.Build.0 = Debug|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.ActiveCfg = Release|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.Build.0 = Release|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.ActiveCfg = Debug|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.Build.0 = Debug|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.ActiveCfg = Release|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.Build.0 = Release|Win32
+ {C539D7C8-26A8-4A94-B938-77672165C130}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C539D7C8-26A8-4A94-B938-77672165C130}.Debug|Win32.Build.0 = Debug|Win32
+ {C539D7C8-26A8-4A94-B938-77672165C130}.Release|Win32.ActiveCfg = Release|Win32
+ {C539D7C8-26A8-4A94-B938-77672165C130}.Release|Win32.Build.0 = Release|Win32
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.ActiveCfg = Debug|Win32
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.Build.0 = Debug|Win32
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.ActiveCfg = Release|Win32
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.Build.0 = Release|Win32
+ {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|Win32.ActiveCfg = Release|Win32
+ {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Release|Win32.ActiveCfg = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
Added: freeswitch/trunk/libs/openzap/openzap.2008.sln (0 => 17141)
--- freeswitch/trunk/libs/openzap/openzap.2008.sln (rev 0)
+++ freeswitch/trunk/libs/openzap/openzap.2008.sln 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,119 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openzap", "msvc\openzap.2008.vcproj", "{93B8812C-3EC4-4F78-8970-FFBFC99E167D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testanalog", "msvc\testanalog\testanalog.2008.vcproj", "{BB833648-BAFF-4BE2-94DB-F8BB043C588C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testisdn", "msvc\testisdn\testisdn.2008.vcproj", "{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_openzap", "mod_openzap\mod_openzap.2008.vcproj", "{FE3540C5-3303-46E0-A69E-D92F775687F1}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_analog", "src\ozmod\ozmod_analog\ozmod_analog.2008.vcproj", "{37C94798-6E33-4B4F-8EE0-C72A7DC91157}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_analog_em", "src\ozmod\ozmod_analog_em\ozmod_analog_em.2008.vcproj", "{B3F49375-2834-4937-9D8C-4AC2EC911010}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_isdn", "src\ozmod\ozmod_isdn\ozmod_isdn.2008.vcproj", "{729344A5-D5E9-434D-8EE8-AF8C6C795D15}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_pika", "src\ozmod\ozmod_pika\ozmod_pika.2008.vcproj", "{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_wanpipe", "src\ozmod\ozmod_wanpipe\ozmod_wanpipe.2008.vcproj", "{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.Build.0 = Debug|Win32
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|x64.ActiveCfg = Debug|x64
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|x64.Build.0 = Debug|x64
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.ActiveCfg = Release|Win32
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.Build.0 = Release|Win32
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|x64.ActiveCfg = Release|x64
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|x64.Build.0 = Release|x64
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.Build.0 = Debug|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|x64.ActiveCfg = Debug|x64
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|x64.Build.0 = Debug|x64
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.ActiveCfg = Release|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.Build.0 = Release|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|x64.ActiveCfg = Release|x64
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|x64.Build.0 = Release|x64
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.Build.0 = Debug|Win32
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|x64.ActiveCfg = Debug|x64
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|x64.Build.0 = Debug|x64
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.ActiveCfg = Release|Win32
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.Build.0 = Release|Win32
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|x64.ActiveCfg = Release|x64
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|x64.Build.0 = Release|x64
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.Build.0 = Debug|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|x64.ActiveCfg = Debug|x64
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|x64.Build.0 = Debug|x64
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.ActiveCfg = Release|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.Build.0 = Release|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|x64.ActiveCfg = Release|x64
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|x64.Build.0 = Release|x64
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.ActiveCfg = Debug|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.Build.0 = Debug|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|x64.ActiveCfg = Debug|x64
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|x64.Build.0 = Debug|x64
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.ActiveCfg = Release|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.Build.0 = Release|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|x64.ActiveCfg = Release|x64
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|x64.Build.0 = Release|x64
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|Win32.Build.0 = Debug|Win32
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|x64.ActiveCfg = Debug|x64
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|x64.Build.0 = Debug|x64
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|Win32.ActiveCfg = Release|Win32
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|Win32.Build.0 = Release|Win32
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|x64.ActiveCfg = Release|x64
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|x64.Build.0 = Release|x64
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.ActiveCfg = Debug|Win32
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.Build.0 = Debug|Win32
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|x64.ActiveCfg = Debug|x64
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|x64.Build.0 = Debug|x64
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.ActiveCfg = Release|Win32
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.Build.0 = Release|Win32
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|x64.ActiveCfg = Release|x64
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|x64.Build.0 = Release|x64
+ {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Debug|x64.ActiveCfg = Debug|Win32
+ {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Release|Win32.ActiveCfg = Release|Win32
+ {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Release|x64.ActiveCfg = Release|Win32
+ {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|x64.ActiveCfg = Debug|x64
+ {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|Win32.ActiveCfg = Release|Win32
+ {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|x64.ActiveCfg = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
Added: freeswitch/trunk/libs/openzap/openzap.pc.in (0 => 17141)
--- freeswitch/trunk/libs/openzap/openzap.pc.in (rev 0)
+++ freeswitch/trunk/libs/openzap/openzap.pc.in 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,17 @@
+#
+# OpenZAP pkg-config file
+#
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: OpenZAP
+Description:
+Version: @PACKAGE_VERSION@
+URL: http://www.openzap.org/
+Requires:
+Conflicts:
+Libs: -L${libdir} -lopenzap
+Libs.private: -lm
+Cflags: -I${includedir}
Added: freeswitch/trunk/libs/openzap/patches/oz.diff (0 => 17141)
--- freeswitch/trunk/libs/openzap/patches/oz.diff (rev 0)
+++ freeswitch/trunk/libs/openzap/patches/oz.diff 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,134 @@
+Index: src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c
+===================================================================
+--- src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c (revision 745)
++++ src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c (working copy)
+@@ -98,19 +98,21 @@
+ * so we can have one analong handler thread that will deal with all the idle analog channels for events
+ * the alternative would be for the driver to provide one socket for all of the oob events for all analog channels
+ */
+-static __inline__ int tdmv_api_wait_socket(sng_fd_t fd, int timeout, int *flags)
++static __inline__ int tdmv_api_wait_socket(zap_channel_t *zchan, int timeout, int *flags)
+ {
+
+ #ifdef LIBSANGOMA_VERSION
+ int err;
+- sangoma_wait_obj_t sangoma_wait_obj;
++ sangoma_wait_obj_t *sangoma_wait_obj = zchan->mod_data;
+
+- sangoma_init_wait_obj(&sangoma_wait_obj, fd, 1, 1, *flags, SANGOMA_WAIT_OBJ);
++ sangoma_init_wait_obj(sangoma_wait_obj, zchan->sockfd, 1, 1, 0, SANGOMA_WAIT_OBJ);
+
+- err=sangoma_socket_waitfor_many(&sangoma_wait_obj,1 , timeout);
++ err = sangoma_socket_waitfor_many(&sangoma_wait_obj, 1, timeout);
++
+ if (err > 0) {
+- *flags=sangoma_wait_obj.flags_out;
++ *flags = sangoma_wait_obj.flags_out;
+ }
++
+ return err;
+
+ #else
+@@ -118,7 +120,7 @@
+ int res;
+
+ memset(&pfds[0], 0, sizeof(pfds[0]));
+- pfds[0].fd = fd;
++ pfds[0].fd = zchan->sockfd;
+ pfds[0].events = *flags;
+ res = poll(pfds, 1, timeout);
+ *flags = 0;
+@@ -200,6 +202,15 @@
+
+ if (sockfd != WP_INVALID_SOCKET && zap_span_add_channel(span, sockfd, type, &chan) == ZAP_SUCCESS) {
+ wanpipe_tdm_api_t tdm_api;
++#ifdef LIBSANGOMA_VERSION
++ sangoma_wait_obj_t *sangoma_wait_obj;
++
++ sangoma_wait_obj = malloc(sizeof(*sangoma_wait_obj));
++ memset(sangoma_wait_obj, 0, sizeof(*sangoma_wait_obj));
++ sangoma_init_wait_obj(sangoma_wait_obj, sockfd, 1, 1, 0, SANGOMA_WAIT_OBJ);
++ chan->mod_data = sangoma_wait_obj;
++#endif
++
+ memset(&tdm_api,0,sizeof(tdm_api));
+
+ chan->physical_span_id = spanno;
+@@ -211,7 +222,7 @@
+
+ dtmf = "software";
+
+- /* FIXME: Handle Error Conditino Check for return code */
++ /* FIXME: Handle Error Condition Check for return code */
+ err= sangoma_tdm_get_hw_coding(chan->sockfd, &tdm_api);
+
+ if (tdm_api.wp_tdm_cmd.hw_tdm_coding) {
+@@ -606,7 +617,7 @@
+ inflags |= POLLPRI;
+ }
+
+- result = tdmv_api_wait_socket(zchan->sockfd, to, &inflags);
++ result = tdmv_api_wait_socket(zchan, to, &inflags);
+
+ *flags = ZAP_NO_FLAGS;
+
+@@ -643,26 +654,30 @@
+ ZIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event)
+ {
+ #ifdef LIBSANGOMA_VERSION
+- sangoma_wait_obj_t pfds[ZAP_MAX_CHANNELS_SPAN];
++ sangoma_wait_obj_t *pfds[ZAP_MAX_CHANNELS_SPAN] = { 0 };
+ #else
+ struct pollfd pfds[ZAP_MAX_CHANNELS_SPAN];
+ #endif
+
+ uint32_t i, j = 0, k = 0, l = 0;
+- int objects=0;
+ int r;
+
+ for(i = 1; i <= span->chan_count; i++) {
+ zap_channel_t *zchan = span->channels[i];
+
++
+ #ifdef LIBSANGOMA_VERSION
+- sangoma_init_wait_obj(&pfds[j], zchan->sockfd , 1, 1, POLLPRI, SANGOMA_WAIT_OBJ);
++ if (!zchan->mod_data) {
++ continue;
++ }
++ pfds[j] = zchan->mod_data;
++
+ #else
+ memset(&pfds[j], 0, sizeof(pfds[j]));
+ pfds[j].fd = span->channels[i]->sockfd;
+ pfds[j].events = POLLPRI;
+ #endif
+- objects++;
++
+ /* The driver probably should be able to do this wink/flash/ringing by itself this is sort of a hack to make it work! */
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_WINK) || zap_test_flag(zchan, ZAP_CHANNEL_FLASH)) {
+@@ -703,7 +718,7 @@
+ ms = l;
+ }
+ #ifdef LIBSANGOMA_VERSION
+- r = sangoma_socket_waitfor_many(pfds,objects,ms);
++ r = sangoma_socket_waitfor_many(pfds, j, ms);
+ #else
+ r = poll(pfds, j, ms);
+ #endif
+@@ -935,6 +950,15 @@
+ */
+ static ZIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy)
+ {
++ sangoma_wait_obj_t *sangoma_wait_obj;
++
++ if (zchan->mod_data) {
++ sangoma_wait_obj = zchan->mod_data;
++ zchan->mod_data = NULL;
++ sangoma_release_wait_obj(sangoma_wait_obj);
++ free(sangoma_wait_obj);
++ }
++
+ if (zchan->sockfd > -1) {
+ close(zchan->sockfd);
+ zchan->sockfd = WP_INVALID_SOCKET;
Added: freeswitch/trunk/libs/openzap/src/detect_dtmf.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/detect_dtmf.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/detect_dtmf.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,33 @@
+//#include "openzap.h"
+#include "libteletone_detect.h"
+
+int main(int argc, char *argv[])
+{
+ int fd, b;
+ short sln[512] = {0};
+ teletone_dtmf_detect_state_t dtmf_detect = {0};
+ char digit_str[128] = "";
+
+ if (argc < 2) {
+ fprintf(stderr, "Arg Error!\n");
+ exit(-1);
+ }
+
+ teletone_dtmf_detect_init (&dtmf_detect, 8000);
+
+ if ((fd = open(argv[1], O_RDONLY)) < 0) {
+ fprintf(stderr, "File Error! [%s]\n", strerror(errno));
+ exit(-1);
+ }
+
+ while((b = read(fd, sln, 320)) > 0) {
+ teletone_dtmf_detect(&dtmf_detect, sln, b / 2);
+ teletone_dtmf_get(&dtmf_detect, digit_str, sizeof(digit_str));
+ if (*digit_str) {
+ printf("digit: %s\n", digit_str);
+ }
+ }
+ close(fd);
+ return 0;
+}
+
Added: freeswitch/trunk/libs/openzap/src/detect_tones.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/detect_tones.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/detect_tones.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,32 @@
+//#include "openzap.h"
+#include "libteletone_detect.h"
+
+int main(int argc, char *argv[])
+{
+ teletone_multi_tone_t mt = {0};
+ teletone_tone_map_t map = {{0}};
+
+ int fd, b;
+ short sln[512] = {0};
+
+ if (argc < 2) {
+ fprintf(stderr, "Arg Error!\n");
+ exit(-1);
+ }
+
+ map.freqs[0] = atof("350");
+ map.freqs[1] = atof("440");
+ teletone_multi_tone_init(&mt, &map);
+
+ if ((fd = open(argv[1], O_RDONLY)) < 0) {
+ fprintf(stderr, "File Error! [%s]\n", strerror(errno));
+ exit(-1);
+ }
+
+ while((b = read(fd, sln, 320)) > 0) {
+ printf("TEST %d %d\n", b, teletone_multi_tone_detect(&mt, sln, b / 2));
+ }
+ close(fd);
+ return 0;
+}
+
Added: freeswitch/trunk/libs/openzap/src/fsk.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/fsk.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/fsk.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,351 @@
+
+/*
+ * bell202.c
+ *
+ * Copyright (c) 2005 Robert Krten. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * This module contains a Bell-202 1200-baud FSK decoder, suitable for
+ * use in a library. The general style of the library calls is modeled
+ * after the POSIX pthread_*() functions.
+ *
+ * 2005 03 20 R. Krten created
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+
+#include "fsk.h"
+#include "uart.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+fsk_modem_definition_t fsk_modem_definitions[] =
+{
+ { /* FSK_V23_FORWARD_MODE1 */ 1700, 1300, 600 },
+ { /* FSK_V23_FORWARD_MODE2 */ 2100, 1300, 1200 },
+ { /* FSK_V23_BACKWARD */ 450, 390, 75 },
+ { /* FSK_BELL202 */ 2200, 1200, 1200 },
+};
+
+/*
+ * dsp_fsk_attr_init
+ *
+ * Initializes the attributes structure; this must be done before the
+ * attributes structure is used.
+*/
+
+void dsp_fsk_attr_init (dsp_fsk_attr_t *attr)
+{
+ memset(attr, 0, sizeof(*attr));
+}
+
+/*
+ * dsp_fsk_attr_get_bithandler
+ * dsp_fsk_attr_set_bithandler
+ * dsp_fsk_attr_get_bytehandler
+ * dsp_fsk_attr_set_bytehandler
+ * dsp_fsk_attr_getsamplerate
+ * dsp_fsk_attr_setsamplerate
+ *
+ * These functions get and set their respective elements from the
+ * attributes structure. If an error code is returned, it is just
+ * zero == ok, -1 == fail.
+*/
+
+bithandler_func_t dsp_fsk_attr_get_bithandler(dsp_fsk_attr_t *attr, void **bithandler_arg)
+{
+ *bithandler_arg = attr->bithandler_arg;
+ return attr->bithandler;
+}
+
+void dsp_fsk_attr_set_bithandler(dsp_fsk_attr_t *attr, bithandler_func_t bithandler, void *bithandler_arg)
+{
+ attr->bithandler = bithandler;
+ attr->bithandler_arg = bithandler_arg;
+}
+
+bytehandler_func_t dsp_fsk_attr_get_bytehandler(dsp_fsk_attr_t *attr, void **bytehandler_arg)
+{
+ *bytehandler_arg = attr->bytehandler_arg;
+ return attr->bytehandler;
+}
+
+void dsp_fsk_attr_set_bytehandler(dsp_fsk_attr_t *attr, bytehandler_func_t bytehandler, void *bytehandler_arg)
+{
+ attr->bytehandler = bytehandler;
+ attr->bytehandler_arg = bytehandler_arg;
+}
+
+int dsp_fsk_attr_get_samplerate (dsp_fsk_attr_t *attr)
+{
+ return attr->sample_rate;
+}
+
+int dsp_fsk_attr_set_samplerate (dsp_fsk_attr_t *attr, int samplerate)
+{
+ if (samplerate <= 0) {
+ return -1;
+ }
+ attr->sample_rate = samplerate;
+ return 0;
+}
+
+/*
+ * dsp_fsk_create
+ *
+ * Creates a handle for subsequent use. The handle is created to contain
+ * a context data structure for use by the sample handler function. The
+ * function expects an initialized attributes structure, and returns the
+ * handle or a NULL if there were errors.
+ *
+ * Once created, the handle can be used until it is destroyed.
+*/
+
+dsp_fsk_handle_t *dsp_fsk_create(dsp_fsk_attr_t *attr)
+{
+ int i;
+ double phi_mark, phi_space;
+ dsp_fsk_handle_t *handle;
+
+ handle = malloc(sizeof(*handle));
+ if (!handle) {
+ return NULL;
+ }
+
+ memset(handle, 0, sizeof(*handle));
+
+ /* fill the attributes member */
+ memcpy(&handle->attr, attr, sizeof(*attr));
+
+ /* see if we can do downsampling. We only really need 6 samples to "match" */
+ if (attr->sample_rate / fsk_modem_definitions[FSK_BELL202].freq_mark > 6) {
+ handle->downsampling_count = attr->sample_rate / fsk_modem_definitions[FSK_BELL202].freq_mark / 6;
+ } else {
+ handle->downsampling_count = 1;
+ }
+ handle->current_downsample = 1;
+
+ /* calculate the correlate size (number of samples required for slowest wave) */
+ handle->corrsize = attr->sample_rate / handle->downsampling_count / fsk_modem_definitions[FSK_BELL202].freq_mark;
+
+ /* allocate the correlation sin/cos arrays and initialize */
+ for (i = 0; i < 4; i++) {
+ handle->correlates[i] = malloc(sizeof(double) * handle->corrsize);
+ if (handle->correlates[i] == NULL) {
+ /* some failed, back out memory allocations */
+ dsp_fsk_destroy(&handle);
+ return NULL;
+ }
+ }
+
+ /* now initialize them */
+ phi_mark = 2. * M_PI / ((double) attr->sample_rate / (double) handle->downsampling_count / (double) fsk_modem_definitions[FSK_BELL202].freq_mark);
+ phi_space = 2. * M_PI / ((double) attr->sample_rate / (double) handle->downsampling_count / (double) fsk_modem_definitions[FSK_BELL202].freq_space);
+
+ for (i = 0; i < handle->corrsize; i++) {
+ handle->correlates[0][i] = sin(phi_mark * (double) i);
+ handle->correlates[1][i] = cos(phi_mark * (double) i);
+ handle->correlates[2][i] = sin(phi_space * (double) i);
+ handle->correlates[3][i] = cos(phi_space * (double) i);
+ }
+
+ /* initialize the ring buffer */
+ handle->buffer = malloc(sizeof(double) * handle->corrsize);
+ if (!handle->buffer) { /* failed; back out memory allocations */
+ dsp_fsk_destroy(&handle);
+ return NULL;
+ }
+ memset(handle->buffer, 0, sizeof(double) * handle->corrsize);
+ handle->ringstart = 0;
+
+ /* initalize intra-cell position */
+ handle->cellpos = 0;
+ handle->celladj = fsk_modem_definitions[FSK_BELL202].baud_rate / (double) attr->sample_rate * (double) handle->downsampling_count;
+
+ /* if they have provided a byte handler, add a UART to the processing chain */
+ if (handle->attr.bytehandler) {
+ dsp_uart_attr_t uart_attr;
+ dsp_uart_handle_t *uart_handle;
+
+ dsp_uart_attr_init(&uart_attr);
+ dsp_uart_attr_set_bytehandler(&uart_attr, handle->attr.bytehandler, handle->attr.bytehandler_arg);
+ uart_handle = dsp_uart_create(&uart_attr);
+ if (uart_handle == NULL) {
+ dsp_fsk_destroy(&handle);
+ return NULL;
+ }
+ handle->attr.bithandler = dsp_uart_bit_handler;
+ handle->attr.bithandler_arg = uart_handle;
+ }
+
+ return handle;
+}
+
+/*
+ * dsp_fsk_destroy
+ *
+ * Destroys a handle, releasing any associated memory. Sets handle pointer to NULL
+ * so A destroyed handle can not be used for anything after the destroy.
+*/
+
+void dsp_fsk_destroy(dsp_fsk_handle_t **handle)
+{
+ int i;
+
+ /* if empty handle, just return */
+ if (*handle == NULL) {
+ return;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if ((*handle)->correlates[i] != NULL) {
+ free((*handle)->correlates[i]);
+ (*handle)->correlates[i] = NULL;
+ }
+ }
+
+ if ((*handle)->buffer != NULL) {
+ free((*handle)->buffer);
+ (*handle)->buffer = NULL;
+ }
+
+ if ((*handle)->attr.bytehandler) {
+ dsp_uart_handle_t** dhandle = (void *)(&(*handle)->attr.bithandler_arg);
+ dsp_uart_destroy(dhandle);
+ }
+
+ free(*handle);
+ *handle = NULL;
+}
+
+/*
+ * dsp_fsk_sample
+ *
+ * This is the main processing entry point. The function accepts a normalized
+ * sample (i.e., one whose range is between -1 and +1). The function performs
+ * the Bell-202 FSK modem decode processing, and, if it detects a valid bit,
+ * will call the bithandler associated with the attributes structure.
+ *
+ * For the Bell-202 standard, a logical zero (space) is 2200 Hz, and a logical
+ * one (mark) is 1200 Hz.
+*/
+
+void
+dsp_fsk_sample (dsp_fsk_handle_t *handle, double normalized_sample)
+{
+ double val;
+ double factors[4];
+ int i, j;
+
+ /* if we can avoid processing samples, do so */
+ if (handle->downsampling_count != 1) {
+ if (handle->current_downsample < handle->downsampling_count) {
+ handle->current_downsample++;
+ return; /* throw this sample out */
+ }
+ handle->current_downsample = 1;
+ }
+
+ /* store sample in buffer */
+ handle->buffer[handle->ringstart++] = normalized_sample;
+ if (handle->ringstart >= handle->corrsize) {
+ handle->ringstart = 0;
+ }
+
+ /* do the correlation calculation */
+ factors[0] = factors[1] = factors[2] = factors[3] = 0; /* clear out intermediate sums */
+ j = handle->ringstart;
+ for (i = 0; i < handle->corrsize; i++) {
+ if (j >= handle->corrsize) {
+ j = 0;
+ }
+ val = handle->buffer[j];
+ factors[0] += handle->correlates[0][i] * val;
+ factors[1] += handle->correlates[1][i] * val;
+ factors[2] += handle->correlates[2][i] * val;
+ factors[3] += handle->correlates[3][i] * val;
+ j++;
+ }
+
+ /* store the bit (bit value is comparison of the two sets of correlate factors) */
+ handle->previous_bit = handle->current_bit;
+ handle->current_bit = (factors[0] * factors[0] + factors[1] * factors[1] > factors[2] * factors[2] + factors[3] * factors[3]);
+
+ /* if there's a transition, we can synchronize the cell position */
+ if (handle->previous_bit != handle->current_bit) {
+ handle->cellpos = 0.5; /* adjust cell position to be in the middle of the cell */
+ }
+ handle->cellpos += handle->celladj; /* walk the cell along */
+
+ if (handle->cellpos > 1.0) {
+ handle->cellpos -= 1.0;
+
+ switch (handle->state) {
+ case FSK_STATE_DATA:
+ {
+
+ (*handle->attr.bithandler) (handle->attr.bithandler_arg, handle->current_bit);
+ }
+ break;
+ case FSK_STATE_CHANSEIZE:
+ {
+
+ if (handle->last_bit != handle->current_bit) {
+ handle->conscutive_state_bits++;
+ } else {
+ handle->conscutive_state_bits = 0;
+ }
+
+ if (handle->conscutive_state_bits > 15) {
+ handle->state = FSK_STATE_CARRIERSIG;
+ handle->conscutive_state_bits = 0;
+ }
+ }
+ break;
+ case FSK_STATE_CARRIERSIG:
+ {
+ if (handle->current_bit) {
+ handle->conscutive_state_bits++;
+ } else {
+ handle->conscutive_state_bits = 0;
+ }
+
+ if (handle->conscutive_state_bits > 15) {
+ handle->state = FSK_STATE_DATA;
+ handle->conscutive_state_bits = 0;
+ }
+ }
+ break;
+ }
+
+ handle->last_bit = handle->current_bit;
+ }
+}
+
Added: freeswitch/trunk/libs/openzap/src/g711.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/g711.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/g711.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,104 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * g711.c - A-law and u-law transcoding routines
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2006 Steve Underwood
+ *
+ * Despite my general liking of the GPL, I place this code in the
+ * public domain for the benefit of all mankind - even the slimy
+ * ones who might try to proprietize my work and use it to my
+ * detriment.
+ *
+ * $Id: g711.c,v 1.1 2006/06/07 15:46:39 steveu Exp $
+ */
+
+/*! \file */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#ifndef _MSC_VER
+#include <inttypes.h>
+#ifdef HAVE_TGMATH_H
+#include <tgmath.h>
+#endif
+#endif
+
+#include "g711.h"
+
+/* Copied from the CCITT G.711 specification */
+static const uint8_t ulaw_to_alaw_table[256] =
+ {
+ 42, 43, 40, 41, 46, 47, 44, 45, 34, 35, 32, 33, 38, 39, 36, 37,
+ 58, 59, 56, 57, 62, 63, 60, 61, 50, 51, 48, 49, 54, 55, 52, 53,
+ 10, 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, 1, 6, 7, 4, 26,
+ 27, 24, 25, 30, 31, 28, 29, 18, 19, 16, 17, 22, 23, 20, 21, 106,
+ 104, 105, 110, 111, 108, 109, 98, 99, 96, 97, 102, 103, 100, 101, 122, 120,
+ 126, 127, 124, 125, 114, 115, 112, 113, 118, 119, 116, 117, 75, 73, 79, 77,
+ 66, 67, 64, 65, 70, 71, 68, 69, 90, 91, 88, 89, 94, 95, 92, 93,
+ 82, 82, 83, 83, 80, 80, 81, 81, 86, 86, 87, 87, 84, 84, 85, 85,
+ 170, 171, 168, 169, 174, 175, 172, 173, 162, 163, 160, 161, 166, 167, 164, 165,
+ 186, 187, 184, 185, 190, 191, 188, 189, 178, 179, 176, 177, 182, 183, 180, 181,
+ 138, 139, 136, 137, 142, 143, 140, 141, 130, 131, 128, 129, 134, 135, 132, 154,
+ 155, 152, 153, 158, 159, 156, 157, 146, 147, 144, 145, 150, 151, 148, 149, 234,
+ 232, 233, 238, 239, 236, 237, 226, 227, 224, 225, 230, 231, 228, 229, 250, 248,
+ 254, 255, 252, 253, 242, 243, 240, 241, 246, 247, 244, 245, 203, 201, 207, 205,
+ 194, 195, 192, 193, 198, 199, 196, 197, 218, 219, 216, 217, 222, 223, 220, 221,
+ 210, 210, 211, 211, 208, 208, 209, 209, 214, 214, 215, 215, 212, 212, 213, 213
+ };
+
+/* These transcoding tables are copied from the CCITT G.711 specification. To achieve
+ optimal results, do not change them. */
+
+static const uint8_t alaw_to_ulaw_table[256] =
+ {
+ 42, 43, 40, 41, 46, 47, 44, 45, 34, 35, 32, 33, 38, 39, 36, 37,
+ 57, 58, 55, 56, 61, 62, 59, 60, 49, 50, 47, 48, 53, 54, 51, 52,
+ 10, 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, 1, 6, 7, 4, 5,
+ 26, 27, 24, 25, 30, 31, 28, 29, 18, 19, 16, 17, 22, 23, 20, 21,
+ 98, 99, 96, 97, 102, 103, 100, 101, 93, 93, 92, 92, 95, 95, 94, 94,
+ 116, 118, 112, 114, 124, 126, 120, 122, 106, 107, 104, 105, 110, 111, 108, 109,
+ 72, 73, 70, 71, 76, 77, 74, 75, 64, 65, 63, 63, 68, 69, 66, 67,
+ 86, 87, 84, 85, 90, 91, 88, 89, 79, 79, 78, 78, 82, 83, 80, 81,
+ 170, 171, 168, 169, 174, 175, 172, 173, 162, 163, 160, 161, 166, 167, 164, 165,
+ 185, 186, 183, 184, 189, 190, 187, 188, 177, 178, 175, 176, 181, 182, 179, 180,
+ 138, 139, 136, 137, 142, 143, 140, 141, 130, 131, 128, 129, 134, 135, 132, 133,
+ 154, 155, 152, 153, 158, 159, 156, 157, 146, 147, 144, 145, 150, 151, 148, 149,
+ 226, 227, 224, 225, 230, 231, 228, 229, 221, 221, 220, 220, 223, 223, 222, 222,
+ 244, 246, 240, 242, 252, 254, 248, 250, 234, 235, 232, 233, 238, 239, 236, 237,
+ 200, 201, 198, 199, 204, 205, 202, 203, 192, 193, 191, 191, 196, 197, 194, 195,
+ 214, 215, 212, 213, 218, 219, 216, 217, 207, 207, 206, 206, 210, 211, 208, 209
+ };
+
+uint8_t alaw_to_ulaw(uint8_t alaw)
+{
+ return alaw_to_ulaw_table[alaw];
+}
+/*- End of function --------------------------------------------------------*/
+
+uint8_t ulaw_to_alaw(uint8_t ulaw)
+{
+ return ulaw_to_alaw_table[ulaw];
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/openzap/src/hashtable.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/hashtable.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/hashtable.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * 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.
+ */
+
+#include "hashtable.h"
+#include "hashtable_private.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+/*
+ Credit for primes table: Aaron Krowne
+ http://br.endernet.org/~akrowne/
+ http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
+*/
+static const unsigned int primes[] = {
+ 53, 97, 193, 389,
+ 769, 1543, 3079, 6151,
+ 12289, 24593, 49157, 98317,
+ 196613, 393241, 786433, 1572869,
+ 3145739, 6291469, 12582917, 25165843,
+ 50331653, 100663319, 201326611, 402653189,
+ 805306457, 1610612741
+};
+const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]);
+const float max_load_factor = 0.65f;
+
+/*****************************************************************************/
+OZ_DECLARE(struct hashtable *)
+create_hashtable(unsigned int minsize,
+ unsigned int (*hashf) (void*),
+ int (*eqf) (void*,void*))
+{
+ struct hashtable *h;
+ unsigned int pindex, size = primes[0];
+ /* Check requested hashtable isn't too large */
+ if (minsize > (1u << 30)) return NULL;
+ /* Enforce size as prime */
+ for (pindex=0; pindex < prime_table_length; pindex++) {
+ if (primes[pindex] > minsize) { size = primes[pindex]; break; }
+ }
+ h = (struct hashtable *)malloc(sizeof(struct hashtable));
+ if (NULL == h) return NULL; /*oom*/
+ h->table = (struct entry **)malloc(sizeof(struct entry*) * size);
+ if (NULL == h->table) { free(h); return NULL; } /*oom*/
+ memset(h->table, 0, size * sizeof(struct entry *));
+ h->tablelength = size;
+ h->primeindex = pindex;
+ h->entrycount = 0;
+ h->hashfn = hashf;
+ h->eqfn = eqf;
+ h->loadlimit = (unsigned int) ceil(size * max_load_factor);
+ return h;
+}
+
+/*****************************************************************************/
+unsigned int
+hash(struct hashtable *h, void *k)
+{
+ /* Aim to protect against poor hash functions by adding logic here
+ * - logic taken from java 1.4 hashtable source */
+ unsigned int i = h->hashfn(k);
+ i += ~(i << 9);
+ i ^= ((i >> 14) | (i << 18)); /* >>> */
+ i += (i << 4);
+ i ^= ((i >> 10) | (i << 22)); /* >>> */
+ return i;
+}
+
+/*****************************************************************************/
+static int
+hashtable_expand(struct hashtable *h)
+{
+ /* Double the size of the table to accomodate more entries */
+ struct entry **newtable;
+ struct entry *e;
+ struct entry **pE;
+ unsigned int newsize, i, index;
+ /* Check we're not hitting max capacity */
+ if (h->primeindex == (prime_table_length - 1)) return 0;
+ newsize = primes[++(h->primeindex)];
+
+ newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize);
+ if (NULL != newtable)
+ {
+ memset(newtable, 0, newsize * sizeof(struct entry *));
+ /* This algorithm is not 'stable'. ie. it reverses the list
+ * when it transfers entries between the tables */
+ for (i = 0; i < h->tablelength; i++) {
+ while (NULL != (e = h->table[i])) {
+ h->table[i] = e->next;
+ index = indexFor(newsize,e->h);
+ e->next = newtable[index];
+ newtable[index] = e;
+ }
+ }
+ free(h->table);
+ h->table = newtable;
+ }
+ /* Plan B: realloc instead */
+ else
+ {
+ newtable = (struct entry **)
+ realloc(h->table, newsize * sizeof(struct entry *));
+ if (NULL == newtable) { (h->primeindex)--; return 0; }
+ h->table = newtable;
+ memset(newtable[h->tablelength], 0, newsize - h->tablelength);
+ for (i = 0; i < h->tablelength; i++) {
+ for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) {
+ index = indexFor(newsize,e->h);
+ if (index == i)
+ {
+ pE = &(e->next);
+ }
+ else
+ {
+ *pE = e->next;
+ e->next = newtable[index];
+ newtable[index] = e;
+ }
+ }
+ }
+ }
+ h->tablelength = newsize;
+ h->loadlimit = (unsigned int) ceil(newsize * max_load_factor);
+ return -1;
+}
+
+/*****************************************************************************/
+OZ_DECLARE(unsigned int)
+hashtable_count(struct hashtable *h)
+{
+ return h->entrycount;
+}
+
+/*****************************************************************************/
+OZ_DECLARE(int)
+hashtable_insert(struct hashtable *h, void *k, void *v, hashtable_flag_t flags)
+{
+ /* This method allows duplicate keys - but they shouldn't be used */
+ unsigned int index;
+ struct entry *e;
+ if (++(h->entrycount) > h->loadlimit)
+ {
+ /* Ignore the return value. If expand fails, we should
+ * still try cramming just this value into the existing table
+ * -- we may not have memory for a larger table, but one more
+ * element may be ok. Next time we insert, we'll try expanding again.*/
+ hashtable_expand(h);
+ }
+ e = (struct entry *)malloc(sizeof(struct entry));
+ if (NULL == e) { --(h->entrycount); return 0; } /*oom*/
+ e->h = hash(h,k);
+ index = indexFor(h->tablelength,e->h);
+ e->k = k;
+ e->v = v;
+ e->flags = flags;
+ e->next = h->table[index];
+ h->table[index] = e;
+ return -1;
+}
+
+/*****************************************************************************/
+OZ_DECLARE(void *) /* returns value associated with key */
+hashtable_search(struct hashtable *h, void *k)
+{
+ struct entry *e;
+ unsigned int hashvalue, index;
+ hashvalue = hash(h,k);
+ index = indexFor(h->tablelength,hashvalue);
+ e = h->table[index];
+ while (NULL != e)
+ {
+ /* Check hash value to short circuit heavier comparison */
+ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v;
+ e = e->next;
+ }
+ return NULL;
+}
+
+/*****************************************************************************/
+OZ_DECLARE(void *) /* returns value associated with key */
+hashtable_remove(struct hashtable *h, void *k)
+{
+ /* TODO: consider compacting the table when the load factor drops enough,
+ * or provide a 'compact' method. */
+
+ struct entry *e;
+ struct entry **pE;
+ void *v;
+ unsigned int hashvalue, index;
+
+ hashvalue = hash(h,k);
+ index = indexFor(h->tablelength,hash(h,k));
+ pE = &(h->table[index]);
+ e = *pE;
+ while (NULL != e)
+ {
+ /* Check hash value to short circuit heavier comparison */
+ if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
+ {
+ *pE = e->next;
+ h->entrycount--;
+ v = e->v;
+ if (e->flags & HASHTABLE_FLAG_FREE_KEY) {
+ freekey(e->k);
+ }
+ free(e);
+ return v;
+ }
+ pE = &(e->next);
+ e = e->next;
+ }
+ return NULL;
+}
+
+/*****************************************************************************/
+/* destroy */
+OZ_DECLARE(void)
+hashtable_destroy(struct hashtable *h)
+{
+ unsigned int i;
+ struct entry *e, *f;
+ struct entry **table = h->table;
+
+ for (i = 0; i < h->tablelength; i++)
+ {
+ e = table[i];
+ while (NULL != e)
+ { f = e; e = e->next; if (f->flags & HASHTABLE_FLAG_FREE_KEY) freekey(f->k); if (f->flags & HASHTABLE_FLAG_FREE_VALUE) free(f->v); free(f); }
+ }
+
+ free(h->table);
+ free(h);
+}
+
+OZ_DECLARE(struct hashtable_iterator *) hashtable_next(struct hashtable_iterator *i)
+{
+
+ if (i->e) {
+ if ((i->e = i->e->next) != 0) {
+ return i;
+ } else {
+ i->pos++;
+ }
+ }
+
+ while(i->pos < i->h->tablelength && !i->h->table[i->pos]) {
+ i->pos++;
+ }
+
+ if (i->pos >= i->h->tablelength) {
+ return NULL;
+ }
+
+ if ((i->e = i->h->table[i->pos]) != 0) {
+ return i;
+ }
+
+ return NULL;
+}
+
+OZ_DECLARE(struct hashtable_iterator *) hashtable_first(struct hashtable *h)
+{
+ h->iterator.pos = 0;
+ h->iterator.e = NULL;
+ h->iterator.h = h;
+ return hashtable_next(&h->iterator);
+}
+
+
+
+OZ_DECLARE(void) hashtable_this(struct hashtable_iterator *i, const void **key, int *klen, void **val)
+{
+ if (i->e) {
+ if (key) {
+ *key = i->e->k;
+ }
+ if (klen) {
+ *klen = (int)strlen(i->e->k);
+ }
+ if (val) {
+ *val = i->e->v;
+ }
+ } else {
+ if (key) {
+ *key = NULL;
+ }
+ if (klen) {
+ *klen = 0;
+ }
+ if (val) {
+ *val = NULL;
+ }
+ }
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/openzap/src/hashtable_itr.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/hashtable_itr.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/hashtable_itr.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2002, 2004, Christopher Clark
+ * 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.
+ */
+
+#include "hashtable.h"
+#include "hashtable_private.h"
+#include "hashtable_itr.h"
+#include <stdlib.h> /* defines NULL */
+
+/*****************************************************************************/
+/* hashtable_iterator - iterator constructor */
+
+struct hashtable_itr *
+hashtable_iterator(struct hashtable *h)
+{
+ unsigned int i, tablelength;
+ struct hashtable_itr *itr = (struct hashtable_itr *)
+ malloc(sizeof(struct hashtable_itr));
+ if (NULL == itr) return NULL;
+ itr->h = h;
+ itr->e = NULL;
+ itr->parent = NULL;
+ tablelength = h->tablelength;
+ itr->index = tablelength;
+ if (0 == h->entrycount) return itr;
+
+ for (i = 0; i < tablelength; i++)
+ {
+ if (NULL != h->table[i])
+ {
+ itr->e = h->table[i];
+ itr->index = i;
+ break;
+ }
+ }
+ return itr;
+}
+
+/*****************************************************************************/
+/* advance - advance the iterator to the next element
+ * returns zero if advanced to end of table */
+
+int
+hashtable_iterator_advance(struct hashtable_itr *itr)
+{
+ unsigned int j,tablelength;
+ struct entry **table;
+ struct entry *next;
+ if (NULL == itr->e) return 0; /* stupidity check */
+
+ next = itr->e->next;
+ if (NULL != next)
+ {
+ itr->parent = itr->e;
+ itr->e = next;
+ return -1;
+ }
+ tablelength = itr->h->tablelength;
+ itr->parent = NULL;
+ if (tablelength <= (j = ++(itr->index)))
+ {
+ itr->e = NULL;
+ return 0;
+ }
+ table = itr->h->table;
+ while (NULL == (next = table[j]))
+ {
+ if (++j >= tablelength)
+ {
+ itr->index = tablelength;
+ itr->e = NULL;
+ return 0;
+ }
+ }
+ itr->index = j;
+ itr->e = next;
+ return -1;
+}
+
+/*****************************************************************************/
+/* remove - remove the entry at the current iterator position
+ * and advance the iterator, if there is a successive
+ * element.
+ * If you want the value, read it before you remove:
+ * beware memory leaks if you don't.
+ * Returns zero if end of iteration. */
+
+int
+hashtable_iterator_remove(struct hashtable_itr *itr)
+{
+ struct entry *remember_e, *remember_parent;
+ int ret;
+
+ /* Do the removal */
+ if (NULL == (itr->parent))
+ {
+ /* element is head of a chain */
+ itr->h->table[itr->index] = itr->e->next;
+ } else {
+ /* element is mid-chain */
+ itr->parent->next = itr->e->next;
+ }
+ /* itr->e is now outside the hashtable */
+ remember_e = itr->e;
+ itr->h->entrycount--;
+ freekey(remember_e->k);
+
+ /* Advance the iterator, correcting the parent */
+ remember_parent = itr->parent;
+ ret = hashtable_iterator_advance(itr);
+ if (itr->parent == remember_e) { itr->parent = remember_parent; }
+ free(remember_e);
+ return ret;
+}
+
+/*****************************************************************************/
+int /* returns zero if not found */
+hashtable_iterator_search(struct hashtable_itr *itr,
+ struct hashtable *h, void *k)
+{
+ struct entry *e, *parent;
+ unsigned int hashvalue, index;
+
+ hashvalue = hash(h,k);
+ index = indexFor(h->tablelength,hashvalue);
+
+ e = h->table[index];
+ parent = NULL;
+ while (NULL != e)
+ {
+ /* Check hash value to short circuit heavier comparison */
+ if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
+ {
+ itr->index = index;
+ itr->e = e;
+ itr->parent = parent;
+ itr->h = h;
+ return -1;
+ }
+ parent = e;
+ e = e->next;
+ }
+ return 0;
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/openzap/src/include/fsk.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/include/fsk.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/fsk.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,113 @@
+/*
+ * bell202.h
+ *
+ * Copyright (c) 2005 Robert Krten. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * This module contains the manifest constants and declarations for
+ * the Bell-202 1200 baud FSK modem.
+ *
+ * 2005 03 20 R. Krten created
+*/
+
+#ifndef __FSK_H__
+#define __FSK_H__
+#include "uart.h"
+
+typedef struct {
+ int freq_space; /* Frequency of the 0 bit */
+ int freq_mark; /* Frequency of the 1 bit */
+ int baud_rate; /* baud rate for the modem */
+} fsk_modem_definition_t;
+
+/* Must be kept in sync with fsk_modem_definitions array in fsk.c */
+/* V.23 definitions: http://www.itu.int/rec/recommendation.asp?type=folders&lang=e&parent=T-REC-V.23 */
+typedef enum {
+ FSK_V23_FORWARD_MODE1 = 0, /* Maximum 600 bps for long haul */
+ FSK_V23_FORWARD_MODE2, /* Standard 1200 bps V.23 */
+ FSK_V23_BACKWARD, /* 75 bps return path for V.23 */
+ FSK_BELL202 /* Bell 202 half-duplex 1200 bps */
+} fsk_modem_types_t;
+
+typedef enum {
+ FSK_STATE_CHANSEIZE = 0,
+ FSK_STATE_CARRIERSIG,
+ FSK_STATE_DATA
+} fsk_state_t;
+
+typedef struct dsp_fsk_attr_s
+{
+ int sample_rate; /* sample rate in HZ */
+ bithandler_func_t bithandler; /* bit handler */
+ void *bithandler_arg; /* arbitrary ID passed to bithandler as first argument */
+ bytehandler_func_t bytehandler; /* byte handler */
+ void *bytehandler_arg; /* arbitrary ID passed to bytehandler as first argument */
+} dsp_fsk_attr_t;
+
+typedef struct
+{
+ fsk_state_t state;
+ dsp_fsk_attr_t attr; /* attributes structure */
+ double *correlates[4]; /* one for each of sin/cos for mark/space */
+ int corrsize; /* correlate size (also number of samples in ring buffer) */
+ double *buffer; /* sample ring buffer */
+ int ringstart; /* ring buffer start offset */
+ double cellpos; /* bit cell position */
+ double celladj; /* bit cell adjustment for each sample */
+ int previous_bit; /* previous bit (for detecting a transition to sync-up cell position) */
+ int current_bit; /* current bit */
+ int last_bit;
+ int downsampling_count; /* number of samples to skip */
+ int current_downsample; /* current skip count */
+ int conscutive_state_bits; /* number of bits in a row that matches the pattern for the current state */
+} dsp_fsk_handle_t;
+
+/*
+ * Function prototypes
+ *
+ * General calling order is:
+ * a) create the attributes structure (dsp_fsk_attr_init)
+ * b) initialize fields in the attributes structure (dsp_fsk_attr_set_*)
+ * c) create a Bell-202 handle (dsp_fsk_create)
+ * d) feed samples through the handler (dsp_fsk_sample)
+*/
+
+void dsp_fsk_attr_init(dsp_fsk_attr_t *attributes);
+
+bithandler_func_t dsp_fsk_attr_get_bithandler(dsp_fsk_attr_t *attributes, void **bithandler_arg);
+void dsp_fsk_attr_set_bithandler(dsp_fsk_attr_t *attributes, bithandler_func_t bithandler, void *bithandler_arg);
+bytehandler_func_t dsp_fsk_attr_get_bytehandler(dsp_fsk_attr_t *attributes, void **bytehandler_arg);
+void dsp_fsk_attr_set_bytehandler(dsp_fsk_attr_t *attributes, bytehandler_func_t bytehandler, void *bytehandler_arg);
+int dsp_fsk_attr_get_samplerate(dsp_fsk_attr_t *attributes);
+int dsp_fsk_attr_set_samplerate(dsp_fsk_attr_t *attributes, int samplerate);
+
+dsp_fsk_handle_t * dsp_fsk_create(dsp_fsk_attr_t *attributes);
+void dsp_fsk_destroy(dsp_fsk_handle_t **handle);
+
+void dsp_fsk_sample(dsp_fsk_handle_t *handle, double normalized_sample);
+
+extern fsk_modem_definition_t fsk_modem_definitions[];
+
+#endif
+
Added: freeswitch/trunk/libs/openzap/src/include/g711.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/include/g711.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/g711.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,395 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * g711.h - In line A-law and u-law conversion routines
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2001 Steve Underwood
+ *
+ * Despite my general liking of the GPL, I place this code in the
+ * public domain for the benefit of all mankind - even the slimy
+ * ones who might try to proprietize my work and use it to my
+ * detriment.
+ *
+ * $Id: g711.h,v 1.1 2006/06/07 15:46:39 steveu Exp $
+ */
+
+/*! \file */
+
+/*! \page g711_page A-law and mu-law handling
+ Lookup tables for A-law and u-law look attractive, until you consider the impact
+ on the CPU cache. If it causes a substantial area of your processor cache to get
+ hit too often, cache sloshing will severely slow things down. The main reason
+ these routines are slow in C, is the lack of direct access to the CPU's "find
+ the first 1" instruction. A little in-line assembler fixes that, and the
+ conversion routines can be faster than lookup tables, in most real world usage.
+ A "find the first 1" instruction is available on most modern CPUs, and is a
+ much underused feature.
+
+ If an assembly language method of bit searching is not available, these routines
+ revert to a method that can be a little slow, so the cache thrashing might not
+ seem so bad :(
+
+ Feel free to submit patches to add fast "find the first 1" support for your own
+ favourite processor.
+
+ Look up tables are used for transcoding between A-law and u-law, since it is
+ difficult to achieve the precise transcoding procedure laid down in the G.711
+ specification by other means.
+*/
+
+#if !defined(_G711_H_)
+#define _G711_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+ typedef unsigned __int8 uint8_t;
+ typedef __int16 int16_t;
+ typedef __int32 int32_t;
+ typedef unsigned __int16 uint16_t;
+#else
+#include <stdint.h>
+#endif
+
+#if defined(__i386__)
+ /*! \brief Find the bit position of the highest set bit in a word
+ \param bits The word to be searched
+ \return The bit number of the highest set bit, or -1 if the word is zero. */
+ static __inline__ int top_bit(unsigned int bits)
+ {
+ int res;
+
+ __asm__ __volatile__(" movl $-1,%%edx;\n"
+ " bsrl %%eax,%%edx;\n"
+ : "=d" (res)
+ : "a" (bits));
+ return res;
+ }
+ /*- End of function --------------------------------------------------------*/
+
+ /*! \brief Find the bit position of the lowest set bit in a word
+ \param bits The word to be searched
+ \return The bit number of the lowest set bit, or -1 if the word is zero. */
+ static __inline__ int bottom_bit(unsigned int bits)
+ {
+ int res;
+
+ __asm__ __volatile__(" movl $-1,%%edx;\n"
+ " bsfl %%eax,%%edx;\n"
+ : "=d" (res)
+ : "a" (bits));
+ return res;
+ }
+ /*- End of function --------------------------------------------------------*/
+#elif defined(__x86_64__)
+ static __inline__ int top_bit(unsigned int bits)
+ {
+ int res;
+
+ __asm__ __volatile__(" movq $-1,%%rdx;\n"
+ " bsrq %%rax,%%rdx;\n"
+ : "=d" (res)
+ : "a" (bits));
+ return res;
+ }
+ /*- End of function --------------------------------------------------------*/
+
+ static __inline__ int bottom_bit(unsigned int bits)
+ {
+ int res;
+
+ __asm__ __volatile__(" movq $-1,%%rdx;\n"
+ " bsfq %%rax,%%rdx;\n"
+ : "=d" (res)
+ : "a" (bits));
+ return res;
+ }
+ /*- End of function --------------------------------------------------------*/
+#else
+ static __inline__ int top_bit(unsigned int bits)
+ {
+ int i;
+
+ if (bits == 0)
+ return -1;
+ i = 0;
+ if (bits & 0xFFFF0000)
+ {
+ bits &= 0xFFFF0000;
+ i += 16;
+ }
+ if (bits & 0xFF00FF00)
+ {
+ bits &= 0xFF00FF00;
+ i += 8;
+ }
+ if (bits & 0xF0F0F0F0)
+ {
+ bits &= 0xF0F0F0F0;
+ i += 4;
+ }
+ if (bits & 0xCCCCCCCC)
+ {
+ bits &= 0xCCCCCCCC;
+ i += 2;
+ }
+ if (bits & 0xAAAAAAAA)
+ {
+ bits &= 0xAAAAAAAA;
+ i += 1;
+ }
+ return i;
+ }
+ /*- End of function --------------------------------------------------------*/
+
+ static __inline__ int bottom_bit(unsigned int bits)
+ {
+ int i;
+
+ if (bits == 0)
+ return -1;
+ i = 32;
+ if (bits & 0x0000FFFF)
+ {
+ bits &= 0x0000FFFF;
+ i -= 16;
+ }
+ if (bits & 0x00FF00FF)
+ {
+ bits &= 0x00FF00FF;
+ i -= 8;
+ }
+ if (bits & 0x0F0F0F0F)
+ {
+ bits &= 0x0F0F0F0F;
+ i -= 4;
+ }
+ if (bits & 0x33333333)
+ {
+ bits &= 0x33333333;
+ i -= 2;
+ }
+ if (bits & 0x55555555)
+ {
+ bits &= 0x55555555;
+ i -= 1;
+ }
+ return i;
+ }
+ /*- End of function --------------------------------------------------------*/
+#endif
+
+ /* N.B. It is tempting to use look-up tables for A-law and u-law conversion.
+ * However, you should consider the cache footprint.
+ *
+ * A 64K byte table for linear to x-law and a 512 byte table for x-law to
+ * linear sound like peanuts these days, and shouldn't an array lookup be
+ * real fast? No! When the cache sloshes as badly as this one will, a tight
+ * calculation may be better. The messiest part is normally finding the
+ * segment, but a little inline assembly can fix that on an i386, x86_64 and
+ * many other modern processors.
+ */
+
+ /*
+ * Mu-law is basically as follows:
+ *
+ * Biased Linear Input Code Compressed Code
+ * ------------------------ ---------------
+ * 00000001wxyza 000wxyz
+ * 0000001wxyzab 001wxyz
+ * 000001wxyzabc 010wxyz
+ * 00001wxyzabcd 011wxyz
+ * 0001wxyzabcde 100wxyz
+ * 001wxyzabcdef 101wxyz
+ * 01wxyzabcdefg 110wxyz
+ * 1wxyzabcdefgh 111wxyz
+ *
+ * Each biased linear code has a leading 1 which identifies the segment
+ * number. The value of the segment number is equal to 7 minus the number
+ * of leading 0's. The quantization interval is directly available as the
+ * four bits wxyz. * The trailing bits (a - h) are ignored.
+ *
+ * Ordinarily the complement of the resulting code word is used for
+ * transmission, and so the code word is complemented before it is returned.
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+
+ /*#define ULAW_ZEROTRAP*/ /* turn on the trap as per the MIL-STD */
+#define ULAW_BIAS 0x84 /* Bias for linear code. */
+
+ /*! \brief Encode a linear sample to u-law
+ \param linear The sample to encode.
+ \return The u-law value.
+ */
+ static __inline__ uint8_t linear_to_ulaw(int linear)
+ {
+ uint8_t u_val;
+ int mask;
+ int seg;
+
+ /* Get the sign and the magnitude of the value. */
+ if (linear < 0)
+ {
+ linear = ULAW_BIAS - linear;
+ mask = 0x7F;
+ }
+ else
+ {
+ linear = ULAW_BIAS + linear;
+ mask = 0xFF;
+ }
+
+ seg = top_bit(linear | 0xFF) - 7;
+
+ /*
+ * Combine the sign, segment, quantization bits,
+ * and complement the code word.
+ */
+ if (seg >= 8)
+ u_val = (uint8_t) (0x7F ^ mask);
+ else
+ u_val = (uint8_t) (((seg << 4) | ((linear >> (seg + 3)) & 0xF)) ^ mask);
+#ifdef ULAW_ZEROTRAP
+ /* Optional ITU trap */
+ if (u_val == 0)
+ u_val = 0x02;
+#endif
+ return u_val;
+ }
+ /*- End of function --------------------------------------------------------*/
+
+ /*! \brief Decode an u-law sample to a linear value.
+ \param ulaw The u-law sample to decode.
+ \return The linear value.
+ */
+ static __inline__ int16_t ulaw_to_linear(uint8_t ulaw)
+ {
+ int t;
+
+ /* Complement to obtain normal u-law value. */
+ ulaw = ~ulaw;
+ /*
+ * Extract and bias the quantization bits. Then
+ * shift up by the segment number and subtract out the bias.
+ */
+ t = (((ulaw & 0x0F) << 3) + ULAW_BIAS) << (((int) ulaw & 0x70) >> 4);
+ return (int16_t) ((ulaw & 0x80) ? (ULAW_BIAS - t) : (t - ULAW_BIAS));
+ }
+ /*- End of function --------------------------------------------------------*/
+
+ /*
+ * A-law is basically as follows:
+ *
+ * Linear Input Code Compressed Code
+ * ----------------- ---------------
+ * 0000000wxyza 000wxyz
+ * 0000001wxyza 001wxyz
+ * 000001wxyzab 010wxyz
+ * 00001wxyzabc 011wxyz
+ * 0001wxyzabcd 100wxyz
+ * 001wxyzabcde 101wxyz
+ * 01wxyzabcdef 110wxyz
+ * 1wxyzabcdefg 111wxyz
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+
+#define ALAW_AMI_MASK 0x55
+
+ /*! \brief Encode a linear sample to A-law
+ \param linear The sample to encode.
+ \return The A-law value.
+ */
+ static __inline__ uint8_t linear_to_alaw(int linear)
+ {
+ int mask;
+ int seg;
+
+ if (linear >= 0)
+ {
+ /* Sign (bit 7) bit = 1 */
+ mask = ALAW_AMI_MASK | 0x80;
+ }
+ else
+ {
+ /* Sign (bit 7) bit = 0 */
+ mask = ALAW_AMI_MASK;
+ linear = -linear - 8;
+ }
+
+ /* Convert the scaled magnitude to segment number. */
+ seg = top_bit(linear | 0xFF) - 7;
+ if (seg >= 8)
+ {
+ if (linear >= 0)
+ {
+ /* Out of range. Return maximum value. */
+ return (uint8_t) (0x7F ^ mask);
+ }
+ /* We must be just a tiny step below zero */
+ return (uint8_t) (0x00 ^ mask);
+ }
+ /* Combine the sign, segment, and quantization bits. */
+ return (uint8_t) (((seg << 4) | ((linear >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask);
+ }
+ /*- End of function --------------------------------------------------------*/
+
+ /*! \brief Decode an A-law sample to a linear value.
+ \param alaw The A-law sample to decode.
+ \return The linear value.
+ */
+ static __inline__ int16_t alaw_to_linear(uint8_t alaw)
+ {
+ int i;
+ int seg;
+
+ alaw ^= ALAW_AMI_MASK;
+ i = ((alaw & 0x0F) << 4);
+ seg = (((int) alaw & 0x70) >> 4);
+ if (seg)
+ i = (i + 0x108) << (seg - 1);
+ else
+ i += 8;
+ return (int16_t) ((alaw & 0x80) ? i : -i);
+ }
+ /*- End of function --------------------------------------------------------*/
+
+ /*! \brief Transcode from A-law to u-law, using the procedure defined in G.711.
+ \param alaw The A-law sample to transcode.
+ \return The best matching u-law value.
+ */
+ uint8_t alaw_to_ulaw(uint8_t alaw);
+
+ /*! \brief Transcode from u-law to A-law, using the procedure defined in G.711.
+ \param alaw The u-law sample to transcode.
+ \return The best matching A-law value.
+ */
+ uint8_t ulaw_to_alaw(uint8_t ulaw);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/*- End of file ------------------------------------------------------------*/
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/include/hashtable.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/include/hashtable.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/hashtable.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,228 @@
+/* Copyright (C) 2002 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_CWC22_H__
+#define __HASHTABLE_CWC22_H__
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+#endif
+#include "openzap.h"
+
+struct hashtable;
+struct hashtable_iterator;
+
+/* Example of use:
+ *
+ * struct hashtable *h;
+ * struct some_key *k;
+ * struct some_value *v;
+ *
+ * static unsigned int hash_from_key_fn( void *k );
+ * static int keys_equal_fn ( void *key1, void *key2 );
+ *
+ * h = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
+ * k = (struct some_key *) malloc(sizeof(struct some_key));
+ * v = (struct some_value *) malloc(sizeof(struct some_value));
+ *
+ * (initialise k and v to suitable values)
+ *
+ * if (! hashtable_insert(h,k,v) )
+ * { exit(-1); }
+ *
+ * if (NULL == (found = hashtable_search(h,k) ))
+ * { printf("not found!"); }
+ *
+ * if (NULL == (found = hashtable_remove(h,k) ))
+ * { printf("Not found\n"); }
+ *
+ */
+
+/* Macros may be used to define type-safe(r) hashtable access functions, with
+ * methods specialized to take known key and value types as parameters.
+ *
+ * Example:
+ *
+ * Insert this at the start of your file:
+ *
+ * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value);
+ *
+ * This defines the functions 'insert_some', 'search_some' and 'remove_some'.
+ * These operate just like hashtable_insert etc., with the same parameters,
+ * but their function signatures have 'struct some_key *' rather than
+ * 'void *', and hence can generate compile time errors if your program is
+ * supplying incorrect data as a key (and similarly for value).
+ *
+ * Note that the hash and key equality functions passed to create_hashtable
+ * still take 'void *' parameters instead of 'some key *'. This shouldn't be
+ * a difficult issue as they're only defined and passed once, and the other
+ * functions will ensure that only valid keys are supplied to them.
+ *
+ * The cost for this checking is increased code size and runtime overhead
+ * - if performance is important, it may be worth switching back to the
+ * unsafe methods once your program has been debugged with the safe methods.
+ * This just requires switching to some simple alternative defines - eg:
+ * #define insert_some hashtable_insert
+ *
+ */
+
+/*****************************************************************************
+ * create_hashtable
+
+ * @name create_hashtable
+ * @param minsize minimum initial size of hashtable
+ * @param hashfunction function for hashing keys
+ * @param key_eq_fn function for determining key equality
+ * @return newly created hashtable or NULL on failure
+ */
+
+OZ_DECLARE(struct hashtable *)
+create_hashtable(unsigned int minsize,
+ unsigned int (*hashfunction) (void*),
+ int (*key_eq_fn) (void*,void*));
+
+/*****************************************************************************
+ * hashtable_insert
+
+ * @name hashtable_insert
+ * @param h the hashtable to insert into
+ * @param k the key - hashtable claims ownership and will free on removal
+ * @param v the value - does not claim ownership
+ * @return non-zero for successful insertion
+ *
+ * This function will cause the table to expand if the insertion would take
+ * the ratio of entries to table size over the maximum load factor.
+ *
+ * This function does not check for repeated insertions with a duplicate key.
+ * The value returned when using a duplicate key is undefined -- when
+ * the hashtable changes size, the order of retrieval of duplicate key
+ * entries is reversed.
+ * If in doubt, remove before insert.
+ */
+
+
+typedef enum {
+ HASHTABLE_FLAG_NONE = 0,
+ HASHTABLE_FLAG_FREE_KEY = (1 << 0),
+ HASHTABLE_FLAG_FREE_VALUE = (1 << 1)
+} hashtable_flag_t;
+
+OZ_DECLARE(int)
+hashtable_insert(struct hashtable *h, void *k, void *v, hashtable_flag_t flags);
+
+#define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \
+ int fnname (struct hashtable *h, keytype *k, valuetype *v) \
+ { \
+ return hashtable_insert(h,k,v); \
+ }
+
+/*****************************************************************************
+ * hashtable_search
+
+ * @name hashtable_search
+ * @param h the hashtable to search
+ * @param k the key to search for - does not claim ownership
+ * @return the value associated with the key, or NULL if none found
+ */
+
+OZ_DECLARE(void *)
+hashtable_search(struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
+ valuetype * fnname (struct hashtable *h, keytype *k) \
+ { \
+ return (valuetype *) (hashtable_search(h,k)); \
+ }
+
+/*****************************************************************************
+ * hashtable_remove
+
+ * @name hashtable_remove
+ * @param h the hashtable to remove the item from
+ * @param k the key to search for - does not claim ownership
+ * @return the value associated with the key, or NULL if none found
+ */
+
+OZ_DECLARE(void *) /* returns value */
+hashtable_remove(struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
+ valuetype * fnname (struct hashtable *h, keytype *k) \
+ { \
+ return (valuetype *) (hashtable_remove(h,k)); \
+ }
+
+
+/*****************************************************************************
+ * hashtable_count
+
+ * @name hashtable_count
+ * @param h the hashtable
+ * @return the number of items stored in the hashtable
+ */
+OZ_DECLARE(unsigned int)
+hashtable_count(struct hashtable *h);
+
+
+/*****************************************************************************
+ * hashtable_destroy
+
+ * @name hashtable_destroy
+ * @param h the hashtable
+ * @param free_values whether to call 'free' on the remaining values
+ */
+
+OZ_DECLARE(void)
+hashtable_destroy(struct hashtable *h);
+
+OZ_DECLARE(struct hashtable_iterator*) hashtable_first(struct hashtable *h);
+OZ_DECLARE(struct hashtable_iterator*) hashtable_next(struct hashtable_iterator *i);
+OZ_DECLARE(void) hashtable_this(struct hashtable_iterator *i, const void **key, int *klen, void **val);
+
+#endif /* __HASHTABLE_CWC22_H__ */
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * 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.
+ */
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/include/hashtable_itr.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/include/hashtable_itr.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/hashtable_itr.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,129 @@
+/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_ITR_CWC22__
+#define __HASHTABLE_ITR_CWC22__
+#include "hashtable.h"
+#include "hashtable_private.h" /* needed to enable inlining */
+
+/*****************************************************************************/
+/* This struct is only concrete here to allow the inlining of two of the
+ * accessor functions. */
+struct hashtable_itr
+{
+ struct hashtable *h;
+ struct entry *e;
+ struct entry *parent;
+ unsigned int index;
+};
+
+
+/*****************************************************************************/
+/* hashtable_iterator
+ */
+
+struct hashtable_itr *
+hashtable_iterator(struct hashtable *h);
+
+/*****************************************************************************/
+/* hashtable_iterator_key
+ * - return the value of the (key,value) pair at the current position */
+extern __inline__ void *
+hashtable_iterator_key(struct hashtable_itr *i);
+
+extern __inline__ void *
+hashtable_iterator_key(struct hashtable_itr *i)
+{
+ return i->e->k;
+}
+
+/*****************************************************************************/
+/* value - return the value of the (key,value) pair at the current position */
+
+extern __inline__ void *
+hashtable_iterator_value(struct hashtable_itr *i);
+
+extern __inline__ void *
+hashtable_iterator_value(struct hashtable_itr *i)
+{
+ return i->e->v;
+}
+
+/*****************************************************************************/
+/* advance - advance the iterator to the next element
+ * returns zero if advanced to end of table */
+
+int
+hashtable_iterator_advance(struct hashtable_itr *itr);
+
+/*****************************************************************************/
+/* remove - remove current element and advance the iterator to the next element
+ * NB: if you need the value to free it, read it before
+ * removing. ie: beware memory leaks!
+ * returns zero if advanced to end of table */
+
+int
+hashtable_iterator_remove(struct hashtable_itr *itr);
+
+/*****************************************************************************/
+/* search - overwrite the supplied iterator, to point to the entry
+ * matching the supplied key.
+ h points to the hashtable to be searched.
+ * returns zero if not found. */
+int
+hashtable_iterator_search(struct hashtable_itr *itr,
+ struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \
+ int fnname (struct hashtable_itr *i, struct hashtable *h, keytype *k) \
+ { \
+ return (hashtable_iterator_search(i,h,k)); \
+ }
+
+
+
+#endif /* __HASHTABLE_ITR_CWC22__*/
+
+/*
+ * Copyright (c) 2002, 2004, Christopher Clark
+ * 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.
+ */
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/openzap/src/include/hashtable_private.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/include/hashtable_private.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/hashtable_private.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,105 @@
+/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_PRIVATE_CWC22_H__
+#define __HASHTABLE_PRIVATE_CWC22_H__
+
+#include "hashtable.h"
+
+
+/*****************************************************************************/
+
+struct entry
+{
+ void *k, *v;
+ unsigned int h;
+ hashtable_flag_t flags;
+ struct entry *next;
+};
+
+struct hashtable_iterator {
+ unsigned int pos;
+ struct entry *e;
+ struct hashtable *h;
+};
+
+struct hashtable {
+ unsigned int tablelength;
+ struct entry **table;
+ unsigned int entrycount;
+ unsigned int loadlimit;
+ unsigned int primeindex;
+ unsigned int (*hashfn) (void *k);
+ int (*eqfn) (void *k1, void *k2);
+ struct hashtable_iterator iterator;
+};
+
+/*****************************************************************************/
+unsigned int
+hash(struct hashtable *h, void *k);
+
+/*****************************************************************************/
+/* indexFor */
+static __inline__ unsigned int
+indexFor(unsigned int tablelength, unsigned int hashvalue) {
+ return (hashvalue % tablelength);
+}
+
+/* Only works if tablelength == 2^N */
+/*static inline unsigned int
+ indexFor(unsigned int tablelength, unsigned int hashvalue)
+ {
+ return (hashvalue & (tablelength - 1u));
+ }
+*/
+
+/*****************************************************************************/
+#define freekey(X) free(X)
+/*define freekey(X) ; */
+
+
+/*****************************************************************************/
+
+#endif /* __HASHTABLE_PRIVATE_CWC22_H__*/
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * 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.
+ */
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/include/libteletone.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/include/libteletone.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/libteletone.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,161 @@
+/*
+ * libteletone
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * 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 libteletone
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * libteletone.h -- Tone Generator/Detector
+ *
+ *
+ *
+ * Exception:
+ * The author hereby grants the use of this source code under the
+ * following license if and only if the source code is distributed
+ * as part of the openzap library. Any use or distribution of this
+ * source code outside the scope of the openzap library will nullify the
+ * following license and reinact the MPL 1.1 as stated above.
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+#ifndef LIBTELETONE_H
+#define LIBTELETONE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <math.h>
+
+#define TELETONE_MAX_DTMF_DIGITS 128
+#define TELETONE_MAX_TONES 18
+#define TELETONE_TONE_RANGE 127
+
+typedef double teletone_process_t;
+
+/*! \file libteletone.h
+ \brief Top level include file
+
+ This file should be included by applications using the library
+*/
+
+/*! \brief An abstraction to store a tone mapping */
+typedef struct {
+ /*! An array of tone frequencies */
+ teletone_process_t freqs[TELETONE_MAX_TONES];
+} teletone_tone_map_t;
+
+#if !defined(M_PI)
+/* C99 systems may not define M_PI */
+#define M_PI 3.14159265358979323846264338327
+#endif
+
+#ifdef _MSC_VER
+typedef __int16 int16_t;
+#endif
+
+#if (_MSC_VER >= 1400) // VC8+
+#define teletone_assert(expr) assert(expr);__analysis_assume( expr )
+#else
+#define teletone_assert(expr) assert(expr)
+#endif
+
+#ifdef _MSC_VER
+#if defined(TT_DECLARE_STATIC)
+#define TELETONE_API(type) type __stdcall
+#define TELETONE_API_NONSTD(type) type __cdecl
+#define TELETONE_API_DATA
+#elif defined(TELETONE_EXPORTS)
+#define TELETONE_API(type) __declspec(dllexport) type __stdcall
+#define TELETONE_API_NONSTD(type) __declspec(dllexport) type __cdecl
+#define TELETONE_API_DATA __declspec(dllexport)
+#else
+#define TELETONE_API(type) __declspec(dllimport) type __stdcall
+#define TELETONE_API_NONSTD(type) __declspec(dllimport) type __cdecl
+#define TELETONE_API_DATA __declspec(dllimport)
+#endif
+#else
+#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(HAVE_VISIBILITY)
+#define TELETONE_API(type) __attribute__((visibility("default"))) type
+#define TELETONE_API_NONSTD(type) __attribute__((visibility("default"))) type
+#define TELETONE_API_DATA __attribute__((visibility("default")))
+#else
+#define TELETONE_API(type) type
+#define TELETONE_API_NONSTD(type) type
+#define TELETONE_API_DATA
+#endif
+#endif
+
+#include <libteletone_generate.h>
+#include <libteletone_detect.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/include/libteletone_detect.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/include/libteletone_detect.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/libteletone_detect.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,240 @@
+/*
+ * libteletone
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * libteletone_detect.c Tone Detection Code
+ *
+ * Exception:
+ * The author hereby grants the use of this source code under the
+ * following license if and only if the source code is distributed
+ * as part of the openzap library. Any use or distribution of this
+ * source code outside the scope of the openzap library will nullify the
+ * following license and reinact the MPL 1.1 as stated above.
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ *
+ *********************************************************************************
+ *
+ * Derived from tone_detect.h - General telephony tone detection, and specific
+ * detection of DTMF.
+ *
+ * Copyright (C) 2001 Steve Underwood <steveu@coppice.org>
+ *
+ * Despite my general liking of the GPL, I place this code in the
+ * public domain for the benefit of all mankind - even the slimy
+ * ones who might try to proprietize my work and use it to my
+ * detriment.
+ *
+ *
+ */
+
+#ifndef LIBTELETONE_DETECT_H
+#define LIBTELETONE_DETECT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <libteletone.h>
+
+ /*! \file libteletone_detect.h
+ \brief Tone Detection Routines
+
+ This module is responsible for tone detection specifics
+ */
+
+#ifndef FALSE
+#define FALSE 0
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+#endif
+
+ /* Basic DTMF specs:
+ *
+ * Minimum tone on = 40ms
+ * Minimum tone off = 50ms
+ * Maximum digit rate = 10 per second
+ * Normal twist <= 8dB accepted
+ * Reverse twist <= 4dB accepted
+ * S/N >= 15dB will detect OK
+ * Attenuation <= 26dB will detect OK
+ * Frequency tolerance +- 1.5% will detect, +-3.5% will reject
+ */
+
+#define DTMF_THRESHOLD 8.0e7
+#define DTMF_NORMAL_TWIST 6.3 /* 8dB */
+#define DTMF_REVERSE_TWIST 2.5 /* 4dB */
+#define DTMF_RELATIVE_PEAK_ROW 6.3 /* 8dB */
+#define DTMF_RELATIVE_PEAK_COL 6.3 /* 8dB */
+#define DTMF_2ND_HARMONIC_ROW 2.5 /* 4dB */
+#define DTMF_2ND_HARMONIC_COL 63.1 /* 18dB */
+#define GRID_FACTOR 4
+#define BLOCK_LEN 102
+#define M_TWO_PI 2.0*M_PI
+
+ /*! \brief A continer for the elements of a Goertzel Algorithm (The names are from his formula) */
+ typedef struct {
+ float v2;
+ float v3;
+ double fac;
+ } teletone_goertzel_state_t;
+
+ /*! \brief A container for a DTMF detection state.*/
+ typedef struct {
+ int hit1;
+ int hit2;
+ int hit3;
+ int hit4;
+ int mhit;
+
+ teletone_goertzel_state_t row_out[GRID_FACTOR];
+ teletone_goertzel_state_t col_out[GRID_FACTOR];
+ teletone_goertzel_state_t row_out2nd[GRID_FACTOR];
+ teletone_goertzel_state_t col_out2nd[GRID_FACTOR];
+ float energy;
+
+ int current_sample;
+ char digits[TELETONE_MAX_DTMF_DIGITS + 1];
+ int current_digits;
+ int detected_digits;
+ int lost_digits;
+ int digit_hits[16];
+ } teletone_dtmf_detect_state_t;
+
+ /*! \brief An abstraction to store the coefficient of a tone frequency */
+ typedef struct {
+ float fac;
+ } teletone_detection_descriptor_t;
+
+ /*! \brief A container for a single multi-tone detection
+ TELETONE_MAX_TONES dictates the maximum simultaneous tones that can be present
+ in a multi-tone representation.
+ */
+ typedef struct {
+ int sample_rate;
+
+ teletone_detection_descriptor_t tdd[TELETONE_MAX_TONES];
+ teletone_goertzel_state_t gs[TELETONE_MAX_TONES];
+ teletone_goertzel_state_t gs2[TELETONE_MAX_TONES];
+ int tone_count;
+
+ float energy;
+ int current_sample;
+
+ int min_samples;
+ int total_samples;
+
+ int positives;
+ int negatives;
+ int hits;
+
+ int positive_factor;
+ int negative_factor;
+ int hit_factor;
+
+ } teletone_multi_tone_t;
+
+
+ /*!
+ \brief Initilize a multi-frequency tone detector
+ \param mt the multi-frequency tone descriptor
+ \param map a representation of the multi-frequency tone
+ */
+TELETONE_API(void) teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map);
+
+ /*!
+ \brief Check a sample buffer for the presence of the mulit-frequency tone described by mt
+ \param mt the multi-frequency tone descriptor
+ \param sample_buffer an array aof 16 bit signed linear samples
+ \param samples the number of samples present in sample_buffer
+ \return true when the tone was detected or false when it is not
+ */
+TELETONE_API(int) teletone_multi_tone_detect (teletone_multi_tone_t *mt,
+ int16_t sample_buffer[],
+ int samples);
+
+ /*!
+ \brief Initilize a DTMF detection state object
+ \param dtmf_detect_state the DTMF detection state to initilize
+ \param sample_rate the desired sample rate
+ */
+TELETONE_API(void) teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate);
+
+ /*!
+ \brief Check a sample buffer for the presence of DTMF digits
+ \param dtmf_detect_state the detection state object to check
+ \param sample_buffer an array aof 16 bit signed linear samples
+ \param samples the number of samples present in sample_buffer
+ \return true when DTMF was detected or false when it is not
+ */
+TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
+ int16_t sample_buffer[],
+ int samples);
+ /*!
+ \brief retrieve any collected digits into a string buffer
+ \param dtmf_detect_state the detection state object to check
+ \param buf the string buffer to write to
+ \param max the maximum length of buf
+ \return the number of characters written to buf
+ */
+TELETONE_API(int) teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state,
+ char *buf,
+ int max);
+
+ /*!
+ \brief Step through the Goertzel Algorithm for each sample in a buffer
+ \param goertzel_state the goertzel state to step the samples through
+ \param sample_buffer an array aof 16 bit signed linear samples
+ \param samples the number of samples present in sample_buffer
+ */
+TELETONE_API(void) teletone_goertzel_update(teletone_goertzel_state_t *goertzel_state,
+ int16_t sample_buffer[],
+ int samples);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/include/libteletone_generate.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/include/libteletone_generate.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/libteletone_generate.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,281 @@
+/*
+ * libteletone
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+#ifndef LIBTELETONE_GENERATE_H
+#define LIBTELETONE_GENERATE_H
+#ifdef __cplusplus
+extern "C" {
+#ifdef _doh
+}
+#endif
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+#ifndef __inline__
+#define __inline__ inline
+#endif
+#endif
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+
+typedef unsigned __int64 uint64_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int8 uint8_t;
+typedef __int64 int64_t;
+typedef __int32 int32_t;
+typedef __int16 int16_t;
+typedef __int8 int8_t;
+#else
+#include <stdint.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <math.h>
+#if !defined(powf) && !defined(_WIN64)
+extern float powf (float, float);
+#endif
+#include <string.h>
+#include <errno.h>
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+#include <assert.h>
+#include <stdarg.h>
+#include <libteletone.h>
+
+#define TELETONE_VOL_DB_MAX 0
+#define TELETONE_VOL_DB_MIN -63
+#define MAX_PHASE_TONES 4
+
+struct teletone_dds_state {
+ uint32_t phase_rate[MAX_PHASE_TONES];
+ uint32_t scale_factor;
+ uint32_t phase_accumulator;
+ teletone_process_t tx_level;
+};
+typedef struct teletone_dds_state teletone_dds_state_t;
+
+#define SINE_TABLE_MAX 128
+#define SINE_TABLE_LEN (SINE_TABLE_MAX - 1)
+#define MAX_PHASE_ACCUMULATOR 0x10000 * 0x10000
+/* 3.14 == the max power on ulaw (alaw is 3.17) */
+/* 3.02 represents twice the power */
+#define DBM0_MAX_POWER (3.14f + 3.02f)
+
+TELETONE_API_DATA extern int16_t TELETONE_SINES[SINE_TABLE_MAX];
+
+static __inline__ int32_t teletone_dds_phase_rate(teletone_process_t tone, uint32_t rate)
+{
+ return (int32_t) ((tone * MAX_PHASE_ACCUMULATOR) / rate);
+}
+
+static __inline__ int16_t teletone_dds_state_modulate_sample(teletone_dds_state_t *dds, uint32_t pindex)
+{
+ int32_t bitmask = dds->phase_accumulator, sine_index = (bitmask >>= 23) & SINE_TABLE_LEN;
+ int16_t sample;
+
+ if (pindex >= MAX_PHASE_TONES) {
+ pindex = 0;
+ }
+
+ if (bitmask & SINE_TABLE_MAX) {
+ sine_index = SINE_TABLE_LEN - sine_index;
+ }
+
+ sample = TELETONE_SINES[sine_index];
+
+ if (bitmask & (SINE_TABLE_MAX * 2)) {
+ sample *= -1;
+ }
+
+ dds->phase_accumulator += dds->phase_rate[pindex];
+ return (int16_t) (sample * dds->scale_factor >> 15);
+}
+
+static __inline__ void teletone_dds_state_set_tx_level(teletone_dds_state_t *dds, float tx_level)
+{
+ dds->scale_factor = (int) (powf(10.0f, (tx_level - DBM0_MAX_POWER) / 20.0f) * (32767.0f * 1.414214f));
+ dds->tx_level = tx_level;
+}
+
+static __inline__ void teletone_dds_state_reset_accum(teletone_dds_state_t *dds)
+{
+ dds->phase_accumulator = 0;
+}
+
+static __inline__ int teletone_dds_state_set_tone(teletone_dds_state_t *dds, teletone_process_t tone, uint32_t rate, uint32_t pindex)
+{
+ if (pindex < MAX_PHASE_TONES) {
+ dds->phase_rate[pindex] = teletone_dds_phase_rate(tone, rate);
+ return 0;
+ }
+
+ return -1;
+}
+
+
+
+/*! \file libteletone_generate.h
+ \brief Tone Generation Routines
+
+ This module is responsible for tone generation specifics
+*/
+
+typedef int16_t teletone_audio_t;
+struct teletone_generation_session;
+typedef int (*tone_handler)(struct teletone_generation_session *ts, teletone_tone_map_t *map);
+
+/*! \brief An abstraction to store a tone generation session */
+struct teletone_generation_session {
+ /*! An array of tone mappings to character mappings */
+ teletone_tone_map_t TONES[TELETONE_TONE_RANGE];
+ /*! The number of channels the output audio should be in */
+ int channels;
+ /*! The Rate in hz of the output audio */
+ int rate;
+ /*! The duration (in samples) of the output audio */
+ int duration;
+ /*! The duration of silence to append after the initial audio is generated */
+ int wait;
+ /*! The duration (in samples) of the output audio (takes prescedence over actual duration value) */
+ int tmp_duration;
+ /*! The duration of silence to append after the initial audio is generated (takes prescedence over actual wait value)*/
+ int tmp_wait;
+ /*! Number of loops to repeat a single instruction*/
+ int loops;
+ /*! Number of loops to repeat the entire set of instructions*/
+ int LOOPS;
+ /*! Number to mutiply total samples by to determine when to begin ascent or decent e.g. 0=beginning 4=(last 25%) */
+ float decay_factor;
+ /*! Direction to perform volume increase/decrease 1/-1*/
+ int decay_direction;
+ /*! Number of samples between increase/decrease of volume */
+ int decay_step;
+ /*! Volume factor of the tone */
+ float volume;
+ /*! Debug on/off */
+ int debug;
+ /*! FILE stream to write debug data to */
+ FILE *debug_stream;
+ /*! Extra user data to attach to the session*/
+ void *user_data;
+ /*! Buffer for storing sample data (dynamic) */
+ teletone_audio_t *buffer;
+ /*! Size of the buffer */
+ int datalen;
+ /*! In-Use size of the buffer */
+ int samples;
+ /*! Callback function called during generation */
+ int dynamic;
+ tone_handler handler;
+};
+
+typedef struct teletone_generation_session teletone_generation_session_t;
+
+
+/*!
+ \brief Assign a set of tones to a tone_session indexed by a paticular index/character
+ \param ts the tone generation session
+ \param index the index to map the tone to
+ \param ... up to TELETONE_MAX_TONES frequencies terminated by 0.0
+ \return 0
+*/
+TELETONE_API(int) teletone_set_tone(teletone_generation_session_t *ts, int index, ...);
+
+/*!
+ \brief Assign a set of tones to a single tone map
+ \param map the map to assign the tones to
+ \param ... up to TELETONE_MAX_TONES frequencies terminated by 0.0
+ \return 0
+*/
+TELETONE_API(int) teletone_set_map(teletone_tone_map_t *map, ...);
+
+/*!
+ \brief Initilize a tone generation session
+ \param ts the tone generation session to initilize
+ \param buflen the size of the buffer(in samples) to dynamically allocate
+ \param handler a callback function to execute when a tone generation instruction is complete
+ \param user_data optional user data to send
+ \return 0
+*/
+TELETONE_API(int) teletone_init_session(teletone_generation_session_t *ts, int buflen, tone_handler handler, void *user_data);
+
+/*!
+ \brief Free the buffer allocated by a tone generation session
+ \param ts the tone generation session to destroy
+ \return 0
+*/
+TELETONE_API(int) teletone_destroy_session(teletone_generation_session_t *ts);
+
+/*!
+ \brief Execute a single tone generation instruction
+ \param ts the tone generation session to consult for parameters
+ \param map the tone mapping to use for the frequencies
+ \return 0
+*/
+TELETONE_API(int) teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *map);
+
+/*!
+ \brief Execute a tone generation script and call callbacks after each instruction
+ \param ts the tone generation session to execute on
+ \param cmd the script to execute
+ \return 0
+*/
+TELETONE_API(int) teletone_run(teletone_generation_session_t *ts, const char *cmd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/include/openzap.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/include/openzap.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/openzap.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,797 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#ifndef OPENZAP_H
+#define OPENZAP_H
+
+
+#if !defined(_XOPEN_SOURCE) && !defined(__FreeBSD__)
+#define _XOPEN_SOURCE 600
+#endif
+
+#ifndef HAVE_STRINGS_H
+#define HAVE_STRINGS_H 1
+#endif
+#ifndef HAVE_SYS_SOCKET_H
+#define HAVE_SYS_SOCKET_H 1
+#endif
+
+#ifndef __WINDOWS__
+#if defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32) || defined(_WIN64)
+#define __WINDOWS__
+#endif
+#endif
+
+#ifdef _MSC_VER
+#if defined(OZ_DECLARE_STATIC)
+#define OZ_DECLARE(type) type __stdcall
+#define OZ_DECLARE_NONSTD(type) type __cdecl
+#define OZ_DECLARE_DATA
+#elif defined(OPENZAP_EXPORTS)
+#define OZ_DECLARE(type) __declspec(dllexport) type __stdcall
+#define OZ_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl
+#define OZ_DECLARE_DATA __declspec(dllexport)
+#else
+#define OZ_DECLARE(type) __declspec(dllimport) type __stdcall
+#define OZ_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl
+#define OZ_DECLARE_DATA __declspec(dllimport)
+#endif
+#define EX_DECLARE_DATA __declspec(dllexport)
+#else
+#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(HAVE_VISIBILITY)
+#define OZ_DECLARE(type) __attribute__((visibility("default"))) type
+#define OZ_DECLARE_NONSTD(type) __attribute__((visibility("default"))) type
+#define OZ_DECLARE_DATA __attribute__((visibility("default")))
+#else
+#define OZ_DECLARE(type) type
+#define OZ_DECLARE_NONSTD(type) type
+#define OZ_DECLARE_DATA
+#endif
+#define EX_DECLARE_DATA
+#endif
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+#if (_MSC_VER >= 1400) /* VC8+ */
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+#ifndef _CRT_NONSTDC_NO_DEPRECATE
+#define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+#endif
+#ifndef strcasecmp
+#define strcasecmp(s1, s2) _stricmp(s1, s2)
+#endif
+#ifndef strncasecmp
+#define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n)
+#endif
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#ifndef S_IRUSR
+#define S_IRUSR _S_IREAD
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR _S_IWRITE
+#endif
+#undef HAVE_STRINGS_H
+#undef HAVE_SYS_SOCKET_H
+/* disable warning for zero length array in a struct */
+/* this will cause errors on c99 and ansi compliant compilers and will need to be fixed in the wanpipe header files */
+#pragma warning(disable:4706)
+#pragma comment(lib, "Winmm")
+#endif
+
+#define ZAP_THREAD_STACKSIZE 240 * 1024
+#define ZAP_ENUM_NAMES(_NAME, _STRINGS) static const char * _NAME [] = { _STRINGS , NULL };
+#define ZAP_STR2ENUM_P(_FUNC1, _FUNC2, _TYPE) OZ_DECLARE(_TYPE) _FUNC1 (const char *name); OZ_DECLARE(const char *) _FUNC2 (_TYPE type);
+#define ZAP_STR2ENUM(_FUNC1, _FUNC2, _TYPE, _STRINGS, _MAX) \
+ OZ_DECLARE(_TYPE) _FUNC1 (const char *name) \
+ { \
+ int i; \
+ _TYPE t = _MAX ; \
+ \
+ for (i = 0; i < _MAX ; i++) { \
+ if (!strcasecmp(name, _STRINGS[i])) { \
+ t = (_TYPE) i; \
+ break; \
+ } \
+ } \
+ \
+ return t; \
+ } \
+ OZ_DECLARE(const char *) _FUNC2 (_TYPE type) \
+ { \
+ if (type > _MAX) { \
+ type = _MAX; \
+ } \
+ return _STRINGS[(int)type]; \
+ } \
+
+#define zap_true(expr) \
+ (expr && ( !strcasecmp(expr, "yes") || \
+ !strcasecmp(expr, "on") || \
+ !strcasecmp(expr, "true") || \
+ !strcasecmp(expr, "enabled") || \
+ !strcasecmp(expr, "active") || \
+ atoi(expr))) ? 1 : 0
+
+
+#include <time.h>
+#ifndef __WINDOWS__
+#include <sys/time.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include <assert.h>
+#include "zap_types.h"
+#include "hashtable.h"
+#include "zap_config.h"
+#include "g711.h"
+#include "libteletone.h"
+#include "zap_buffer.h"
+#include "zap_threadmutex.h"
+
+#ifdef __WINDOWS__
+#define zap_sleep(x) Sleep(x)
+#else
+#define zap_sleep(x) usleep(x * 1000)
+#endif
+
+#ifdef NDEBUG
+#undef assert
+#define assert(_Expression) ((void)(_Expression))
+#endif
+
+#define ZAP_MAX_CHANNELS_PHYSICAL_SPAN 32
+#define ZAP_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN 32
+#define ZAP_MAX_CHANNELS_SPAN ZAP_MAX_CHANNELS_PHYSICAL_SPAN * ZAP_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN
+#define ZAP_MAX_SPANS_INTERFACE 128
+
+#define GOTO_STATUS(label,st) status = st; goto label ;
+
+#define zap_copy_string(x,y,z) strncpy(x, y, z - 1)
+#define zap_set_string(x,y) strncpy(x, y, sizeof(x)-1)
+#define zap_strlen_zero(s) (!s || *s == '\0')
+#define zap_strlen_zero_buf(s) (*s == '\0')
+
+
+#define zap_channel_test_feature(obj, flag) ((obj)->features & flag)
+#define zap_channel_set_feature(obj, flag) (obj)->features |= (flag)
+#define zap_channel_clear_feature(obj, flag) (obj)->features &= ~(flag)
+#define zap_channel_set_member_locked(obj, _m, _v) zap_mutex_lock(obj->mutex); obj->_m = _v; zap_mutex_unlock(obj->mutex)
+
+/*!
+ \brief Test for the existance of a flag on an arbitary object
+ \command obj the object to test
+ \command flag the or'd list of flags to test
+ \return true value if the object has the flags defined
+*/
+#define zap_test_flag(obj, flag) ((obj)->flags & flag)
+#define zap_test_pflag(obj, flag) ((obj)->pflags & flag)
+#define zap_test_sflag(obj, flag) ((obj)->sflags & flag)
+
+
+#define zap_set_alarm_flag(obj, flag) (obj)->alarm_flags |= (flag)
+#define zap_clear_alarm_flag(obj, flag) (obj)->alarm_flags &= ~(flag)
+#define zap_test_alarm_flag(obj, flag) ((obj)->alarm_flags & flag)
+
+/*!
+ \brief Set a flag on an arbitrary object
+ \command obj the object to set the flags on
+ \command flag the or'd list of flags to set
+*/
+#define zap_set_flag(obj, flag) (obj)->flags |= (flag)
+#define zap_set_flag_locked(obj, flag) assert(obj->mutex != NULL); \
+ zap_mutex_lock(obj->mutex); \
+ (obj)->flags |= (flag); \
+ zap_mutex_unlock(obj->mutex);
+
+#define zap_set_pflag(obj, flag) (obj)->pflags |= (flag)
+#define zap_set_pflag_locked(obj, flag) assert(obj->mutex != NULL); \
+ zap_mutex_lock(obj->mutex); \
+ (obj)->pflags |= (flag); \
+ zap_mutex_unlock(obj->mutex);
+
+#define zap_set_sflag(obj, flag) (obj)->sflags |= (flag)
+#define zap_set_sflag_locked(obj, flag) assert(obj->mutex != NULL); \
+ zap_mutex_lock(obj->mutex); \
+ (obj)->sflags |= (flag); \
+ zap_mutex_unlock(obj->mutex);
+
+/*!
+ \brief Clear a flag on an arbitrary object while locked
+ \command obj the object to test
+ \command flag the or'd list of flags to clear
+*/
+#define zap_clear_flag(obj, flag) (obj)->flags &= ~(flag)
+
+#define zap_clear_flag_locked(obj, flag) assert(obj->mutex != NULL); zap_mutex_lock(obj->mutex); (obj)->flags &= ~(flag); zap_mutex_unlock(obj->mutex);
+
+#define zap_clear_pflag(obj, flag) (obj)->pflags &= ~(flag)
+
+#define zap_clear_pflag_locked(obj, flag) assert(obj->mutex != NULL); zap_mutex_lock(obj->mutex); (obj)->pflags &= ~(flag); zap_mutex_unlock(obj->mutex);
+
+#define zap_clear_sflag(obj, flag) (obj)->sflags &= ~(flag)
+
+#define zap_clear_sflag_locked(obj, flag) assert(obj->mutex != NULL); zap_mutex_lock(obj->mutex); (obj)->sflags &= ~(flag); zap_mutex_unlock(obj->mutex);
+
+
+#define zap_set_state_locked(obj, s) if ( obj->state == s ) { \
+ if (s != ZAP_CHANNEL_STATE_HANGUP) zap_log(ZAP_LOG_WARNING, "Why bother changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, zap_channel_state2str(obj->state), zap_channel_state2str(s)); \
+ } else if (zap_test_flag(obj, ZAP_CHANNEL_READY)) { \
+ int st = obj->state; \
+ zap_channel_set_state(obj, s, 1); \
+ if (obj->state == s) zap_log(ZAP_LOG_DEBUG, "Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, zap_channel_state2str(st), zap_channel_state2str(s)); \
+ else if (!((obj->state == ZAP_CHANNEL_STATE_HANGUP && s == ZAP_CHANNEL_STATE_TERMINATING) || (obj->state == ZAP_CHANNEL_STATE_HANGUP_COMPLETE && s == ZAP_CHANNEL_STATE_HANGUP) || (obj->state == ZAP_CHANNEL_STATE_TERMINATING && s == ZAP_CHANNEL_STATE_HANGUP))) zap_log(ZAP_LOG_WARNING, "VETO Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, zap_channel_state2str(st), zap_channel_state2str(s)); \
+ }
+
+#ifdef _MSC_VER
+/* The while(0) below throws a conditional expression is constant warning */
+#pragma warning(disable:4127)
+#endif
+
+#define zap_set_state_locked_wait(obj, s) \
+ do { \
+ int __safety = 100; \
+ zap_set_state_locked(obj, s); \
+ while(__safety-- && zap_test_flag(obj, ZAP_CHANNEL_STATE_CHANGE)) { \
+ zap_sleep(10); \
+ } \
+ if(!__safety) { \
+ zap_log(ZAP_LOG_CRIT, "State change not completed\n"); \
+ } \
+ } while(0);
+
+#define zap_wait_for_flag_cleared(obj, flag, time) \
+ do { \
+ int __safety = time; \
+ while(__safety-- && zap_test_flag(obj, flag)) { \
+ zap_mutex_unlock(obj->mutex); \
+ zap_sleep(10); \
+ zap_mutex_lock(obj->mutex); \
+ } \
+ if(!__safety) { \
+ zap_log(ZAP_LOG_CRIT, "flag %d was never cleared\n", flag); \
+ } \
+ } while(0);
+
+#define zap_set_state_wait(obj, s) \
+ do { \
+ zap_channel_set_state(obj, s, 0); \
+ zap_wait_for_flag_cleared(obj, ZAP_CHANNEL_STATE_CHANGE, 100); \
+ } while(0);
+
+
+typedef enum {
+ ZAP_STATE_CHANGE_FAIL,
+ ZAP_STATE_CHANGE_SUCCESS,
+ ZAP_STATE_CHANGE_SAME,
+} zap_state_change_result_t;
+
+#define zap_set_state_r(obj, s, l, r) if ( obj->state == s ) { \
+ if (s != ZAP_CHANNEL_STATE_HANGUP) zap_log(ZAP_LOG_WARNING, "Why bother changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, zap_channel_state2str(obj->state), zap_channel_state2str(s)); r = ZAP_STATE_CHANGE_SAME; \
+ } else if (zap_test_flag(obj, ZAP_CHANNEL_READY)) { \
+ int st = obj->state; \
+ r = (zap_channel_set_state(obj, s, l) == ZAP_SUCCESS) ? ZAP_STATE_CHANGE_SUCCESS : ZAP_STATE_CHANGE_FAIL; \
+ if (obj->state == s) {zap_log(ZAP_LOG_DEBUG, "Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, zap_channel_state2str(st), zap_channel_state2str(s));} \
+ else { if (!((obj->state == ZAP_CHANNEL_STATE_HANGUP && s == ZAP_CHANNEL_STATE_TERMINATING) || (obj->state == ZAP_CHANNEL_STATE_HANGUP_COMPLETE && s == ZAP_CHANNEL_STATE_HANGUP) || (obj->state == ZAP_CHANNEL_STATE_TERMINATING && s == ZAP_CHANNEL_STATE_HANGUP))) zap_log(ZAP_LOG_WARNING, "VETO Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, zap_channel_state2str(st), zap_channel_state2str(s)); } \
+ }
+
+
+#define zap_is_dtmf(key) ((key > 47 && key < 58) || (key > 64 && key < 69) || (key > 96 && key < 101) || key == 35 || key == 42 || key == 87 || key == 119)
+
+/*!
+ \brief Copy flags from one arbitrary object to another
+ \command dest the object to copy the flags to
+ \command src the object to copy the flags from
+ \command flags the flags to copy
+*/
+#define zap_copy_flags(dest, src, flags) (dest)->flags &= ~(flags); (dest)->flags |= ((src)->flags & (flags))
+
+/*!
+ \brief Free a pointer and set it to NULL unless it already is NULL
+ \command it the pointer
+*/
+#define zap_safe_free(it) if (it) {free(it);it=NULL;}
+
+#define zap_socket_close(it) if (it > -1) { close(it); it = -1;}
+
+
+struct zap_stream_handle {
+ zap_stream_handle_write_function_t write_function;
+ zap_stream_handle_raw_write_function_t raw_write_function;
+ void *data;
+ void *end;
+ zap_size_t data_size;
+ zap_size_t data_len;
+ zap_size_t alloc_len;
+ zap_size_t alloc_chunk;
+};
+
+
+OZ_DECLARE_NONSTD(zap_status_t) zap_console_stream_raw_write(zap_stream_handle_t *handle, uint8_t *data, zap_size_t datalen);
+OZ_DECLARE_NONSTD(zap_status_t) zap_console_stream_write(zap_stream_handle_t *handle, const char *fmt, ...);
+
+#define ZAP_CMD_CHUNK_LEN 1024
+#define ZAP_STANDARD_STREAM(s) memset(&s, 0, sizeof(s)); s.data = malloc(ZAP_CMD_CHUNK_LEN); \
+ assert(s.data); \
+ memset(s.data, 0, ZAP_CMD_CHUNK_LEN); \
+ s.end = s.data; \
+ s.data_size = ZAP_CMD_CHUNK_LEN; \
+ s.write_function = zap_console_stream_write; \
+ s.raw_write_function = zap_console_stream_raw_write; \
+ s.alloc_len = ZAP_CMD_CHUNK_LEN; \
+ s.alloc_chunk = ZAP_CMD_CHUNK_LEN
+
+struct zap_event {
+ zap_event_type_t e_type;
+ uint32_t enum_id;
+ zap_channel_t *channel;
+ void *data;
+};
+
+#define ZAP_TOKEN_STRLEN 128
+#define ZAP_MAX_TOKENS 10
+
+static __inline__ char *zap_clean_string(char *s)
+{
+ char *p;
+
+ for (p = s; p && *p; p++) {
+ uint8_t x = (uint8_t) *p;
+ if (x < 32 || x > 127) {
+ *p = ' ';
+ }
+ }
+
+ return s;
+}
+
+struct zap_bitstream {
+ uint8_t *data;
+ uint32_t datalen;
+ uint32_t byte_index;
+ uint8_t bit_index;
+ int8_t endian;
+ uint8_t top;
+ uint8_t bot;
+ uint8_t ss;
+ uint8_t ssv;
+};
+
+struct zap_fsk_data_state {
+ dsp_fsk_handle_t *fsk1200_handle;
+ uint8_t init;
+ uint8_t *buf;
+ size_t bufsize;
+ zap_size_t blen;
+ zap_size_t bpos;
+ zap_size_t dlen;
+ zap_size_t ppos;
+ int checksum;
+};
+
+struct zap_fsk_modulator {
+ teletone_dds_state_t dds;
+ zap_bitstream_t bs;
+ uint32_t carrier_bits_start;
+ uint32_t carrier_bits_stop;
+ uint32_t chan_sieze_bits;
+ uint32_t bit_factor;
+ uint32_t bit_accum;
+ uint32_t sample_counter;
+ int32_t samples_per_bit;
+ int32_t est_bytes;
+ fsk_modem_types_t modem_type;
+ zap_fsk_data_state_t *fsk_data;
+ zap_fsk_write_sample_t write_sample_callback;
+ void *user_data;
+ int16_t sample_buffer[64];
+};
+
+/**
+ * Type Of Number (TON)
+ */
+typedef enum {
+ ZAP_TON_UNKNOWN = 0,
+ ZAP_TON_INTERNATIONAL,
+ ZAP_TON_NATIONAL,
+ ZAP_TON_NETWORK_SPECIFIC,
+ ZAP_TON_SUBSCRIBER_NUMBER,
+ ZAP_TON_ABBREVIATED_NUMBER,
+ ZAP_TON_RESERVED,
+ ZAP_TON_INVALID = 255
+} zap_ton_t;
+
+/**
+ * Numbering Plan Identification (NPI)
+ */
+typedef enum {
+ ZAP_NPI_UNKNOWN = 0,
+ ZAP_NPI_ISDN = 1,
+ ZAP_NPI_DATA = 3,
+ ZAP_NPI_TELEX = 4,
+ ZAP_NPI_NATIONAL = 8,
+ ZAP_NPI_PRIVATE = 9,
+ ZAP_NPI_RESERVED = 10,
+ ZAP_NPI_INVALID = 255
+} zap_npi_t;
+
+typedef struct {
+ char digits[25];
+ uint8_t type;
+ uint8_t plan;
+} zap_number_t;
+
+typedef enum {
+ ZAP_CALLER_STATE_DIALING,
+ ZAP_CALLER_STATE_SUCCESS,
+ ZAP_CALLER_STATE_FAIL
+} zap_caller_state_t;
+
+struct zap_caller_data {
+ char cid_date[8];
+ char cid_name[80];
+ zap_number_t cid_num;
+ zap_number_t ani;
+ zap_number_t dnis;
+ zap_number_t rdnis;
+ char aniII[25];
+ uint8_t screen;
+ uint8_t pres;
+ char collected[25];
+ int CRV;
+ int hangup_cause;
+ uint8_t raw_data[1024];
+ uint32_t raw_data_len;
+ uint32_t flags;
+ zap_caller_state_t call_state;
+ uint32_t chan_id;
+};
+
+typedef enum {
+ ZAP_TYPE_NONE,
+ ZAP_TYPE_SPAN = 0xFF,
+ ZAP_TYPE_CHANNEL
+} zap_data_type_t;
+
+/* 2^8 table size, one for each byte value */
+#define ZAP_GAINS_TABLE_SIZE 256
+struct zap_channel {
+ zap_data_type_t data_type;
+ uint32_t span_id;
+ uint32_t chan_id;
+ uint32_t physical_span_id;
+ uint32_t physical_chan_id;
+ uint32_t rate;
+ uint32_t extra_id;
+ zap_chan_type_t type;
+ zap_socket_t sockfd;
+ zap_channel_flag_t flags;
+ uint32_t pflags;
+ uint32_t sflags;
+ zap_alarm_flag_t alarm_flags;
+ zap_channel_feature_t features;
+ zap_codec_t effective_codec;
+ zap_codec_t native_codec;
+ uint32_t effective_interval;
+ uint32_t native_interval;
+ uint32_t packet_len;
+ zap_channel_state_t state;
+ zap_channel_state_t last_state;
+ zap_channel_state_t init_state;
+ zap_mutex_t *mutex;
+ teletone_dtmf_detect_state_t dtmf_detect;
+ uint32_t buffer_delay;
+ zap_event_t event_header;
+ char last_error[256];
+ zio_event_cb_t event_callback;
+ uint32_t skip_read_frames;
+ zap_buffer_t *dtmf_buffer;
+ zap_buffer_t *gen_dtmf_buffer;
+ zap_buffer_t *pre_buffer;
+ zap_buffer_t *digit_buffer;
+ zap_buffer_t *fsk_buffer;
+ zap_mutex_t *pre_buffer_mutex;
+ uint32_t dtmf_on;
+ uint32_t dtmf_off;
+ char *dtmf_hangup_buf;
+ teletone_generation_session_t tone_session;
+ zap_time_t last_event_time;
+ zap_time_t ring_time;
+ char tokens[ZAP_MAX_TOKENS+1][ZAP_TOKEN_STRLEN];
+ uint8_t needed_tones[ZAP_TONEMAP_INVALID];
+ uint8_t detected_tones[ZAP_TONEMAP_INVALID];
+ zap_tonemap_t last_detected_tone;
+ uint32_t token_count;
+ char chan_name[128];
+ char chan_number[32];
+ zap_filehandle_t fds[2];
+ zap_fsk_data_state_t fsk;
+ uint8_t fsk_buf[80];
+ uint32_t ring_count;
+ void *mod_data;
+ void *call_data;
+ struct zap_caller_data caller_data;
+ struct zap_span *span;
+ struct zap_io_interface *zio;
+ zap_hash_t *variable_hash;
+ unsigned char rx_cas_bits;
+ uint32_t pre_buffer_size;
+ unsigned char rxgain_table[ZAP_GAINS_TABLE_SIZE];
+ unsigned char txgain_table[ZAP_GAINS_TABLE_SIZE];
+ float rxgain;
+ float txgain;
+};
+
+
+struct zap_sigmsg {
+ zap_signal_event_t event_id;
+ uint32_t chan_id;
+ uint32_t span_id;
+ zap_channel_t *channel;
+ void *raw_data;
+ uint32_t raw_data_len;
+};
+
+
+struct zap_span {
+ zap_data_type_t data_type;
+ char *name;
+ uint32_t span_id;
+ uint32_t chan_count;
+ zap_span_flag_t flags;
+ struct zap_io_interface *zio;
+ zio_event_cb_t event_callback;
+ zap_mutex_t *mutex;
+ zap_trunk_type_t trunk_type;
+ zap_analog_start_type_t start_type;
+ zap_signal_type_t signal_type;
+ void *signal_data;
+ zio_signal_cb_t signal_cb;
+ zap_event_t event_header;
+ char last_error[256];
+ char tone_map[ZAP_TONEMAP_INVALID+1][ZAP_TONEMAP_LEN];
+ teletone_tone_map_t tone_detect_map[ZAP_TONEMAP_INVALID+1];
+ teletone_multi_tone_t tone_finder[ZAP_TONEMAP_INVALID+1];
+ zap_channel_t *channels[ZAP_MAX_CHANNELS_SPAN+1];
+ zio_channel_outgoing_call_t outgoing_call;
+ zio_channel_request_t channel_request;
+ zap_span_start_t start;
+ zap_span_stop_t stop;
+ void *mod_data;
+ char *type;
+ char *dtmf_hangup;
+ size_t dtmf_hangup_len;
+ int suggest_chan_id;
+ zap_state_map_t *state_map;
+ zap_caller_data_t default_caller_data;
+ struct zap_span *next;
+};
+
+
+OZ_DECLARE_DATA extern zap_logger_t zap_log;
+
+struct zap_io_interface {
+ const char *name;
+ zio_configure_span_t configure_span;
+ zio_configure_t configure;
+ zio_open_t open;
+ zio_close_t close;
+ zio_channel_destroy_t channel_destroy;
+ zio_span_destroy_t span_destroy;
+ zio_get_alarms_t get_alarms;
+ zio_command_t command;
+ zio_wait_t wait;
+ zio_read_t read;
+ zio_write_t write;
+ zio_span_poll_event_t poll_event;
+ zio_span_next_event_t next_event;
+ zio_api_t api;
+};
+
+
+OZ_DECLARE(zap_size_t) zap_fsk_modulator_generate_bit(zap_fsk_modulator_t *fsk_trans, int8_t bit, int16_t *buf, zap_size_t buflen);
+OZ_DECLARE(int32_t) zap_fsk_modulator_generate_carrier_bits(zap_fsk_modulator_t *fsk_trans, uint32_t bits);
+OZ_DECLARE(void) zap_fsk_modulator_generate_chan_sieze(zap_fsk_modulator_t *fsk_trans);
+OZ_DECLARE(void) zap_fsk_modulator_send_data(zap_fsk_modulator_t *fsk_trans);
+#define zap_fsk_modulator_send_all(_it) zap_fsk_modulator_generate_chan_sieze(_it); \
+ zap_fsk_modulator_generate_carrier_bits(_it, _it->carrier_bits_start); \
+ zap_fsk_modulator_send_data(_it); \
+ zap_fsk_modulator_generate_carrier_bits(_it, _it->carrier_bits_stop)
+
+OZ_DECLARE(zap_status_t) zap_fsk_modulator_init(zap_fsk_modulator_t *fsk_trans,
+ fsk_modem_types_t modem_type,
+ uint32_t sample_rate,
+ zap_fsk_data_state_t *fsk_data,
+ float db_level,
+ uint32_t carrier_bits_start,
+ uint32_t carrier_bits_stop,
+ uint32_t chan_sieze_bits,
+ zap_fsk_write_sample_t write_sample_callback,
+ void *user_data);
+OZ_DECLARE(int8_t) zap_bitstream_get_bit(zap_bitstream_t *bsp);
+OZ_DECLARE(void) zap_bitstream_init(zap_bitstream_t *bsp, uint8_t *data, uint32_t datalen, zap_endian_t endian, uint8_t ss);
+OZ_DECLARE(zap_status_t) zap_fsk_data_parse(zap_fsk_data_state_t *state, zap_size_t *type, char **data, zap_size_t *len);
+OZ_DECLARE(zap_status_t) zap_fsk_demod_feed(zap_fsk_data_state_t *state, int16_t *data, size_t samples);
+OZ_DECLARE(zap_status_t) zap_fsk_demod_destroy(zap_fsk_data_state_t *state);
+OZ_DECLARE(int) zap_fsk_demod_init(zap_fsk_data_state_t *state, int rate, uint8_t *buf, size_t bufsize);
+OZ_DECLARE(zap_status_t) zap_fsk_data_init(zap_fsk_data_state_t *state, uint8_t *data, uint32_t datalen);
+OZ_DECLARE(zap_status_t) zap_fsk_data_add_mdmf(zap_fsk_data_state_t *state, zap_mdmf_type_t type, const uint8_t *data, uint32_t datalen);
+OZ_DECLARE(zap_status_t) zap_fsk_data_add_checksum(zap_fsk_data_state_t *state);
+OZ_DECLARE(zap_status_t) zap_fsk_data_add_sdmf(zap_fsk_data_state_t *state, const char *date, char *number);
+OZ_DECLARE(zap_status_t) zap_channel_outgoing_call(zap_channel_t *zchan);
+OZ_DECLARE(void) zap_channel_rotate_tokens(zap_channel_t *zchan);
+OZ_DECLARE(void) zap_channel_clear_detected_tones(zap_channel_t *zchan);
+OZ_DECLARE(void) zap_channel_clear_needed_tones(zap_channel_t *zchan);
+OZ_DECLARE(zap_status_t) zap_channel_get_alarms(zap_channel_t *zchan);
+OZ_DECLARE(zap_status_t) zap_channel_send_fsk_data(zap_channel_t *zchan, zap_fsk_data_state_t *fsk_data, float db_level);
+OZ_DECLARE(zap_status_t) zap_channel_clear_token(zap_channel_t *zchan, const char *token);
+OZ_DECLARE(void) zap_channel_replace_token(zap_channel_t *zchan, const char *old_token, const char *new_token);
+OZ_DECLARE(zap_status_t) zap_channel_add_token(zap_channel_t *zchan, char *token, int end);
+OZ_DECLARE(zap_status_t) zap_channel_set_state(zap_channel_t *zchan, zap_channel_state_t state, int lock);
+OZ_DECLARE(zap_status_t) zap_span_load_tones(zap_span_t *span, const char *mapname);
+OZ_DECLARE(zap_size_t) zap_channel_dequeue_dtmf(zap_channel_t *zchan, char *dtmf, zap_size_t len);
+OZ_DECLARE(zap_status_t) zap_channel_queue_dtmf(zap_channel_t *zchan, const char *dtmf);
+OZ_DECLARE(void) zap_channel_flush_dtmf(zap_channel_t *zchan);
+OZ_DECLARE(zap_time_t) zap_current_time_in_ms(void);
+OZ_DECLARE(zap_status_t) zap_span_poll_event(zap_span_t *span, uint32_t ms);
+OZ_DECLARE(zap_status_t) zap_span_next_event(zap_span_t *span, zap_event_t **event);
+OZ_DECLARE(zap_status_t) zap_span_find(uint32_t id, zap_span_t **span);
+OZ_DECLARE(zap_status_t) zap_span_create(zap_io_interface_t *zio, zap_span_t **span, const char *name);
+OZ_DECLARE(zap_status_t) zap_span_close_all(void);
+OZ_DECLARE(zap_status_t) zap_span_add_channel(zap_span_t *span, zap_socket_t sockfd, zap_chan_type_t type, zap_channel_t **chan);
+OZ_DECLARE(zap_status_t) zap_span_set_event_callback(zap_span_t *span, zio_event_cb_t event_callback);
+OZ_DECLARE(zap_status_t) zap_channel_set_event_callback(zap_channel_t *zchan, zio_event_cb_t event_callback);
+OZ_DECLARE(zap_status_t) zap_channel_open(uint32_t span_id, uint32_t chan_id, zap_channel_t **zchan);
+OZ_DECLARE(zap_status_t) zap_channel_open_chan(zap_channel_t *zchan);
+OZ_DECLARE(zap_status_t) zap_span_channel_use_count(zap_span_t *span, uint32_t *count);
+OZ_DECLARE(zap_status_t) zap_channel_open_any(uint32_t span_id, zap_direction_t direction, zap_caller_data_t *caller_data, zap_channel_t **zchan);
+OZ_DECLARE(zap_status_t) zap_channel_close(zap_channel_t **zchan);
+OZ_DECLARE(zap_status_t) zap_channel_done(zap_channel_t *zchan);
+OZ_DECLARE(zap_status_t) zap_channel_use(zap_channel_t *zchan);
+OZ_DECLARE(zap_status_t) zap_channel_command(zap_channel_t *zchan, zap_command_t command, void *obj);
+OZ_DECLARE(zap_status_t) zap_channel_wait(zap_channel_t *zchan, zap_wait_flag_t *flags, int32_t to);
+OZ_DECLARE(zap_status_t) zap_channel_read(zap_channel_t *zchan, void *data, zap_size_t *datalen);
+OZ_DECLARE(void) zap_generate_sln_silence(int16_t *data, uint32_t samples, uint32_t divisor);
+OZ_DECLARE(zap_status_t) zap_channel_write(zap_channel_t *zchan, void *data, zap_size_t datasize, zap_size_t *datalen);
+OZ_DECLARE(zap_status_t) zap_channel_add_var(zap_channel_t *zchan, const char *var_name, const char *value);
+OZ_DECLARE(const char *) zap_channel_get_var(zap_channel_t *zchan, const char *var_name);
+OZ_DECLARE(zap_status_t) zap_channel_clear_vars(zap_channel_t *zchan);
+OZ_DECLARE(zap_status_t) zap_global_init(void);
+OZ_DECLARE(zap_status_t) zap_global_destroy(void);
+OZ_DECLARE(void) zap_global_set_logger(zap_logger_t logger);
+OZ_DECLARE(void) zap_global_set_default_logger(int level);
+OZ_DECLARE(uint32_t) zap_separate_string(char *buf, char delim, char **array, int arraylen);
+OZ_DECLARE(void) print_bits(uint8_t *b, int bl, char *buf, int blen, int e, uint8_t ss);
+OZ_DECLARE(void) print_hex_bytes(uint8_t *data, zap_size_t dlen, char *buf, zap_size_t blen);
+OZ_DECLARE_NONSTD(int) zap_hash_equalkeys(void *k1, void *k2);
+OZ_DECLARE_NONSTD(uint32_t) zap_hash_hashfromstring(void *ky);
+OZ_DECLARE(uint32_t) zap_running(void);
+OZ_DECLARE(zap_status_t) zap_channel_complete_state(zap_channel_t *zchan);
+OZ_DECLARE(zap_status_t) zap_channel_init(zap_channel_t *zchan);
+OZ_DECLARE(int) zap_load_modules(void);
+OZ_DECLARE(zap_status_t) zap_unload_modules(void);
+OZ_DECLARE(zap_status_t) zap_configure_span(const char *type, zap_span_t *span, zio_signal_cb_t sig_cb, ...);
+OZ_DECLARE(zap_status_t) zap_span_start(zap_span_t *span);
+OZ_DECLARE(zap_status_t) zap_span_stop(zap_span_t *span);
+OZ_DECLARE(zap_status_t) zap_span_send_signal(zap_span_t *span, zap_sigmsg_t *sigmsg);
+OZ_DECLARE(int) zap_load_module(const char *name);
+OZ_DECLARE(int) zap_load_module_assume(const char *name);
+OZ_DECLARE(zap_status_t) zap_span_find_by_name(const char *name, zap_span_t **span);
+OZ_DECLARE(char *) zap_api_execute(const char *type, const char *cmd);
+OZ_DECLARE(int) zap_vasprintf(char **ret, const char *fmt, va_list ap);
+OZ_DECLARE(zap_status_t) zap_channel_set_caller_data(zap_channel_t *zchan, zap_caller_data_t *caller_data);
+OZ_DECLARE(void) zap_cpu_monitor_disable(void);
+
+ZIO_CODEC_FUNCTION(zio_slin2ulaw);
+ZIO_CODEC_FUNCTION(zio_ulaw2slin);
+ZIO_CODEC_FUNCTION(zio_slin2alaw);
+ZIO_CODEC_FUNCTION(zio_alaw2slin);
+ZIO_CODEC_FUNCTION(zio_ulaw2alaw);
+ZIO_CODEC_FUNCTION(zio_alaw2ulaw);
+
+#ifdef DEBUG_LOCKS
+#define zap_mutex_lock(_x) printf("++++++lock %s:%d\n", __FILE__, __LINE__) && _zap_mutex_lock(_x)
+#define zap_mutex_trylock(_x) printf("++++++try %s:%d\n", __FILE__, __LINE__) && _zap_mutex_trylock(_x)
+#define zap_mutex_unlock(_x) printf("------unlock %s:%d\n", __FILE__, __LINE__) && _zap_mutex_unlock(_x)
+#else
+#define zap_mutex_lock(_x) _zap_mutex_lock(_x)
+#define zap_mutex_trylock(_x) _zap_mutex_trylock(_x)
+#define zap_mutex_unlock(_x) _zap_mutex_unlock(_x)
+#endif
+
+
+static __inline__ void zap_set_state_all(zap_span_t *span, zap_channel_state_t state)
+{
+ uint32_t j;
+ zap_mutex_lock(span->mutex);
+ for(j = 1; j <= span->chan_count; j++) {
+ zap_set_state_locked((span->channels[j]), state);
+ }
+ zap_mutex_unlock(span->mutex);
+}
+
+static __inline__ int zap_check_state_all(zap_span_t *span, zap_channel_state_t state)
+{
+ uint32_t j;
+ for(j = 1; j <= span->chan_count; j++) {
+ if (span->channels[j]->state != state || zap_test_flag(span->channels[j], ZAP_CHANNEL_STATE_CHANGE)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static __inline__ void zap_set_flag_all(zap_span_t *span, uint32_t flag)
+{
+ uint32_t j;
+ zap_mutex_lock(span->mutex);
+ for(j = 1; j <= span->chan_count; j++) {
+ zap_set_flag_locked((span->channels[j]), flag);
+ }
+ zap_mutex_unlock(span->mutex);
+}
+
+static __inline__ void zap_clear_flag_all(zap_span_t *span, uint32_t flag)
+{
+ uint32_t j;
+ zap_mutex_lock(span->mutex);
+ for(j = 1; j <= span->chan_count; j++) {
+ zap_clear_flag_locked((span->channels[j]), flag);
+ }
+ zap_mutex_unlock(span->mutex);
+}
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/include/sangoma_tdm_api.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/include/sangoma_tdm_api.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/sangoma_tdm_api.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,321 @@
+/*****************************************************************************
+ * sangoma_tdm_api.h Sangoma TDM API Portability functions
+ *
+ * Author(s): Anthony Minessale II <anthmct@yahoo.com>
+ * Nenad Corbic <ncorbic@sangoma.com>
+ * Michael Jerris <mike@jerris.com>
+ * David Rokhvarg <davidr@sangoma.com>
+ *
+ * Copyright: (c) 2006 Nenad Corbic <ncorbic@sangoma.com>
+ * Anthony Minessale II
+ * (c) 1984-2007 Sangoma Technologies Inc.
+ *
+ * ============================================================================
+ */
+
+#ifndef _SANGOMA_TDM_API_H
+#define _SANGOMA_TDM_API_H
+
+/* This entire block of defines and includes from this line, through #define FNAME_LEN probably dont belong here */
+/* most of them probably belong in wanpipe_defines.h, then each header file listed included below properly included */
+/* in the header files that depend on them, leaving only the include for wanpipe_tdm_api.h left in this file or */
+/* possibly integrating the rest of this file diretly into wanpipe_tdm_api.h */
+#ifndef __WINDOWS__
+#if defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)
+#define __WINDOWS__
+#endif /* defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32) */
+#endif /* ndef __WINDOWS__ */
+
+#if defined(__WINDOWS__)
+#if defined(_MSC_VER)
+/* disable some warnings caused by wanpipe headers that will need to be fixed in those headers */
+#pragma warning(disable:4201 4214)
+
+/* sang_api.h(74) : warning C4201: nonstandard extension used : nameless struct/union */
+
+/* wanpipe_defines.h(219) : warning C4214: nonstandard extension used : bit field types other than int */
+/* wanpipe_defines.h(220) : warning C4214: nonstandard extension used : bit field types other than int */
+/* this will break for any compilers that are strict ansi or strict c99 */
+
+/* The following definition for that struct should resolve this warning and work for 32 and 64 bit */
+#if 0
+struct iphdr {
+
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned ihl:4,
+ version:4;
+#elif defined (__BIG_ENDIAN_BITFIELD)
+ unsigned version:4,
+ ihl:4;
+#else
+# error "unknown byteorder!"
+#endif
+ unsigned tos:8;
+ unsigned tot_len:16;
+ unsigned id:16;
+ unsigned frag_off:16;
+ __u8 ttl;
+ __u8 protocol;
+ __u16 check;
+ __u32 saddr;
+ __u32 daddr;
+ /*The options start here. */
+};
+#endif /* #if 0 */
+
+#define __inline__ __inline
+#endif /* defined(_MSC_VER) */
+#include <windows.h>
+/* do we like the name WP_INVALID_SOCKET or should it be changed? */
+#define WP_INVALID_SOCKET INVALID_HANDLE_VALUE
+#else /* defined(__WINDOWS__) */
+#define WP_INVALID_SOCKET -1
+#include <stropts.h>
+#include <poll.h>
+#include <sys/socket.h>
+#endif
+
+#include <wanpipe_defines.h>
+#include <wanpipe_cfg.h>
+#include <wanpipe_tdm_api.h>
+#include <sdla_te1_pmc.h>
+#ifdef __WINDOWS__
+#include <sang_status_defines.h>
+#include <sang_api.h>
+#endif
+#include <sdla_aft_te1.h>
+
+#define FNAME_LEN 50
+
+
+#if defined(__WINDOWS__)
+/* This might be broken on windows, as POLL_EVENT_TELEPHONY seems to be commented out in sang_api.h.. it should be added to POLLPRI */
+#define POLLPRI (POLL_EVENT_LINK_STATE | POLL_EVENT_LINK_CONNECT | POLL_EVENT_LINK_DISCONNECT)
+#endif
+
+/* return -1 for error, 0 for timeout or 1 for success. *flags is set to the poll evetns POLLIN | POLLOUT | POLLPRI based on the result of the poll */
+/* on windows we actually have POLLPRI defined with several events, so we could theoretically poll */
+/* for specific events. Is there any way to do this on *nix as well? */
+
+/* a cross platform way to poll on an actual pollset (span and/or list of spans) will probably also be needed for analog */
+/* so we can have one analong handler thread that will deal with all the idle analog channels for events */
+/* the alternative would be for the driver to provide one socket for all of the oob events for all analog channels */
+static __inline__ int tdmv_api_wait_socket(sng_fd_t fd, int timeout, int *flags)
+{
+#if defined(__WINDOWS__)
+ DWORD ln;
+ API_POLL_STRUCT api_poll;
+
+ memset(&api_poll, 0x00, sizeof(API_POLL_STRUCT));
+
+ api_poll.user_flags_bitmap = *flags;
+ api_poll.timeout = timeout;
+
+ if (!DeviceIoControl(
+ fd,
+ IoctlApiPoll,
+ (LPVOID)NULL,
+ 0L,
+ (LPVOID)&api_poll,
+ sizeof(API_POLL_STRUCT),
+ (LPDWORD)(&ln),
+ (LPOVERLAPPED)NULL)) {
+ return -1;
+ }
+
+ *flags = 0;
+
+ switch(api_poll.operation_status)
+ {
+ case SANG_STATUS_RX_DATA_AVAILABLE:
+ break;
+
+ case SANG_STATUS_RX_DATA_TIMEOUT:
+ return 0;
+
+ default:
+ return -1;
+ }
+
+ if (api_poll.poll_events_bitmap == 0){
+ return -1;
+ }
+
+ if (api_poll.poll_events_bitmap & POLL_EVENT_TIMEOUT) {
+ return 0;
+ }
+
+ *flags = api_poll.poll_events_bitmap;
+
+ return 1;
+#else
+ struct pollfd pfds[1];
+ int res;
+
+ memset(&pfds[0], 0, sizeof(pfds[0]));
+ pfds[0].fd = fd;
+ pfds[0].events = *flags;
+ res = poll(pfds, 1, timeout);
+ *flags = 0;
+
+ if (pfds[0].revents & POLLERR) {
+ res = -1;
+ }
+
+ if (res > 0) {
+ *flags = pfds[0].revents;
+ }
+
+ return res;
+#endif
+}
+
+/* on windows right now, there is no way to specify if we want to read events here or not, we allways get them here */
+/* we need some what to select if we are reading regular tdm msgs or events */
+/* need to either have 2 functions, 1 for events, 1 for regural read, or a flag on this function to choose */
+/* 2 functions preferred. Need implementation for the event function for both nix and windows that is threadsafe */
+static __inline__ int tdmv_api_readmsg_tdm(sng_fd_t fd, void *hdrbuf, int hdrlen, void *databuf, int datalen)
+{
+ /* What do we need to do here to avoid having to do all */
+ /* the memcpy's on windows and still maintain api compat with nix */
+ int rx_len=0;
+#if defined(__WINDOWS__)
+ static RX_DATA_STRUCT rx_data;
+ api_header_t *pri;
+ wp_tdm_api_rx_hdr_t *tdm_api_rx_hdr;
+ wp_tdm_api_rx_hdr_t *user_buf = (wp_tdm_api_rx_hdr_t*)hdrbuf;
+ DWORD ln;
+
+ if (hdrlen != sizeof(wp_tdm_api_rx_hdr_t)){
+ return -1;
+ }
+
+ if (!DeviceIoControl(
+ fd,
+ IoctlReadCommand,
+ (LPVOID)NULL,
+ 0L,
+ (LPVOID)&rx_data,
+ sizeof(RX_DATA_STRUCT),
+ (LPDWORD)(&ln),
+ (LPOVERLAPPED)NULL
+ )){
+ return -1;
+ }
+
+ pri = &rx_data.api_header;
+ tdm_api_rx_hdr = (wp_tdm_api_rx_hdr_t*)rx_data.data;
+
+ user_buf->wp_tdm_api_event_type = pri->operation_status;
+
+ switch(pri->operation_status)
+ {
+ case SANG_STATUS_RX_DATA_AVAILABLE:
+ if (pri->data_length > datalen){
+ break;
+ }
+ memcpy(databuf, rx_data.data, pri->data_length);
+ rx_len = pri->data_length;
+ break;
+
+ default:
+ break;
+ }
+
+#else
+ struct msghdr msg;
+ struct iovec iov[2];
+
+ memset(&msg,0,sizeof(struct msghdr));
+
+ iov[0].iov_len=hdrlen;
+ iov[0].iov_base=hdrbuf;
+
+ iov[1].iov_len=datalen;
+ iov[1].iov_base=databuf;
+
+ msg.msg_iovlen=2;
+ msg.msg_iov=iov;
+
+ rx_len = read(fd,&msg,datalen+hdrlen);
+
+ if (rx_len <= sizeof(wp_tdm_api_rx_hdr_t)){
+ return -EINVAL;
+ }
+
+ rx_len-=sizeof(wp_tdm_api_rx_hdr_t);
+#endif
+ return rx_len;
+}
+
+static __inline__ int tdmv_api_writemsg_tdm(sng_fd_t fd, void *hdrbuf, int hdrlen, void *databuf, unsigned short datalen)
+{
+ /* What do we need to do here to avoid having to do all */
+ /* the memcpy's on windows and still maintain api compat with nix */
+ int bsent = 0;
+#if defined(__WINDOWS__)
+ static TX_DATA_STRUCT local_tx_data;
+ api_header_t *pri;
+ DWORD ln;
+
+ /* Are these really not needed or used??? What about for nix?? */
+ (void)hdrbuf;
+ (void)hdrlen;
+
+ pri = &local_tx_data.api_header;
+
+ pri->data_length = datalen;
+ memcpy(local_tx_data.data, databuf, pri->data_length);
+
+ if (!DeviceIoControl(
+ fd,
+ IoctlWriteCommand,
+ (LPVOID)&local_tx_data,
+ (ULONG)sizeof(TX_DATA_STRUCT),
+ (LPVOID)&local_tx_data,
+ sizeof(TX_DATA_STRUCT),
+ (LPDWORD)(&ln),
+ (LPOVERLAPPED)NULL
+ )){
+ return -1;
+ }
+
+ if (local_tx_data.api_header.operation_status == SANG_STATUS_SUCCESS) {
+ bsent = datalen;
+ }
+#else
+ struct msghdr msg;
+ struct iovec iov[2];
+
+ memset(&msg,0,sizeof(struct msghdr));
+
+ iov[0].iov_len = hdrlen;
+ iov[0].iov_base = hdrbuf;
+
+ iov[1].iov_len = datalen;
+ iov[1].iov_base = databuf;
+
+ msg.msg_iovlen = 2;
+ msg.msg_iov = iov;
+
+ bsent = write(fd, &msg, datalen + hdrlen);
+ if (bsent > 0){
+ bsent -= sizeof(wp_tdm_api_tx_hdr_t);
+ }
+#endif
+ return bsent;
+}
+
+#endif /* _SANGOMA_TDM_API_H */
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/openzap/src/include/uart.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/include/uart.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/uart.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,76 @@
+/*
+ * uart.h
+ *
+ * Copyright (c) 2005 Robert Krten. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * This module contains the manifest constants and declarations for
+ * the UART module.
+ *
+ * 2005 06 19 R. Krten created
+*/
+
+#ifndef __UART_H__
+#define __UART_H__
+
+typedef void (*bytehandler_func_t) (void *, int);
+typedef void (*bithandler_func_t) (void *, int);
+
+
+typedef struct dsp_uart_attr_s
+{
+ bytehandler_func_t bytehandler; /* byte handler */
+ void *bytehandler_arg; /* arbitrary ID passed to bytehandler as first argument */
+} dsp_uart_attr_t;
+
+typedef struct
+{
+ dsp_uart_attr_t attr;
+ int have_start; /* wait for start bit to show up */
+ int data; /* data buffer */
+ int nbits; /* number of bits accumulated so far */
+} dsp_uart_handle_t;
+
+/*
+ * Function prototypes
+ *
+ * General calling order is:
+ * a) create the attributes structure (dsp_uart_attr_init)
+ * b) initialize fields in the attributes structure (dsp_uart_attr_set_*)
+ * c) create a Bell-202 handle (dsp_uart_create)
+ * d) feed bits through dsp_uart_bit_handler
+*/
+
+void dsp_uart_attr_init(dsp_uart_attr_t *attributes);
+
+bytehandler_func_t dsp_uart_attr_get_bytehandler(dsp_uart_attr_t *attributes, void **bytehandler_arg);
+void dsp_uart_attr_set_bytehandler(dsp_uart_attr_t *attributes, bytehandler_func_t bytehandler, void *bytehandler_arg);
+
+dsp_uart_handle_t * dsp_uart_create(dsp_uart_attr_t *attributes);
+void dsp_uart_destroy(dsp_uart_handle_t **handle);
+
+void dsp_uart_bit_handler(void *handle, int bit);
+
+#endif
+
Added: freeswitch/trunk/libs/openzap/src/include/zap_buffer.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/include/zap_buffer.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/zap_buffer.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#ifndef ZAP_BUFFER_H
+#define ZAP_BUFFER_H
+
+#include "openzap.h"
+
+/**
+ * @defgroup zap_buffer Buffer Routines
+ * @ingroup buffer
+ * The purpose of this module is to make a plain buffering interface that can be used for read/write buffers
+ * throughout the application.
+ * @{
+ */
+struct zap_buffer;
+typedef struct zap_buffer zap_buffer_t;
+
+/*! \brief Allocate a new dynamic zap_buffer
+ * \param buffer returned pointer to the new buffer
+ * \param blocksize length to realloc by as data is added
+ * \param start_len ammount of memory to reserve initially
+ * \param max_len length the buffer is allowed to grow to
+ * \return status
+ */
+OZ_DECLARE(zap_status_t) zap_buffer_create(zap_buffer_t **buffer, zap_size_t blocksize, zap_size_t start_len, zap_size_t max_len);
+
+/*! \brief Get the length of a zap_buffer_t
+ * \param buffer any buffer of type zap_buffer_t
+ * \return int size of the buffer.
+ */
+OZ_DECLARE(zap_size_t) zap_buffer_len(zap_buffer_t *buffer);
+
+/*! \brief Get the freespace of a zap_buffer_t
+ * \param buffer any buffer of type zap_buffer_t
+ * \return int freespace in the buffer.
+ */
+OZ_DECLARE(zap_size_t) zap_buffer_freespace(zap_buffer_t *buffer);
+
+/*! \brief Get the in use amount of a zap_buffer_t
+ * \param buffer any buffer of type zap_buffer_t
+ * \return int ammount of buffer curently in use
+ */
+OZ_DECLARE(zap_size_t) zap_buffer_inuse(zap_buffer_t *buffer);
+
+/*! \brief Read data from a zap_buffer_t up to the ammount of datalen if it is available. Remove read data from buffer.
+ * \param buffer any buffer of type zap_buffer_t
+ * \param data pointer to the read data to be returned
+ * \param datalen amount of data to be returned
+ * \return int ammount of data actually read
+ */
+OZ_DECLARE(zap_size_t) zap_buffer_read(zap_buffer_t *buffer, void *data, zap_size_t datalen);
+
+/*! \brief Read data endlessly from a zap_buffer_t
+ * \param buffer any buffer of type zap_buffer_t
+ * \param data pointer to the read data to be returned
+ * \param datalen amount of data to be returned
+ * \return int ammount of data actually read
+ * \note Once you have read all the data from the buffer it will loop around.
+ */
+OZ_DECLARE(zap_size_t) zap_buffer_read_loop(zap_buffer_t *buffer, void *data, zap_size_t datalen);
+
+/*! \brief Assign a number of loops to read
+ * \param buffer any buffer of type zap_buffer_t
+ * \param loops the number of loops (-1 for infinite)
+ */
+OZ_DECLARE(void) zap_buffer_set_loops(zap_buffer_t *buffer, int32_t loops);
+
+/*! \brief Write data into a zap_buffer_t up to the length of datalen
+ * \param buffer any buffer of type zap_buffer_t
+ * \param data pointer to the data to be written
+ * \param datalen amount of data to be written
+ * \return int amount of buffer used after the write, or 0 if no space available
+ */
+OZ_DECLARE(zap_size_t) zap_buffer_write(zap_buffer_t *buffer, const void *data, zap_size_t datalen);
+
+/*! \brief Remove data from the buffer
+ * \param buffer any buffer of type zap_buffer_t
+ * \param datalen amount of data to be removed
+ * \return int size of buffer, or 0 if unable to toss that much data
+ */
+OZ_DECLARE(zap_size_t) zap_buffer_toss(zap_buffer_t *buffer, zap_size_t datalen);
+
+/*! \brief Remove all data from the buffer
+ * \param buffer any buffer of type zap_buffer_t
+ */
+OZ_DECLARE(void) zap_buffer_zero(zap_buffer_t *buffer);
+
+/*! \brief Destroy the buffer
+ * \param buffer buffer to destroy
+ * \note only neccessary on dynamic buffers (noop on pooled ones)
+ */
+OZ_DECLARE(void) zap_buffer_destroy(zap_buffer_t **buffer);
+
+/*! \brief Seek to offset from the beginning of the buffer
+ * \param buffer buffer to seek
+ * \param datalen offset in bytes
+ * \return new position
+ */
+OZ_DECLARE(zap_size_t) zap_buffer_seek(zap_buffer_t *buffer, zap_size_t datalen);
+
+/** @} */
+
+OZ_DECLARE(zap_size_t) zap_buffer_zwrite(zap_buffer_t *buffer, const void *data, zap_size_t datalen);
+
+#endif
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/include/zap_config.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/include/zap_config.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/zap_config.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+/**
+ * @defgroup config Config File Parser
+ * @ingroup config
+ * This module implements a basic interface and file format parser
+ *
+ * <pre>
+ *
+ * EXAMPLE
+ *
+ * [category1]
+ * var1 => val1
+ * var2 => val2
+ * \# lines that begin with \# are comments
+ * \#var3 => val3
+ * </pre>
+ * @{
+ */
+
+#ifndef ZAP_CONFIG_H
+#define ZAP_CONFIG_H
+
+#include "openzap.h"
+#define ZAP_URL_SEPARATOR "://"
+
+
+#ifdef WIN32
+#define ZAP_PATH_SEPARATOR "\\"
+#ifndef ZAP_CONFIG_DIR
+#define ZAP_CONFIG_DIR "c:\\openzap"
+#endif
+#define zap_is_file_path(file) (*(file +1) == ':' || *file == '/' || strstr(file, SWITCH_URL_SEPARATOR))
+#else
+#define ZAP_PATH_SEPARATOR "/"
+#ifndef ZAP_CONFIG_DIR
+#define ZAP_CONFIG_DIR "/etc/openzap"
+#endif
+#define zap_is_file_path(file) ((*file == '/') || strstr(file, SWITCH_URL_SEPARATOR))
+#endif
+
+typedef struct zap_config zap_config_t;
+
+/*! \brief A simple file handle representing an open configuration file **/
+struct zap_config {
+ /*! FILE stream buffer to the opened file */
+ FILE *file;
+ /*! path to the file */
+ char path[512];
+ /*! current category */
+ char category[256];
+ /*! current section */
+ char section[256];
+ /*! buffer of current line being read */
+ char buf[1024];
+ /*! current line number in file */
+ int lineno;
+ /*! current category number in file */
+ int catno;
+ /*! current section number in file */
+ int sectno;
+
+ int lockto;
+};
+
+/*!
+ \brief Open a configuration file
+ \param cfg (zap_config_t *) config handle to use
+ \param file_path path to the file
+ \return 1 (true) on success 0 (false) on failure
+*/
+int zap_config_open_file(zap_config_t * cfg, const char *file_path);
+
+/*!
+ \brief Close a previously opened configuration file
+ \param cfg (zap_config_t *) config handle to use
+*/
+void zap_config_close_file(zap_config_t * cfg);
+
+/*!
+ \brief Retrieve next name/value pair from configuration file
+ \param cfg (zap_config_t *) config handle to use
+ \param var pointer to aim at the new variable name
+ \param val pointer to aim at the new value
+*/
+int zap_config_next_pair(zap_config_t * cfg, char **var, char **val);
+
+/*!
+ \brief Retrieve the CAS bits from a configuration string value
+ \param strvalue pointer to the configuration string value (expected to be in format whatever:xxxx)
+ \param outbits pointer to aim at the CAS bits
+*/
+OZ_DECLARE (int) zap_config_get_cas_bits(char *strvalue, unsigned char *outbits);
+
+
+/** @} */
+#endif
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/include/zap_cpu_monitor.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/include/zap_cpu_monitor.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/zap_cpu_monitor.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,74 @@
+/* * Copyright (c) 2009, Sangoma Technologies
+ * Moises Silva <moy@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:
+ * David Yat Sin <dyatsin@sangoma.com>
+ *
+ */
+
+/*! \brief opaque cpu stats structure */
+struct zap_cpu_monitor_stats;
+
+/*!
+ * \brief create a new cpu monitor
+ * \return profile timer structure previously created with new_profile_timer, NULL on error
+ */
+OZ_DECLARE(struct zap_cpu_monitor_stats*) zap_new_cpu_monitor(void);
+
+/*!
+ * \brief Deletes cpu_monitor
+ */
+OZ_DECLARE(void) zap_delete_cpu_monitor(struct zap_cpu_monitor_stats *p);
+
+/*!
+ * \brief provides the percentage of idle system time
+ * \param p cpu_stats structure previously created with zap_new_cpu_monitor
+ * \param pointer to store the percentage of idle time
+ * \return -1 on error 0 for success
+ */
+OZ_DECLARE(zap_status_t) zap_cpu_get_system_idle_time (struct zap_cpu_monitor_stats *p, double *idle_percentage);
+
+
+
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/include/zap_dso.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/include/zap_dso.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/zap_dso.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,44 @@
+/*
+ * Cross Platform dso/dll load abstraction
+ * Copyright(C) 2008 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer.
+ *
+ */
+
+
+#ifndef _ZAP_DSO_H
+#define _ZAP_DSO_H
+
+typedef void (*zap_func_ptr_t) (void);
+typedef void * zap_dso_lib_t;
+
+void zap_dso_destroy(zap_dso_lib_t *lib);
+zap_dso_lib_t zap_dso_open(const char *path, char **err);
+void *zap_dso_func_sym(zap_dso_lib_t lib, const char *sym, char **err);
+
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4
+ */
+
Added: freeswitch/trunk/libs/openzap/src/include/zap_m3ua.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/include/zap_m3ua.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/zap_m3ua.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,128 @@
+/*
+ * zap_m3ua.h
+ * openzap
+ *
+ * Created by Shane Burrell on 4/3/08.
+ * Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ *
+ * 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.
+ */
+
+
+//#include "m3ua_client.h"
+#include "openzap.h"
+enum e_sigboost_event_id_values
+{
+ SIGBOOST_EVENT_CALL_START = 0x80, /*128*/
+ SIGBOOST_EVENT_CALL_START_ACK = 0x81, /*129*/
+ SIGBOOST_EVENT_CALL_START_NACK = 0x82, /*130*/
+ SIGBOOST_EVENT_CALL_START_NACK_ACK = 0x83, /*131*/
+ SIGBOOST_EVENT_CALL_ANSWERED = 0x84, /*132*/
+ SIGBOOST_EVENT_CALL_STOPPED = 0x85, /*133*/
+ SIGBOOST_EVENT_CALL_STOPPED_ACK = 0x86, /*134*/
+ SIGBOOST_EVENT_SYSTEM_RESTART = 0x87, /*135*/
+ SIGBOOST_EVENT_SYSTEM_RESTART_ACK = 0x88, /*136*/
+ /* Following IDs are ss7boost to sangoma_mgd only. */
+ SIGBOOST_EVENT_HEARTBEAT = 0x89, /*137*/
+ SIGBOOST_EVENT_INSERT_CHECK_LOOP = 0x8a, /*138*/
+ SIGBOOST_EVENT_REMOVE_CHECK_LOOP = 0x8b, /*139*/
+ SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE = 0x8c, /*140*/
+};
+enum e_sigboost_release_cause_values
+{
+ SIGBOOST_RELEASE_CAUSE_UNDEFINED = 0,
+ SIGBOOST_RELEASE_CAUSE_NORMAL = 16,
+ SIGBOOST_RELEASE_CAUSE_BUSY = 17,
+ /* probable elimination */
+ //SIGBOOST_RELEASE_CAUSE_BUSY = 0x91, /* 145 */
+ //SIGBOOST_RELEASE_CAUSE_CALLED_NOT_EXIST = 0x92, /* 146 */
+ //SIGBOOST_RELEASE_CAUSE_CIRCUIT_RESET = 0x93, /* 147 */
+ //SIGBOOST_RELEASE_CAUSE_NOANSWER = 0x94, /* 148 */
+};
+
+enum e_sigboost_call_setup_ack_nack_cause_values
+{
+ SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY = 117, /* unused Q.850 value */
+ SIGBOOST_CALL_SETUP_NACK_TEST_CKT_BUSY = 118, /* unused Q.850 value */
+ SIGBOOST_CALL_SETUP_NACK_INVALID_NUMBER = 28,
+ /* probable elimination */
+ //SIGBOOST_CALL_SETUP_RESERVED = 0x00,
+ //SIGBOOST_CALL_SETUP_CIRCUIT_RESET = 0x10,
+ //SIGBOOST_CALL_SETUP_NACK_CKT_START_TIMEOUT = 0x11,
+ //SIGBOOST_CALL_SETUP_NACK_AUTO_CALL_GAP = 0x17,
+};
+typedef enum {
+ M3UA_SPAN_SIGNALING_M3UA,
+ M3UA_SPAN_SIGNALING_SS7BOX,
+
+} M3UA_TSpanSignaling;
+#define M3UA_SPAN_STRINGS "M3UA", "SS7BOX"
+ZAP_STR2ENUM_P(m3ua_str2span, m3ua_span2str, M3UA_TSpanSignaling)
+
+
+
+typedef enum {
+ ZAP_M3UA_RUNNING = (1 << 0)
+} zap_m3uat_flag_t;
+
+/*typedef struct m3ua_data {
+ m3uac_connection_t mcon;
+ m3uac_connection_t pcon;
+ zio_signal_cb_t signal_cb;
+ uint32_t flags;
+} m3ua_data_t;
+
+*/
+/*typedef struct mu3a_link {
+ ss7bc_connection_t mcon;
+ ss7bc_connection_t pcon;
+ zio_signal_cb_t signal_cb;
+ uint32_t flags;
+} zap_m3ua_data_t;
+*/
+
+zap_status_t m3ua_init(zap_io_interface_t **zint);
+zap_status_t m3ua_destroy(void);
+zap_status_t m3ua_start(zap_span_t *span);
+
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/openzap/src/include/zap_threadmutex.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/include/zap_threadmutex.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/zap_threadmutex.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,56 @@
+/*
+ * Cross Platform Thread/Mutex abstraction
+ * Copyright(C) 2007 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer.
+ *
+ */
+
+
+#ifndef _ZAP_THREADMUTEX_H
+#define _ZAP_THREADMUTEX_H
+
+#include "openzap.h"
+
+typedef struct zap_mutex zap_mutex_t;
+typedef struct zap_thread zap_thread_t;
+typedef void *(*zap_thread_function_t) (zap_thread_t *, void *);
+
+OZ_DECLARE(zap_status_t) zap_thread_create_detached(zap_thread_function_t func, void *data);
+OZ_DECLARE(zap_status_t) zap_thread_create_detached_ex(zap_thread_function_t func, void *data, zap_size_t stack_size);
+OZ_DECLARE(void) zap_thread_override_default_stacksize(zap_size_t size);
+OZ_DECLARE(zap_status_t) zap_mutex_create(zap_mutex_t **mutex);
+OZ_DECLARE(zap_status_t) zap_mutex_destroy(zap_mutex_t **mutex);
+OZ_DECLARE(zap_status_t) _zap_mutex_lock(zap_mutex_t *mutex);
+OZ_DECLARE(zap_status_t) _zap_mutex_trylock(zap_mutex_t *mutex);
+OZ_DECLARE(zap_status_t) _zap_mutex_unlock(zap_mutex_t *mutex);
+
+OZ_DECLARE(zap_status_t) zap_interrupt_create(zap_interrupt_t **ininterrupt, zap_socket_t device);
+OZ_DECLARE(zap_status_t) zap_interrupt_wait(zap_interrupt_t *interrupt, int ms);
+OZ_DECLARE(zap_status_t) zap_interrupt_signal(zap_interrupt_t *interrupt);
+OZ_DECLARE(zap_status_t) zap_interrupt_destroy(zap_interrupt_t **ininterrupt);
+OZ_DECLARE(zap_status_t) zap_interrupt_multiple_wait(zap_interrupt_t *interrupts[], zap_size_t size, int ms);
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/openzap/src/include/zap_types.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/include/zap_types.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/zap_types.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,639 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#ifndef ZAP_TYPES_H
+#define ZAP_TYPES_H
+#include "fsk.h"
+
+#ifdef WIN32
+#define ZAP_INVALID_SOCKET INVALID_HANDLE_VALUE
+#else
+#define ZAP_INVALID_SOCKET -1
+#endif
+#define zap_array_len(obj) sizeof(obj)/sizeof(obj[0])
+
+#ifdef WIN32
+#include <windows.h>
+typedef HANDLE zap_socket_t;
+typedef unsigned __int64 uint64_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int8 uint8_t;
+typedef __int64 int64_t;
+typedef __int32 int32_t;
+typedef __int16 int16_t;
+typedef __int8 int8_t;
+typedef intptr_t zap_ssize_t;
+typedef int zap_filehandle_t;
+#else
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <stdarg.h>
+typedef int zap_socket_t;
+typedef ssize_t zap_ssize_t;
+typedef int zap_filehandle_t;
+#endif
+
+#define TAG_END NULL
+
+typedef size_t zap_size_t;
+struct zap_io_interface;
+typedef struct zap_interrupt zap_interrupt_t;
+
+#define ZAP_COMMAND_OBJ_INT *((int *)obj)
+#define ZAP_COMMAND_OBJ_CHAR_P (char *)obj
+#define ZAP_COMMAND_OBJ_FLOAT *((float *)obj)
+#define ZAP_FSK_MOD_FACTOR 0x10000
+#define ZAP_DEFAULT_DTMF_ON 250
+#define ZAP_DEFAULT_DTMF_OFF 50
+
+#define ZAP_END -1
+#define ZAP_ANY_STATE -1
+
+typedef uint64_t zap_time_t;
+
+typedef enum {
+ ZAP_ENDIAN_BIG = 1,
+ ZAP_ENDIAN_LITTLE = -1
+} zap_endian_t;
+
+typedef enum {
+ ZAP_CID_TYPE_SDMF = 0x04,
+ ZAP_CID_TYPE_MDMF = 0x80
+} zap_cid_type_t;
+
+typedef enum {
+ MDMF_DATETIME = 1,
+ MDMF_PHONE_NUM = 2,
+ MDMF_DDN = 3,
+ MDMF_NO_NUM = 4,
+ MDMF_PHONE_NAME = 7,
+ MDMF_NO_NAME = 8,
+ MDMF_ALT_ROUTE = 9,
+ MDMF_INVALID = 10
+} zap_mdmf_type_t;
+#define MDMF_STRINGS "X", "DATETIME", "PHONE_NUM", "DDN", "NO_NUM", "X", "X", "PHONE_NAME", "NO_NAME", "ALT_ROUTE", "INVALID"
+ZAP_STR2ENUM_P(zap_str2zap_mdmf_type, zap_mdmf_type2str, zap_mdmf_type_t)
+
+#define ZAP_TONEMAP_LEN 128
+typedef enum {
+ ZAP_TONEMAP_NONE,
+ ZAP_TONEMAP_DIAL,
+ ZAP_TONEMAP_RING,
+ ZAP_TONEMAP_BUSY,
+ ZAP_TONEMAP_FAIL1,
+ ZAP_TONEMAP_FAIL2,
+ ZAP_TONEMAP_FAIL3,
+ ZAP_TONEMAP_ATTN,
+ ZAP_TONEMAP_CALLWAITING_CAS,
+ ZAP_TONEMAP_CALLWAITING_SAS,
+ ZAP_TONEMAP_CALLWAITING_ACK,
+ ZAP_TONEMAP_INVALID
+} zap_tonemap_t;
+#define TONEMAP_STRINGS "NONE", "DIAL", "RING", "BUSY", "FAIL1", "FAIL2", "FAIL3", "ATTN", "CALLWAITING-CAS", "CALLWAITING-SAS", "CALLWAITING-ACK", "INVALID"
+ZAP_STR2ENUM_P(zap_str2zap_tonemap, zap_tonemap2str, zap_tonemap_t)
+
+typedef enum {
+ ZAP_TRUNK_E1,
+ ZAP_TRUNK_T1,
+ ZAP_TRUNK_J1,
+ ZAP_TRUNK_BRI,
+ ZAP_TRUNK_BRI_PTMP,
+ ZAP_TRUNK_FXO,
+ ZAP_TRUNK_FXS,
+ ZAP_TRUNK_EM,
+ ZAP_TRUNK_NONE
+} zap_trunk_type_t;
+#define TRUNK_STRINGS "E1", "T1", "J1", "BRI", "BRI_PTMP", "FXO", "FXS", "EM", "NONE"
+ZAP_STR2ENUM_P(zap_str2zap_trunk_type, zap_trunk_type2str, zap_trunk_type_t)
+
+typedef enum {
+ ZAP_ANALOG_START_KEWL,
+ ZAP_ANALOG_START_LOOP,
+ ZAP_ANALOG_START_GROUND,
+ ZAP_ANALOG_START_WINK,
+ ZAP_ANALOG_START_NA
+} zap_analog_start_type_t;
+#define START_TYPE_STRINGS "KEWL", "LOOP", "GROUND", "WINK", "NA"
+ZAP_STR2ENUM_P(zap_str2zap_analog_start_type, zap_analog_start_type2str, zap_analog_start_type_t)
+
+typedef enum {
+ ZAP_OOB_DTMF,
+ ZAP_OOB_ONHOOK,
+ ZAP_OOB_OFFHOOK,
+ ZAP_OOB_WINK,
+ ZAP_OOB_FLASH,
+ ZAP_OOB_RING_START,
+ ZAP_OOB_RING_STOP,
+ ZAP_OOB_ALARM_TRAP,
+ ZAP_OOB_ALARM_CLEAR,
+ ZAP_OOB_NOOP,
+ ZAP_OOB_CAS_BITS_CHANGE,
+ ZAP_OOB_INVALID
+} zap_oob_event_t;
+#define OOB_STRINGS "DTMF", "ONHOOK", "OFFHOOK", "WINK", "FLASH", "RING_START", "RING_STOP", "ALARM_TRAP", "ALARM_CLEAR", "NOOP", "CAS_BITS_CHANGE", "INVALID"
+ZAP_STR2ENUM_P(zap_str2zap_oob_event, zap_oob_event2str, zap_oob_event_t)
+
+typedef enum {
+ ZAP_ALARM_NONE = 0,
+ ZAP_ALARM_RECOVER = (1 << 0),
+ ZAP_ALARM_LOOPBACK = (1 << 2),
+ ZAP_ALARM_YELLOW = (1 << 3),
+ ZAP_ALARM_RED = (1 << 4),
+ ZAP_ALARM_BLUE = (1 << 5),
+ ZAP_ALARM_NOTOPEN = ( 1 << 6),
+ ZAP_ALARM_AIS = ( 1 << 7),
+ ZAP_ALARM_RAI = ( 1 << 8),
+ ZAP_ALARM_GENERAL = ( 1 << 30)
+} zap_alarm_flag_t;
+
+typedef enum {
+ ZAP_SIGTYPE_NONE,
+ ZAP_SIGTYPE_ISDN,
+ ZAP_SIGTYPE_RBS,
+ ZAP_SIGTYPE_ANALOG,
+ ZAP_SIGTYPE_SANGOMABOOST,
+ ZAP_SIGTYPE_M3UA,
+ ZAP_SIGTYPE_R2
+} zap_signal_type_t;
+
+typedef enum {
+ ZAP_SIGEVENT_START,
+ ZAP_SIGEVENT_STOP,
+ ZAP_SIGEVENT_TRANSFER,
+ ZAP_SIGEVENT_ANSWER,
+ ZAP_SIGEVENT_UP,
+ ZAP_SIGEVENT_FLASH,
+ ZAP_SIGEVENT_PROGRESS,
+ ZAP_SIGEVENT_PROGRESS_MEDIA,
+ ZAP_SIGEVENT_NOTIFY,
+ ZAP_SIGEVENT_TONE_DETECTED,
+ ZAP_SIGEVENT_ALARM_TRAP,
+ ZAP_SIGEVENT_ALARM_CLEAR,
+ ZAP_SIGEVENT_MISC,
+ ZAP_SIGEVENT_COLLECTED_DIGIT,
+ ZAP_SIGEVENT_ADD_CALL,
+ ZAP_SIGEVENT_RESTART,
+ ZAP_SIGEVENT_INVALID
+} zap_signal_event_t;
+#define SIGNAL_STRINGS "START", "STOP", "TRANSFER", "ANSWER", "UP", "FLASH", "PROGRESS", \
+ "PROGRESS_MEDIA", "NOTIFY", "TONE_DETECTED", "ALARM_TRAP", "ALARM_CLEAR", "MISC", "COLLECTED_DIGIT", "ADD_CALL", "RESTART", "INVALID"
+ZAP_STR2ENUM_P(zap_str2zap_signal_event, zap_signal_event2str, zap_signal_event_t)
+
+typedef enum {
+ ZAP_EVENT_NONE,
+ ZAP_EVENT_DTMF,
+ ZAP_EVENT_OOB,
+ ZAP_EVENT_COUNT
+} zap_event_type_t;
+
+typedef enum {
+ ZAP_TOP_DOWN,
+ ZAP_BOTTOM_UP
+} zap_direction_t;
+
+typedef enum {
+ ZAP_SUCCESS,
+ ZAP_FAIL,
+ ZAP_MEMERR,
+ ZAP_TIMEOUT,
+ ZAP_NOTIMPL,
+ ZAP_CHECKSUM_ERROR,
+ ZAP_STATUS_COUNT,
+ ZAP_BREAK
+} zap_status_t;
+
+typedef enum {
+ ZAP_NO_FLAGS = 0,
+ ZAP_READ = (1 << 0),
+ ZAP_WRITE = (1 << 1),
+ ZAP_EVENTS = (1 << 2)
+} zap_wait_flag_t;
+
+typedef enum {
+ ZAP_CODEC_ULAW = 0,
+ ZAP_CODEC_ALAW = 8,
+ ZAP_CODEC_SLIN = 10,
+ ZAP_CODEC_NONE = (1 << 30)
+} zap_codec_t;
+
+typedef enum {
+ ZAP_TONE_DTMF = (1 << 0)
+} zap_tone_type_t;
+
+typedef enum {
+ ZAP_COMMAND_NOOP,
+ ZAP_COMMAND_SET_INTERVAL,
+ ZAP_COMMAND_GET_INTERVAL,
+ ZAP_COMMAND_SET_CODEC,
+ ZAP_COMMAND_GET_CODEC,
+ ZAP_COMMAND_SET_NATIVE_CODEC,
+ ZAP_COMMAND_GET_NATIVE_CODEC,
+ ZAP_COMMAND_ENABLE_DTMF_DETECT,
+ ZAP_COMMAND_DISABLE_DTMF_DETECT,
+ ZAP_COMMAND_SEND_DTMF,
+ ZAP_COMMAND_SET_DTMF_ON_PERIOD,
+ ZAP_COMMAND_GET_DTMF_ON_PERIOD,
+ ZAP_COMMAND_SET_DTMF_OFF_PERIOD,
+ ZAP_COMMAND_GET_DTMF_OFF_PERIOD,
+ ZAP_COMMAND_GENERATE_RING_ON,
+ ZAP_COMMAND_GENERATE_RING_OFF,
+ ZAP_COMMAND_OFFHOOK,
+ ZAP_COMMAND_ONHOOK,
+ ZAP_COMMAND_FLASH,
+ ZAP_COMMAND_WINK,
+ ZAP_COMMAND_ENABLE_PROGRESS_DETECT,
+ ZAP_COMMAND_DISABLE_PROGRESS_DETECT,
+ ZAP_COMMAND_TRACE_INPUT,
+ ZAP_COMMAND_TRACE_OUTPUT,
+ ZAP_COMMAND_ENABLE_CALLERID_DETECT,
+ ZAP_COMMAND_DISABLE_CALLERID_DETECT,
+ ZAP_COMMAND_ENABLE_ECHOCANCEL,
+ ZAP_COMMAND_DISABLE_ECHOCANCEL,
+ ZAP_COMMAND_ENABLE_ECHOTRAIN,
+ ZAP_COMMAND_DISABLE_ECHOTRAIN,
+ ZAP_COMMAND_SET_CAS_BITS,
+ ZAP_COMMAND_GET_CAS_BITS,
+ ZAP_COMMAND_SET_RX_GAIN,
+ ZAP_COMMAND_GET_RX_GAIN,
+ ZAP_COMMAND_SET_TX_GAIN,
+ ZAP_COMMAND_GET_TX_GAIN,
+ ZAP_COMMAND_FLUSH_TX_BUFFERS,
+ ZAP_COMMAND_FLUSH_RX_BUFFERS,
+ ZAP_COMMAND_FLUSH_BUFFERS,
+ ZAP_COMMAND_SET_PRE_BUFFER_SIZE,
+ ZAP_COMMAND_ENABLE_LOOP,
+ ZAP_COMMAND_DISABLE_LOOP,
+ ZAP_COMMAND_COUNT
+} zap_command_t;
+
+typedef enum {
+ ZAP_SPAN_CONFIGURED = (1 << 0),
+ ZAP_SPAN_READY = (1 << 1),
+ ZAP_SPAN_STATE_CHANGE = (1 << 2),
+ ZAP_SPAN_SUSPENDED = (1 << 3),
+ ZAP_SPAN_IN_THREAD = (1 << 4),
+ ZAP_SPAN_STOP_THREAD = (1 << 5)
+} zap_span_flag_t;
+
+typedef enum {
+ ZAP_CHAN_TYPE_B,
+ ZAP_CHAN_TYPE_DQ921,
+ ZAP_CHAN_TYPE_DQ931,
+ ZAP_CHAN_TYPE_FXS,
+ ZAP_CHAN_TYPE_FXO,
+ ZAP_CHAN_TYPE_EM,
+ ZAP_CHAN_TYPE_CAS,
+ ZAP_CHAN_TYPE_COUNT
+} zap_chan_type_t;
+
+#define CHAN_TYPE_STRINGS "B", "DQ921", "DQ931", "FXS", "FXO", "EM", "CAS", "INVALID"
+ZAP_STR2ENUM_P(zap_str2zap_chan_type, zap_chan_type2str, zap_chan_type_t)
+
+#define ZAP_IS_VOICE_CHANNEL(zap_chan) ((zap_chan)->type != ZAP_CHAN_TYPE_DQ921 && (zap_chan)->type != ZAP_CHAN_TYPE_DQ931)
+
+typedef enum {
+ ZAP_CHANNEL_FEATURE_DTMF_DETECT = (1 << 0),
+ ZAP_CHANNEL_FEATURE_DTMF_GENERATE = (1 << 1),
+ ZAP_CHANNEL_FEATURE_CODECS = (1 << 2),
+ ZAP_CHANNEL_FEATURE_INTERVAL = (1 << 3),
+ ZAP_CHANNEL_FEATURE_CALLERID = (1 << 4),
+ ZAP_CHANNEL_FEATURE_PROGRESS = (1 << 5)
+} zap_channel_feature_t;
+
+typedef enum {
+ ZAP_CHANNEL_STATE_DOWN,
+ ZAP_CHANNEL_STATE_HOLD,
+ ZAP_CHANNEL_STATE_SUSPENDED,
+ ZAP_CHANNEL_STATE_DIALTONE,
+ ZAP_CHANNEL_STATE_COLLECT,
+ ZAP_CHANNEL_STATE_RING,
+ ZAP_CHANNEL_STATE_BUSY,
+ ZAP_CHANNEL_STATE_ATTN,
+ ZAP_CHANNEL_STATE_GENRING,
+ ZAP_CHANNEL_STATE_DIALING,
+ ZAP_CHANNEL_STATE_GET_CALLERID,
+ ZAP_CHANNEL_STATE_CALLWAITING,
+ ZAP_CHANNEL_STATE_RESTART,
+ ZAP_CHANNEL_STATE_PROGRESS,
+ ZAP_CHANNEL_STATE_PROGRESS_MEDIA,
+ ZAP_CHANNEL_STATE_UP,
+ ZAP_CHANNEL_STATE_IDLE,
+ ZAP_CHANNEL_STATE_TERMINATING,
+ ZAP_CHANNEL_STATE_CANCEL,
+ ZAP_CHANNEL_STATE_HANGUP,
+ ZAP_CHANNEL_STATE_HANGUP_COMPLETE,
+ ZAP_CHANNEL_STATE_IN_LOOP,
+ ZAP_CHANNEL_STATE_INVALID
+} zap_channel_state_t;
+#define CHANNEL_STATE_STRINGS "DOWN", "HOLD", "SUSPENDED", "DIALTONE", "COLLECT", \
+ "RING", "BUSY", "ATTN", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", \
+ "RESTART", "PROGRESS", "PROGRESS_MEDIA", "UP", "IDLE", "TERMINATING", "CANCEL", "HANGUP", "HANGUP_COMPLETE", "INVALID"
+ZAP_STR2ENUM_P(zap_str2zap_channel_state, zap_channel_state2str, zap_channel_state_t)
+
+typedef enum {
+ ZAP_CHANNEL_CONFIGURED = (1 << 0),
+ ZAP_CHANNEL_READY = (1 << 1),
+ ZAP_CHANNEL_OPEN = (1 << 2),
+ ZAP_CHANNEL_DTMF_DETECT = (1 << 3),
+ ZAP_CHANNEL_SUPRESS_DTMF = (1 << 4),
+ ZAP_CHANNEL_TRANSCODE = (1 << 5),
+ ZAP_CHANNEL_BUFFER = (1 << 6),
+ ZAP_CHANNEL_EVENT = (1 << 7),
+ ZAP_CHANNEL_INTHREAD = (1 << 8),
+ ZAP_CHANNEL_WINK = (1 << 9),
+ ZAP_CHANNEL_FLASH = (1 << 10),
+ ZAP_CHANNEL_STATE_CHANGE = (1 << 11),
+ ZAP_CHANNEL_HOLD = (1 << 12),
+ ZAP_CHANNEL_INUSE = (1 << 13),
+ ZAP_CHANNEL_OFFHOOK = (1 << 14),
+ ZAP_CHANNEL_RINGING = (1 << 15),
+ ZAP_CHANNEL_PROGRESS_DETECT = (1 << 16),
+ ZAP_CHANNEL_CALLERID_DETECT = (1 << 17),
+ ZAP_CHANNEL_OUTBOUND = (1 << 18),
+ ZAP_CHANNEL_SUSPENDED = (1 << 19),
+ ZAP_CHANNEL_3WAY = (1 << 20),
+ ZAP_CHANNEL_PROGRESS = (1 << 21),
+ ZAP_CHANNEL_MEDIA = (1 << 22),
+ ZAP_CHANNEL_ANSWERED = (1 << 23),
+ ZAP_CHANNEL_MUTE = (1 << 24),
+ ZAP_CHANNEL_USE_RX_GAIN = (1 << 25),
+ ZAP_CHANNEL_USE_TX_GAIN = (1 << 26),
+} zap_channel_flag_t;
+
+typedef enum {
+ ZSM_NONE,
+ ZSM_UNACCEPTABLE,
+ ZSM_ACCEPTABLE
+} zap_state_map_type_t;
+
+typedef enum {
+ ZSD_INBOUND,
+ ZSD_OUTBOUND,
+} zap_state_direction_t;
+
+#define ZAP_MAP_NODE_SIZE 512
+#define ZAP_MAP_MAX ZAP_CHANNEL_STATE_INVALID+2
+
+struct zap_state_map_node {
+ zap_state_direction_t direction;
+ zap_state_map_type_t type;
+ zap_channel_state_t check_states[ZAP_MAP_MAX];
+ zap_channel_state_t states[ZAP_MAP_MAX];
+};
+typedef struct zap_state_map_node zap_state_map_node_t;
+
+struct zap_state_map {
+ zap_state_map_node_t nodes[ZAP_MAP_NODE_SIZE];
+};
+typedef struct zap_state_map zap_state_map_t;
+
+typedef struct zap_channel zap_channel_t;
+typedef struct zap_event zap_event_t;
+typedef struct zap_sigmsg zap_sigmsg_t;
+typedef struct zap_span zap_span_t;
+typedef struct zap_caller_data zap_caller_data_t;
+typedef struct zap_io_interface zap_io_interface_t;
+
+struct zap_stream_handle;
+typedef struct zap_stream_handle zap_stream_handle_t;
+
+typedef zap_status_t (*zap_stream_handle_raw_write_function_t) (zap_stream_handle_t *handle, uint8_t *data, zap_size_t datalen);
+typedef zap_status_t (*zap_stream_handle_write_function_t) (zap_stream_handle_t *handle, const char *fmt, ...);
+
+#define ZIO_CHANNEL_REQUEST_ARGS (zap_span_t *span, uint32_t chan_id, zap_direction_t direction, zap_caller_data_t *caller_data, zap_channel_t **zchan)
+#define ZIO_CHANNEL_OUTGOING_CALL_ARGS (zap_channel_t *zchan)
+#define ZIO_SPAN_POLL_EVENT_ARGS (zap_span_t *span, uint32_t ms)
+#define ZIO_SPAN_NEXT_EVENT_ARGS (zap_span_t *span, zap_event_t **event)
+#define ZIO_SIGNAL_CB_ARGS (zap_sigmsg_t *sigmsg)
+#define ZIO_EVENT_CB_ARGS (zap_channel_t *zchan, zap_event_t *event)
+#define ZIO_CODEC_ARGS (void *data, zap_size_t max, zap_size_t *datalen)
+#define ZIO_CONFIGURE_SPAN_ARGS (zap_span_t *span, const char *str, zap_chan_type_t type, char *name, char *number)
+#define ZIO_CONFIGURE_ARGS (const char *category, const char *var, const char *val, int lineno)
+#define ZIO_OPEN_ARGS (zap_channel_t *zchan)
+#define ZIO_CLOSE_ARGS (zap_channel_t *zchan)
+#define ZIO_CHANNEL_DESTROY_ARGS (zap_channel_t *zchan)
+#define ZIO_SPAN_DESTROY_ARGS (zap_span_t *span)
+#define ZIO_COMMAND_ARGS (zap_channel_t *zchan, zap_command_t command, void *obj)
+#define ZIO_WAIT_ARGS (zap_channel_t *zchan, zap_wait_flag_t *flags, int32_t to)
+#define ZIO_GET_ALARMS_ARGS (zap_channel_t *zchan)
+#define ZIO_READ_ARGS (zap_channel_t *zchan, void *data, zap_size_t *datalen)
+#define ZIO_WRITE_ARGS (zap_channel_t *zchan, void *data, zap_size_t *datalen)
+#define ZIO_IO_LOAD_ARGS (zap_io_interface_t **zio)
+#define ZIO_IO_UNLOAD_ARGS (void)
+#define ZIO_SIG_LOAD_ARGS (void)
+#define ZIO_SIG_CONFIGURE_ARGS (zap_span_t *span, zio_signal_cb_t sig_cb, va_list ap)
+#define ZIO_SIG_UNLOAD_ARGS (void)
+#define ZIO_API_ARGS (zap_stream_handle_t *stream, const char *data)
+
+typedef zap_status_t (*zio_channel_request_t) ZIO_CHANNEL_REQUEST_ARGS ;
+typedef zap_status_t (*zio_channel_outgoing_call_t) ZIO_CHANNEL_OUTGOING_CALL_ARGS ;
+typedef zap_status_t (*zio_span_poll_event_t) ZIO_SPAN_POLL_EVENT_ARGS ;
+typedef zap_status_t (*zio_span_next_event_t) ZIO_SPAN_NEXT_EVENT_ARGS ;
+typedef zap_status_t (*zio_signal_cb_t) ZIO_SIGNAL_CB_ARGS ;
+typedef zap_status_t (*zio_event_cb_t) ZIO_EVENT_CB_ARGS ;
+typedef zap_status_t (*zio_codec_t) ZIO_CODEC_ARGS ;
+typedef zap_status_t (*zio_configure_span_t) ZIO_CONFIGURE_SPAN_ARGS ;
+typedef zap_status_t (*zio_configure_t) ZIO_CONFIGURE_ARGS ;
+typedef zap_status_t (*zio_open_t) ZIO_OPEN_ARGS ;
+typedef zap_status_t (*zio_close_t) ZIO_CLOSE_ARGS ;
+typedef zap_status_t (*zio_channel_destroy_t) ZIO_CHANNEL_DESTROY_ARGS ;
+typedef zap_status_t (*zio_span_destroy_t) ZIO_SPAN_DESTROY_ARGS ;
+typedef zap_status_t (*zio_get_alarms_t) ZIO_GET_ALARMS_ARGS ;
+typedef zap_status_t (*zio_command_t) ZIO_COMMAND_ARGS ;
+typedef zap_status_t (*zio_wait_t) ZIO_WAIT_ARGS ;
+typedef zap_status_t (*zio_read_t) ZIO_READ_ARGS ;
+typedef zap_status_t (*zio_write_t) ZIO_WRITE_ARGS ;
+typedef zap_status_t (*zio_io_load_t) ZIO_IO_LOAD_ARGS ;
+typedef zap_status_t (*zio_sig_load_t) ZIO_SIG_LOAD_ARGS ;
+typedef zap_status_t (*zio_sig_configure_t) ZIO_SIG_CONFIGURE_ARGS ;
+typedef zap_status_t (*zio_io_unload_t) ZIO_IO_UNLOAD_ARGS ;
+typedef zap_status_t (*zio_sig_unload_t) ZIO_SIG_UNLOAD_ARGS ;
+typedef zap_status_t (*zio_api_t) ZIO_API_ARGS ;
+
+
+#define ZIO_CHANNEL_REQUEST_FUNCTION(name) zap_status_t name ZIO_CHANNEL_REQUEST_ARGS
+#define ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(name) zap_status_t name ZIO_CHANNEL_OUTGOING_CALL_ARGS
+#define ZIO_SPAN_POLL_EVENT_FUNCTION(name) zap_status_t name ZIO_SPAN_POLL_EVENT_ARGS
+#define ZIO_SPAN_NEXT_EVENT_FUNCTION(name) zap_status_t name ZIO_SPAN_NEXT_EVENT_ARGS
+#define ZIO_SIGNAL_CB_FUNCTION(name) zap_status_t name ZIO_SIGNAL_CB_ARGS
+#define ZIO_EVENT_CB_FUNCTION(name) zap_status_t name ZIO_EVENT_CB_ARGS
+#define ZIO_CODEC_FUNCTION(name) OZ_DECLARE_NONSTD(zap_status_t) name ZIO_CODEC_ARGS
+#define ZIO_CONFIGURE_SPAN_FUNCTION(name) zap_status_t name ZIO_CONFIGURE_SPAN_ARGS
+#define ZIO_CONFIGURE_FUNCTION(name) zap_status_t name ZIO_CONFIGURE_ARGS
+#define ZIO_OPEN_FUNCTION(name) zap_status_t name ZIO_OPEN_ARGS
+#define ZIO_CLOSE_FUNCTION(name) zap_status_t name ZIO_CLOSE_ARGS
+#define ZIO_CHANNEL_DESTROY_FUNCTION(name) zap_status_t name ZIO_CHANNEL_DESTROY_ARGS
+#define ZIO_SPAN_DESTROY_FUNCTION(name) zap_status_t name ZIO_SPAN_DESTROY_ARGS
+#define ZIO_GET_ALARMS_FUNCTION(name) zap_status_t name ZIO_GET_ALARMS_ARGS
+#define ZIO_COMMAND_FUNCTION(name) zap_status_t name ZIO_COMMAND_ARGS
+#define ZIO_WAIT_FUNCTION(name) zap_status_t name ZIO_WAIT_ARGS
+#define ZIO_READ_FUNCTION(name) zap_status_t name ZIO_READ_ARGS
+#define ZIO_WRITE_FUNCTION(name) zap_status_t name ZIO_WRITE_ARGS
+#define ZIO_IO_LOAD_FUNCTION(name) zap_status_t name ZIO_IO_LOAD_ARGS
+#define ZIO_SIG_LOAD_FUNCTION(name) zap_status_t name ZIO_SIG_LOAD_ARGS
+#define ZIO_SIG_CONFIGURE_FUNCTION(name) zap_status_t name ZIO_SIG_CONFIGURE_ARGS
+#define ZIO_IO_UNLOAD_FUNCTION(name) zap_status_t name ZIO_IO_UNLOAD_ARGS
+#define ZIO_SIG_UNLOAD_FUNCTION(name) zap_status_t name ZIO_SIG_UNLOAD_ARGS
+#define ZIO_API_FUNCTION(name) zap_status_t name ZIO_API_ARGS
+
+#include "zap_dso.h"
+
+
+
+typedef struct {
+ char name[256];
+ zio_io_load_t io_load;
+ zio_io_unload_t io_unload;
+ zio_sig_load_t sig_load;
+ zio_sig_configure_t sig_configure;
+ zio_sig_unload_t sig_unload;
+ zap_dso_lib_t lib;
+ char path[256];
+} zap_module_t;
+
+#ifndef __FUNCTION__
+#define __FUNCTION__ (const char *)__func__
+#endif
+
+#define ZAP_PRE __FILE__, __FUNCTION__, __LINE__
+#define ZAP_LOG_LEVEL_DEBUG 7
+#define ZAP_LOG_LEVEL_INFO 6
+#define ZAP_LOG_LEVEL_NOTICE 5
+#define ZAP_LOG_LEVEL_WARNING 4
+#define ZAP_LOG_LEVEL_ERROR 3
+#define ZAP_LOG_LEVEL_CRIT 2
+#define ZAP_LOG_LEVEL_ALERT 1
+#define ZAP_LOG_LEVEL_EMERG 0
+
+#define ZAP_LOG_DEBUG ZAP_PRE, ZAP_LOG_LEVEL_DEBUG
+#define ZAP_LOG_INFO ZAP_PRE, ZAP_LOG_LEVEL_INFO
+#define ZAP_LOG_NOTICE ZAP_PRE, ZAP_LOG_LEVEL_NOTICE
+#define ZAP_LOG_WARNING ZAP_PRE, ZAP_LOG_LEVEL_WARNING
+#define ZAP_LOG_ERROR ZAP_PRE, ZAP_LOG_LEVEL_ERROR
+#define ZAP_LOG_CRIT ZAP_PRE, ZAP_LOG_LEVEL_CRIT
+#define ZAP_LOG_ALERT ZAP_PRE, ZAP_LOG_LEVEL_ALERT
+#define ZAP_LOG_EMERG ZAP_PRE, ZAP_LOG_LEVEL_EMERG
+
+typedef struct zap_fsk_data_state zap_fsk_data_state_t;
+typedef int (*zap_fsk_data_decoder_t)(zap_fsk_data_state_t *state);
+typedef zap_status_t (*zap_fsk_write_sample_t)(int16_t *buf, zap_size_t buflen, void *user_data);
+typedef void (*zap_logger_t)(const char *file, const char *func, int line, int level, const char *fmt, ...);
+typedef struct hashtable zap_hash_t;
+typedef struct hashtable_iterator zap_hash_iterator_t;
+typedef struct key zap_hash_key_t;
+typedef struct value zap_hash_val_t;
+typedef struct zap_bitstream zap_bitstream_t;
+typedef struct zap_fsk_modulator zap_fsk_modulator_t;
+typedef zap_status_t (*zap_span_start_t)(zap_span_t *span);
+typedef zap_status_t (*zap_span_stop_t)(zap_span_t *span);
+
+typedef enum {
+ ZAP_CAUSE_NONE = 0,
+ ZAP_CAUSE_UNALLOCATED = 1,
+ ZAP_CAUSE_NO_ROUTE_TRANSIT_NET = 2,
+ ZAP_CAUSE_NO_ROUTE_DESTINATION = 3,
+ ZAP_CAUSE_CHANNEL_UNACCEPTABLE = 6,
+ ZAP_CAUSE_CALL_AWARDED_DELIVERED = 7,
+ ZAP_CAUSE_NORMAL_CLEARING = 16,
+ ZAP_CAUSE_USER_BUSY = 17,
+ ZAP_CAUSE_NO_USER_RESPONSE = 18,
+ ZAP_CAUSE_NO_ANSWER = 19,
+ ZAP_CAUSE_SUBSCRIBER_ABSENT = 20,
+ ZAP_CAUSE_CALL_REJECTED = 21,
+ ZAP_CAUSE_NUMBER_CHANGED = 22,
+ ZAP_CAUSE_REDIRECTION_TO_NEW_DESTINATION = 23,
+ ZAP_CAUSE_EXCHANGE_ROUTING_ERROR = 25,
+ ZAP_CAUSE_DESTINATION_OUT_OF_ORDER = 27,
+ ZAP_CAUSE_INVALID_NUMBER_FORMAT = 28,
+ ZAP_CAUSE_FACILITY_REJECTED = 29,
+ ZAP_CAUSE_RESPONSE_TO_STATUS_ENQUIRY = 30,
+ ZAP_CAUSE_NORMAL_UNSPECIFIED = 31,
+ ZAP_CAUSE_NORMAL_CIRCUIT_CONGESTION = 34,
+ ZAP_CAUSE_NETWORK_OUT_OF_ORDER = 38,
+ ZAP_CAUSE_NORMAL_TEMPORARY_FAILURE = 41,
+ ZAP_CAUSE_SWITCH_CONGESTION = 42,
+ ZAP_CAUSE_ACCESS_INFO_DISCARDED = 43,
+ ZAP_CAUSE_REQUESTED_CHAN_UNAVAIL = 44,
+ ZAP_CAUSE_PRE_EMPTED = 45,
+ ZAP_CAUSE_FACILITY_NOT_SUBSCRIBED = 50,
+ ZAP_CAUSE_OUTGOING_CALL_BARRED = 52,
+ ZAP_CAUSE_INCOMING_CALL_BARRED = 54,
+ ZAP_CAUSE_BEARERCAPABILITY_NOTAUTH = 57,
+ ZAP_CAUSE_BEARERCAPABILITY_NOTAVAIL = 58,
+ ZAP_CAUSE_SERVICE_UNAVAILABLE = 63,
+ ZAP_CAUSE_BEARERCAPABILITY_NOTIMPL = 65,
+ ZAP_CAUSE_CHAN_NOT_IMPLEMENTED = 66,
+ ZAP_CAUSE_FACILITY_NOT_IMPLEMENTED = 69,
+ ZAP_CAUSE_SERVICE_NOT_IMPLEMENTED = 79,
+ ZAP_CAUSE_INVALID_CALL_REFERENCE = 81,
+ ZAP_CAUSE_INCOMPATIBLE_DESTINATION = 88,
+ ZAP_CAUSE_INVALID_MSG_UNSPECIFIED = 95,
+ ZAP_CAUSE_MANDATORY_IE_MISSING = 96,
+ ZAP_CAUSE_MESSAGE_TYPE_NONEXIST = 97,
+ ZAP_CAUSE_WRONG_MESSAGE = 98,
+ ZAP_CAUSE_IE_NONEXIST = 99,
+ ZAP_CAUSE_INVALID_IE_CONTENTS = 100,
+ ZAP_CAUSE_WRONG_CALL_STATE = 101,
+ ZAP_CAUSE_RECOVERY_ON_TIMER_EXPIRE = 102,
+ ZAP_CAUSE_MANDATORY_IE_LENGTH_ERROR = 103,
+ ZAP_CAUSE_PROTOCOL_ERROR = 111,
+ ZAP_CAUSE_INTERWORKING = 127,
+ ZAP_CAUSE_SUCCESS = 142,
+ ZAP_CAUSE_ORIGINATOR_CANCEL = 487,
+ ZAP_CAUSE_CRASH = 500,
+ ZAP_CAUSE_SYSTEM_SHUTDOWN = 501,
+ ZAP_CAUSE_LOSE_RACE = 502,
+ ZAP_CAUSE_MANAGER_REQUEST = 503,
+ ZAP_CAUSE_BLIND_TRANSFER = 600,
+ ZAP_CAUSE_ATTENDED_TRANSFER = 601,
+ ZAP_CAUSE_ALLOTTED_TIMEOUT = 602,
+ ZAP_CAUSE_USER_CHALLENGE = 603,
+ ZAP_CAUSE_MEDIA_TIMEOUT = 604
+} zap_call_cause_t;
+
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/openzap/src/isdn/5ESSStateNT.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/5ESSStateNT.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/5ESSStateNT.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,132 @@
+/*****************************************************************************
+
+ FileName: 5ESSStateNT.c
+
+ Contents: AT&T 5ESS ISDN State Engine for NT (Network Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ Copyright (c) 2007, Michael S. Collins, All rights reserved.
+ email:mcollins@fcnetwork.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "5ESS.h"
+
+/*****************************************************************************
+ Function: ATT5ESSCreateNT
+
+ Description: Will create the AT&T 5ESS ISDN NT as a Dialect in the stack. The first
+ bulk set up the message handlers, the second bulk the IE
+ encoders/coders, and the last bulk set up the state table.
+
+ Parameters: i Dialect index
+*****************************************************************************/
+void ATT5ESSCreateNT(L3UCHAR i)
+{
+ Q931SetMesProc(Q931mes_ALERTING, i, Q931ProcAlertingNT, Q931Umes_Alerting, Q931Pmes_Alerting);
+ Q931SetMesProc(Q931mes_CALL_PROCEEDING, i, Q931ProcCallProceedingNT, Q931Umes_CallProceeding, Q931Pmes_CallProceeding);
+ Q931SetMesProc(Q931mes_CONNECT, i, Q931ProcConnectNT, Q931Umes_Connect, Q931Pmes_Connect);
+ Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i, Q931ProcConnectAckNT, Q931Umes_ConnectAck, Q931Pmes_ConnectAck);
+ Q931SetMesProc(Q931mes_PROGRESS, i, Q931ProcProgressNT, Q931Umes_Progress, Q931Pmes_Progress);
+ Q931SetMesProc(Q931mes_SETUP, i, Q931ProcSetupNT, Q931Umes_Setup, Q931Pmes_Setup);
+ Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE, i, Q931ProcSetupAckNT, Q931Umes_SetupAck, Q931Pmes_SetupAck);
+ Q931SetMesProc(Q931mes_RESUME, i, Q931ProcResumeNT, Q931Umes_Resume, Q931Pmes_Resume);
+ Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE, i, Q931ProcResumeAckNT, Q931Umes_ResumeAck, Q931Pmes_ResumeAck);
+ Q931SetMesProc(Q931mes_RESUME_REJECT, i, Q931ProcResumeRejectNT, Q931Umes_ResumeReject, Q931Pmes_ResumeReject);
+ Q931SetMesProc(Q931mes_SUSPEND, i, Q931ProcSuspendNT, Q931Umes_Suspend, Q931Pmes_Suspend);
+ Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE, i, Q931ProcSuspendAckNT, Q931Umes_SuspendAck, Q931Pmes_SuspendAck);
+ Q931SetMesProc(Q931mes_SUSPEND_REJECT, i, Q931ProcSuspendRejectNT, Q931Umes_SuspendReject, Q931Pmes_SuspendReject);
+ Q931SetMesProc(Q931mes_USER_INFORMATION, i, Q931ProcUserInformationNT, Q931Umes_UserInformation, Q931Pmes_UserInformation);
+ Q931SetMesProc(Q931mes_DISCONNECT, i, Q931ProcDisconnectNT, Q931Umes_Disconnect, Q931Pmes_Disconnect);
+ Q931SetMesProc(Q931mes_RELEASE, i, Q931ProcReleaseNT, Q931Umes_Release, Q931Pmes_Release);
+ Q931SetMesProc(Q931mes_RELEASE_COMPLETE, i, Q931ProcReleaseCompleteNT, Q931Umes_ReleaseComplete, Q931Pmes_ReleaseComplete);
+ Q931SetMesProc(Q931mes_RESTART, i, Q931ProcRestartNT, Q931Umes_Restart, Q931Pmes_Restart);
+ Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE, i, Q931ProcRestartAckNT, Q931Umes_RestartAck, Q931Pmes_RestartAck);
+ Q931SetMesProc(Q931mes_CONGESTION_CONTROL, i, Q931ProcCongestionControlNT, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+ Q931SetMesProc(Q931mes_INFORMATION, i, Q931ProcInformationNT, Q931Umes_Information, Q931Pmes_Information);
+ Q931SetMesProc(Q931mes_NOTIFY, i, Q931ProcNotifyNT, Q931Umes_Notify, Q931Pmes_Notify);
+ Q931SetMesProc(Q931mes_STATUS, i, Q931ProcStatusNT, Q931Umes_Status, Q931Pmes_Status);
+ Q931SetMesProc(Q931mes_STATUS_ENQUIRY, i, Q931ProcStatusEnquiryNT, Q931Umes_StatusEnquiry, Q931Pmes_StatusEnquiry);
+ Q931SetMesProc(Q931mes_SEGMENT, i, Q931ProcSegmentNT, Q931Umes_Segment, Q931Pmes_Segment);
+
+ Q931SetMesProc(Q932mes_FACILITY, i, Q932ProcFacilityNT, Q932Umes_Facility, Q932Pmes_Facility);
+ Q931SetMesProc(Q932mes_HOLD, i, Q932ProcHoldNT, Q932Umes_Hold, Q932Pmes_Hold);
+ Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE, i, Q932ProcHoldAckNT, Q932Umes_HoldAck, Q932Pmes_HoldAck);
+ Q931SetMesProc(Q932mes_HOLD_REJECT, i, Q932ProcHoldRejectNT, Q932Umes_HoldReject, Q932Pmes_HoldReject);
+ Q931SetMesProc(Q932mes_REGISTER, i, Q932ProcRegisterNT, Q932Umes_Register, Q932Pmes_Register);
+ Q931SetMesProc(Q932mes_RETRIEVE, i, Q932ProcRetrieveNT, Q932Umes_Retrieve, Q932Pmes_Retrieve);
+ Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckNT, Q932Umes_RetrieveAck, Q932Pmes_RetrieveAck);
+ Q931SetMesProc(Q932mes_RETRIEVE_REJECT, i, Q932ProcRetrieveRejectNT, Q932Umes_RetrieveReject, Q932Pmes_RetrieveReject);
+
+ /* Set up the IE encoder/decoder handle table.*/
+ Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE, i, Q931Pie_Segment, Q931Uie_Segment);
+ Q931SetIEProc(Q931ie_BEARER_CAPABILITY, i, Q931Pie_BearerCap, Q931Uie_BearerCap);
+ Q931SetIEProc(Q931ie_CAUSE, i, Q931Pie_Cause, Q931Uie_Cause);
+ Q931SetIEProc(Q931ie_CALL_IDENTITY, i, Q931Pie_CallID, Q931Uie_CallID);
+ Q931SetIEProc(Q931ie_CALL_STATE, i, Q931Pie_CallState, Q931Uie_CallState);
+ Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION, i, Q931Pie_ChanID, Q931Uie_ChanID);
+ Q931SetIEProc(Q931ie_PROGRESS_INDICATOR, i, Q931Pie_ProgInd, Q931Uie_ProgInd);
+ Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES, i, Q931Pie_NetFac, Q931Uie_NetFac);
+ Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR, i, Q931Pie_NotifInd, Q931Uie_NotifInd);
+ Q931SetIEProc(Q931ie_DISPLAY, i, Q931Pie_Display, Q931Uie_Display);
+ Q931SetIEProc(Q931ie_DATETIME, i, Q931Pie_DateTime, Q931Uie_DateTime);
+ Q931SetIEProc(Q931ie_KEYPAD_FACILITY, i, Q931Pie_KeypadFac, Q931Uie_KeypadFac);
+ Q931SetIEProc(Q931ie_SIGNAL, i, Q931Pie_Signal, Q931Uie_Signal);
+ Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER, i, Q931Pie_CallingNum, Q931Uie_CallingNum);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS, i, Q931Pie_CallingSub, Q931Uie_CallingSub);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER, i, Q931Pie_CalledNum, Q931Uie_CalledNum);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS, i, Q931Pie_CalledSub, Q931Uie_CalledSub);
+ Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_RESTART_INDICATOR, i, Q931Pie_RestartInd, Q931Uie_RestartInd);
+ Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY, i, Q931Pie_LLComp, Q931Uie_LLComp);
+ Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY, i, Q931Pie_HLComp, Q931Uie_HLComp);
+ Q931SetIEProc(Q931ie_USER_USER, i, Q931Pie_UserUser, Q931Uie_UserUser);
+ Q931SetIEProc(Q931ie_GENERIC_DIGITS, i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+ Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_FACILITY, i, Q931Pie_Generic, Q931Uie_Generic);
+
+ /* The following define a state machine. The point is that the Message */
+ /* procs can when search this to find out if the message/state */
+ /* combination is legale. If not, the proc for unexpected message apply.*/
+
+ /* TODO define state table here */
+}
Added: freeswitch/trunk/libs/openzap/src/isdn/5ESSStateTE.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/5ESSStateTE.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/5ESSStateTE.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,291 @@
+/*****************************************************************************
+
+ FileName: 5ESSStateTE.c
+
+ Contents: AT&T 5ESS ISDN State Engine for TE (User Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ This reference implementation uses a process per message,
+ meaning that each message must check call states. This
+ is easier for dialect maintenance as each message proc
+ can be replaced individually. A new TE variant only
+ need to copy the Q931CreateTE and replace those procs or
+ need to override.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ Copyright (c) 2007, Michael S. Collins, All rights reserved.
+ email:mcollins@fcnetwork.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "5ESS.h"
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+ Function: ATT5ESSCreateTE
+
+ Description: Will create the AT&T 5ESS TE as a Dialect in the stack. The first
+ bulk set up the message handlers, the second bulk the IE
+ encoders/coders, and the last bulk set up the state table.
+
+ Parameters: i Dialect index
+*****************************************************************************/
+void ATT5ESSCreateTE(L3UCHAR i)
+{
+ Q931SetMesProc(Q931mes_ALERTING, i, Q931ProcAlertingTE, Q931Umes_Alerting, Q931Pmes_Alerting);
+ Q931SetMesProc(Q931mes_CALL_PROCEEDING, i, Q931ProcCallProceedingTE, Q931Umes_CallProceeding, Q931Pmes_CallProceeding);
+ Q931SetMesProc(Q931mes_CONNECT, i, ATT5ESSProc0x07TE, ATT5ESSUmes_0x07, ATT5ESSPmes_0x07);
+ Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i, ATT5ESSProc0x0fTE, ATT5ESSUmes_0x0f, ATT5ESSPmes_0x0f);
+ Q931SetMesProc(Q931mes_PROGRESS, i, Q931ProcProgressTE, Q931Umes_Progress, Q931Pmes_Progress);
+ Q931SetMesProc(Q931mes_SETUP, i, Q931ProcSetupTE, ATT5ESSUmes_Setup, ATT5ESSPmes_Setup);
+ Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE, i, Q931ProcSetupAckTE, Q931Umes_SetupAck, Q931Pmes_SetupAck);
+ Q931SetMesProc(Q931mes_RESUME, i, Q931ProcResumeTE, Q931Umes_Resume, Q931Pmes_Resume);
+ Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE, i, Q931ProcResumeAckTE, Q931Umes_ResumeAck, Q931Pmes_ResumeAck);
+ Q931SetMesProc(Q931mes_RESUME_REJECT, i, Q931ProcResumeRejectTE, Q931Umes_ResumeReject, Q931Pmes_ResumeReject);
+ Q931SetMesProc(Q931mes_SUSPEND, i, Q931ProcSuspendTE, Q931Umes_Suspend, Q931Pmes_Suspend);
+ Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE, i, Q931ProcSuspendAckTE, Q931Umes_SuspendAck, Q931Pmes_SuspendAck);
+ Q931SetMesProc(Q931mes_SUSPEND_REJECT, i, Q931ProcSuspendRejectTE, Q931Umes_SuspendReject, Q931Pmes_SuspendReject);
+ Q931SetMesProc(Q931mes_USER_INFORMATION, i, Q931ProcUserInformationTE, Q931Umes_UserInformation, Q931Pmes_UserInformation);
+ Q931SetMesProc(Q931mes_DISCONNECT, i, Q931ProcDisconnectTE, Q931Umes_Disconnect, Q931Pmes_Disconnect);
+ Q931SetMesProc(Q931mes_RELEASE, i, Q931ProcReleaseTE, Q931Umes_Release, Q931Pmes_Release);
+ Q931SetMesProc(Q931mes_RELEASE_COMPLETE, i, Q931ProcReleaseCompleteTE, Q931Umes_ReleaseComplete, Q931Pmes_ReleaseComplete);
+ Q931SetMesProc(Q931mes_RESTART, i, Q931ProcRestartTE, Q931Umes_Restart, Q931Pmes_Restart);
+ Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE, i, Q931ProcRestartAckTE, Q931Umes_RestartAck, Q931Pmes_RestartAck);
+ Q931SetMesProc(Q931mes_CONGESTION_CONTROL, i, Q931ProcCongestionControlTE, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+ Q931SetMesProc(Q931mes_INFORMATION, i, Q931ProcInformationTE, Q931Umes_Information, Q931Pmes_Information);
+ Q931SetMesProc(Q931mes_NOTIFY, i, Q931ProcNotifyTE, Q931Umes_Notify, Q931Pmes_Notify);
+ Q931SetMesProc(Q931mes_STATUS, i, Q931ProcStatusTE, Q931Umes_Status, Q931Pmes_Status);
+ Q931SetMesProc(Q931mes_STATUS_ENQUIRY, i, Q931ProcStatusEnquiryTE, Q931Umes_StatusEnquiry, Q931Pmes_StatusEnquiry);
+ Q931SetMesProc(Q931mes_SEGMENT, i, Q931ProcSegmentTE, Q931Umes_Segment, Q931Pmes_Segment);
+
+ Q931SetMesProc(Q932mes_FACILITY, i, Q932ProcFacilityTE, Q932Umes_Facility, Q932Pmes_Facility);
+ Q931SetMesProc(Q932mes_HOLD, i, Q932ProcHoldTE, Q932Umes_Hold, Q932Pmes_Hold);
+ Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE, i, Q932ProcHoldAckTE, Q932Umes_HoldAck, Q932Pmes_HoldAck);
+ Q931SetMesProc(Q932mes_HOLD_REJECT, i, Q932ProcHoldRejectTE, Q932Umes_HoldReject, Q932Pmes_HoldReject);
+ Q931SetMesProc(Q932mes_REGISTER, i, Q932ProcRegisterTE, Q932Umes_Register, Q932Pmes_Register);
+ Q931SetMesProc(Q932mes_RETRIEVE, i, Q932ProcRetrieveTE, Q932Umes_Retrieve, Q932Pmes_Retrieve);
+ Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckTE, Q932Umes_RetrieveAck, Q932Pmes_RetrieveAck);
+ Q931SetMesProc(Q932mes_RETRIEVE_REJECT, i, Q932ProcRetrieveRejectTE, Q932Umes_RetrieveReject, Q932Pmes_RetrieveReject);
+
+ /* Set up the IE encoder/decoder handle table.*/
+ Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE, i, Q931Pie_Segment, Q931Uie_Segment);
+ Q931SetIEProc(Q931ie_BEARER_CAPABILITY, i, Q931Pie_BearerCap, Q931Uie_BearerCap);
+ Q931SetIEProc(Q931ie_CAUSE, i, Q931Pie_Cause, Q931Uie_Cause);
+ Q931SetIEProc(Q931ie_CALL_IDENTITY, i, Q931Pie_CallID, Q931Uie_CallID);
+ Q931SetIEProc(Q931ie_CALL_STATE, i, Q931Pie_CallState, Q931Uie_CallState);
+ Q931SetIEProc(Q931ie_CHANGE_STATUS, i, Q931Pie_ChangeStatus, Q931Uie_ChangeStatus);
+ Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION, i, Q931Pie_ChanID, Q931Uie_ChanID);
+ Q931SetIEProc(Q931ie_PROGRESS_INDICATOR, i, Q931Pie_ProgInd, Q931Uie_ProgInd);
+ Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES, i, Q931Pie_NetFac, Q931Uie_NetFac);
+ Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR, i, Q931Pie_NotifInd, Q931Uie_NotifInd);
+ Q931SetIEProc(Q931ie_DISPLAY, i, Q931Pie_Display, Q931Uie_Display);
+ Q931SetIEProc(Q931ie_DATETIME, i, Q931Pie_DateTime, Q931Uie_DateTime);
+ Q931SetIEProc(Q931ie_KEYPAD_FACILITY, i, Q931Pie_KeypadFac, Q931Uie_KeypadFac);
+ Q931SetIEProc(Q931ie_SIGNAL, i, Q931Pie_Signal, Q931Uie_Signal);
+ Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER, i, Q931Pie_CallingNum, Q931Uie_CallingNum);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS, i, Q931Pie_CallingSub, Q931Uie_CallingSub);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER, i, Q931Pie_CalledNum, Q931Uie_CalledNum);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS, i, Q931Pie_CalledSub, Q931Uie_CalledSub);
+ Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_RESTART_INDICATOR, i, Q931Pie_RestartInd, Q931Uie_RestartInd);
+ Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY, i, Q931Pie_LLComp, Q931Uie_LLComp);
+ Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY, i, Q931Pie_HLComp, Q931Uie_HLComp);
+ Q931SetIEProc(Q931ie_USER_USER, i, Q931Pie_UserUser, Q931Uie_UserUser);
+ Q931SetIEProc(Q931ie_GENERIC_DIGITS, i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+ Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_FACILITY, i, Q931Pie_Generic, Q931Uie_Generic);
+
+ /* The following define a state machine. The point is that the Message */
+ /* procs can when search this to find out if the message/state */
+ /* combination is legale. If not, the proc for unexpected message apply.*/
+
+ /* State 0 Idle */
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RESUME, 2);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP, 2);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_STATUS, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE_COMPLETE, 4);
+
+ /* State 1 Call Initiating */
+ Q931AddStateEntry(i, Q931_U1, Q931mes_DISCONNECT, 2);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_SETUP_ACKNOWLEDGE, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_RELEASE_COMPLETE, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_CALL_PROCEEDING, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_CONNECT, 4);
+
+ /* State 2 Overlap Sending */
+ Q931AddStateEntry(i, Q931_U2, Q931mes_INFORMATION, 2);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_CALL_PROCEEDING, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_PROGRESS, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_CONNECT, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_RELEASE, 2);
+
+ /* State 3 Outgoing Call Proceeding */
+ Q931AddStateEntry(i, Q931_U3, Q931mes_PROGRESS, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_CONNECT, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_RELEASE, 2);
+
+ /* State 4 Call Delivered */
+ Q931AddStateEntry(i, Q931_U4, Q931mes_CONNECT, 4);
+
+ /* State 6 Call Precent */
+ Q931AddStateEntry(i, Q931_U6, Q931mes_INFORMATION, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_ALERTING, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_CALL_PROCEEDING, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_CONNECT, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE_COMPLETE, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_DISCONNECT, 4);
+
+ /* State 7 Call Received */
+ Q931AddStateEntry(i, Q931_U7, Q931mes_CONNECT, 2);
+
+ /* State 8 Connect request */
+ Q931AddStateEntry(i, Q931_U8, Q931mes_CONNECT_ACKNOWLEDGE, 4);
+
+ /* State 9 Incoming Call Proceeding */
+ Q931AddStateEntry(i, Q931_U9, Q931mes_CONNECT, 2);
+ Q931AddStateEntry(i, Q931_U9, Q931mes_ALERTING, 2);
+ Q931AddStateEntry(i, Q931_U9, Q931mes_PROGRESS, 2);
+
+ /* State 10 Active */
+ Q931AddStateEntry(i, Q931_U10, Q931mes_SUSPEND, 2);
+ Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY, 4);
+ Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY, 2);
+
+ /* State 11 Disconnect Request */
+ Q931AddStateEntry(i, Q931_U11, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U11, Q931mes_DISCONNECT, 4);
+ Q931AddStateEntry(i, Q931_U11, Q931mes_NOTIFY, 4);
+
+ /* State 12 Disconnect Ind */
+ Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 2);
+
+ /* State 15 Suspend Request */
+ Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_ACKNOWLEDGE, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_REJECT, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_DISCONNECT, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_RELEASE, 4);
+
+/* TODO
+ Q931AddStateEntry(i, Q931_U17,
+ Q931AddStateEntry(i, Q931_U19,
+ Q931AddStateEntry(i, Q931_U25,
+*/
+}
+
+/*****************************************************************************
+
+ Function: ATT5ESSProc0x0fTE
+
+*****************************************************************************/
+L3INT ATT5ESSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ if (pMes->ProtDisc == 8) {
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ }
+ if (iFrom == 4) {
+ /* TODO Add proc here*/
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom ==2) {
+ /* TODO Add proc here*/
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+
+ if (pMes->ProtDisc == 3 && pTrunk->autoServiceAck) {
+ printf("autoServiceAck is on, responding to Service Req from network...\n");
+ Q931AckService(pTrunk, buf);
+ }
+ }
+ return ret;
+
+}
+
+/*****************************************************************************
+
+ Function: ATT5ESSProc0x07TE
+
+*****************************************************************************/
+L3INT ATT5ESSProc0x07TE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ if (pMes->ProtDisc == 8) {
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ }
+ if (iFrom == 4) {
+ /* TODO Add proc here*/
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here*/
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+
+}
Added: freeswitch/trunk/libs/openzap/src/isdn/5ESSmes.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/5ESSmes.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/5ESSmes.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,361 @@
+/*****************************************************************************
+
+ FileName: 5ESSmes.c
+
+ Contents: Pack/Unpack functions. These functions will unpack a 5ESS ISDN
+ message from the bit packed original format into structs
+ that contains variables sized by the user. It will also pack
+ the struct back into a Q.931 message as required.
+
+ See 5ESS.h for description.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ Copyright (c) 2007, Michael S. Collins, All rights reserved.
+ email:mcollins@fcnetwork.com
+
+ 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 Case Labs, Ltd 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.
+
+*****************************************************************************/
+
+#include "5ESS.h"
+
+/*****************************************************************************
+
+ Function: ATT5ESSUmes_Setup
+
+*****************************************************************************/
+L3INT ATT5ESSUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT ir = 0;
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+ L3UCHAR last_codeset = 0, codeset = 0;
+ L3UCHAR shift_nolock = 1;
+
+ while (IOff < Size) {
+
+ if (shift_nolock) {
+ codeset = last_codeset;
+ }
+
+ if ((IBuf[IOff] & 0xF0) == Q931ie_SHIFT) {
+ shift_nolock = (IBuf[IOff] & 0x08);
+ if (shift_nolock) {
+ last_codeset = codeset;
+ }
+ codeset = ((IBuf[IOff] & 0x07));
+ IOff++;
+ }
+
+ if (codeset == 0) {
+ switch (IBuf[IOff])
+ {
+ case Q931ie_SENDING_COMPLETE:
+ case Q931ie_BEARER_CAPABILITY:
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_NETWORK_SPECIFIC_FACILITIES:
+ case Q931ie_DISPLAY:
+ case Q931ie_DATETIME:
+ case Q931ie_KEYPAD_FACILITY:
+ case Q931ie_SIGNAL:
+ case Q931ie_CALLING_PARTY_NUMBER:
+ case Q931ie_CALLING_PARTY_SUBADDRESS:
+ case Q931ie_CALLED_PARTY_NUMBER:
+ case Q931ie_CALLED_PARTY_SUBADDRESS:
+ case Q931ie_TRANSIT_NETWORK_SELECTION:
+ case Q931ie_LOW_LAYER_COMPATIBILITY:
+ case Q931ie_HIGH_LAYER_COMPATIBILITY:
+ case Q931ie_FACILITY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ case Q931ie_REPEAT_INDICATOR:
+ if (ir < 2) {
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ ir++;
+ } else {
+ return Q931E_ILLEGAL_IE;
+ }
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ } else if (codeset == 6) {
+ switch (IBuf[IOff])
+ {
+ case Q931ie_GENERIC_DIGITS:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ } else if (codeset == 7) {
+ switch (IBuf[IOff])
+ {
+ case Q931ie_DISPLAY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ } else {
+ return Q931E_ILLEGAL_IE;
+ }
+ }
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: ATT5ESSPmes_Setup
+
+ Decription: Pack a Q931mes_Generic into a real Q.931 message. The user will
+ set up a SETUP message and issue this to the stack where it
+ is processed by Q931ProcSetup that processes and validates
+ it before it actually sends it out. This function is called
+ to compute the real Q.931 message.
+
+ Parameters: IBuf[IN] Ptr to un-packed struct
+ ISize[IN] Size of input buffer (unpacked message).
+ OBuf[OUT] Ptr to packed 'octet' wise message.
+ OSize[OUT] Size of packed message.
+
+ Called By: Q931ProcSetup
+
+*****************************************************************************/
+L3INT ATT5ESSPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3INT rc = Q931E_NO_ERROR;
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Sending Complete */
+ if (Q931IsIEPresent(pMes->SendComplete)) {
+ OBuf[Octet++] = (L3UCHAR)(pMes->SendComplete & 0x00ff);
+ }
+
+ /* Repeat Indicator */
+ if (Q931IsIEPresent(pMes->RepeatInd)) {
+ OBuf[Octet++] = (L3UCHAR)(pMes->RepeatInd & 0x00ff);
+ }
+
+ /* Bearer capability */
+ if (Q931IsIEPresent(pMes->BearerCap)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ } else {
+ rc = Q931E_BEARERCAP;
+ }
+
+ /* Channel Identification */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Network specific facilities */
+ if (Q931IsIEPresent(pMes->NetFac)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_NETWORK_SPECIFIC_FACILITIES](pTrunk, Q931GetIEPtr(pMes->NetFac,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Date/Time */
+ if (Q931IsIEPresent(pMes->DateTime)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Keypad Facility */
+ if (Q931IsIEPresent(pMes->KeypadFac)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Calling Party Number */
+ if (Q931IsIEPresent(pMes->CallingNum)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CallingNum,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Calling Party Subaddress */
+ if (Q931IsIEPresent(pMes->CallingSub)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CallingSub,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Called Party number */
+ if (Q931IsIEPresent(pMes->CalledNum)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Called party subaddress */
+ if (Q931IsIEPresent(pMes->CalledSub)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CalledSub,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Transit network selection */
+ if (Q931IsIEPresent(pMes->TransNetSel)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_TRANSIT_NETWORK_SELECTION](pTrunk, Q931GetIEPtr(pMes->TransNetSel,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* Repeat Indicator */
+ if (Q931IsIEPresent(pMes->LLRepeatInd)) {
+ rc = Q931E_UNKNOWN_IE;/* TODO */
+ }
+
+ /* Low Layer Compatibility */
+ if (Q931IsIEPresent(pMes->LLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ /* High Layer Compatibility */
+ if (Q931IsIEPresent(pMes->HLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet))!=0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+
+/*****************************************************************************
+
+ Function: ATT5ESSUmes_0x0f
+
+*****************************************************************************/
+L3INT ATT5ESSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ if (mes->ProtDisc == 8) {
+ return Q931Umes_ConnectAck(pTrunk, IBuf, mes, IOff, Size);
+ }
+
+ if (mes->ProtDisc == 3) {
+ return Q931Umes_Service(pTrunk, IBuf, mes, IOff, Size);
+ }
+
+ return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+ Function: ATT5ESSPmes_0x0f
+
+*****************************************************************************/
+L3INT ATT5ESSPmes_0x0f(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *mes = (Q931mes_Generic *)IBuf;
+
+ if (mes->ProtDisc == 8) {
+ return Q931Pmes_ConnectAck(pTrunk, IBuf, ISize, OBuf, OSize);
+ }
+
+ if (mes->ProtDisc == 3) {
+ return Q931Pmes_Service(pTrunk, IBuf, ISize, OBuf, OSize);
+ }
+
+ return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+ Function: ATT5ESSUmes_0x07
+
+*****************************************************************************/
+L3INT ATT5ESSUmes_0x07(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ if (mes->ProtDisc == 8) {
+ return Q931Umes_Connect(pTrunk, IBuf, mes, IOff, Size);
+ }
+
+ if (mes->ProtDisc == 3) {
+ return Q931Umes_ServiceAck(pTrunk, IBuf, mes, IOff, Size);
+ }
+
+ return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+ Function: ATT5ESSPmes_0x07
+
+*****************************************************************************/
+L3INT ATT5ESSPmes_0x07(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *mes = (Q931mes_Generic *)IBuf;
+
+ if (mes->ProtDisc == 8) {
+ return Q931Pmes_Connect(pTrunk, IBuf, ISize, OBuf, OSize);
+ }
+
+ if (mes->ProtDisc == 3) {
+ return Q931Pmes_ServiceAck(pTrunk, IBuf, ISize, OBuf, OSize);
+ }
+
+ return Q931E_UNKNOWN_MESSAGE;
+}
Added: freeswitch/trunk/libs/openzap/src/isdn/DMSStateNT.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/DMSStateNT.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/DMSStateNT.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,126 @@
+/*****************************************************************************
+
+ FileName: DMSStateNT.c
+
+ Contents: DMS-100 ISDN State Engine for NT (Network Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "DMS.h"
+
+/*****************************************************************************
+ Function: DMSCreateNT
+
+ Description: Will create the National ISDN NT as a Dialect in the stack. The first
+ bulk set up the message handlers, the second bulk the IE
+ encoders/coders, and the last bulk set up the state table.
+
+ Parameters: i Dialect index
+*****************************************************************************/
+void DMSCreateNT(L3UCHAR i)
+{
+ Q931SetMesProc(Q931mes_ALERTING, i, Q931ProcAlertingNT, Q931Umes_Alerting, Q931Pmes_Alerting);
+ Q931SetMesProc(Q931mes_CALL_PROCEEDING, i, Q931ProcCallProceedingNT, Q931Umes_CallProceeding, Q931Pmes_CallProceeding);
+ Q931SetMesProc(Q931mes_CONNECT, i, Q931ProcConnectNT, Q931Umes_Connect, Q931Pmes_Connect);
+ Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i, Q931ProcConnectAckNT, Q931Umes_ConnectAck, Q931Pmes_ConnectAck);
+ Q931SetMesProc(Q931mes_PROGRESS, i, Q931ProcProgressNT, Q931Umes_Progress, Q931Pmes_Progress);
+ Q931SetMesProc(Q931mes_SETUP, i, Q931ProcSetupNT, DMSUmes_Setup, DMSPmes_Setup);
+ Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE, i, Q931ProcSetupAckNT, Q931Umes_SetupAck, Q931Pmes_SetupAck);
+ Q931SetMesProc(Q931mes_RESUME, i, Q931ProcResumeNT, Q931Umes_Resume, Q931Pmes_Resume);
+ Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE, i, Q931ProcResumeAckNT, Q931Umes_ResumeAck, Q931Pmes_ResumeAck);
+ Q931SetMesProc(Q931mes_RESUME_REJECT, i, Q931ProcResumeRejectNT, Q931Umes_ResumeReject, Q931Pmes_ResumeReject);
+ Q931SetMesProc(Q931mes_SUSPEND, i, Q931ProcSuspendNT, Q931Umes_Suspend, Q931Pmes_Suspend);
+ Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE, i, Q931ProcSuspendAckNT, Q931Umes_SuspendAck, Q931Pmes_SuspendAck);
+ Q931SetMesProc(Q931mes_SUSPEND_REJECT, i, Q931ProcSuspendRejectNT, Q931Umes_SuspendReject, Q931Pmes_SuspendReject);
+ Q931SetMesProc(Q931mes_USER_INFORMATION, i, Q931ProcUserInformationNT, Q931Umes_UserInformation, Q931Pmes_UserInformation);
+ Q931SetMesProc(Q931mes_DISCONNECT, i, Q931ProcDisconnectNT, Q931Umes_Disconnect, Q931Pmes_Disconnect);
+ Q931SetMesProc(Q931mes_RELEASE, i, Q931ProcReleaseNT, Q931Umes_Release, Q931Pmes_Release);
+ Q931SetMesProc(Q931mes_RELEASE_COMPLETE, i, Q931ProcReleaseCompleteNT, Q931Umes_ReleaseComplete, Q931Pmes_ReleaseComplete);
+ Q931SetMesProc(Q931mes_RESTART, i, Q931ProcRestartNT, Q931Umes_Restart, Q931Pmes_Restart);
+ Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE, i, Q931ProcRestartAckNT, Q931Umes_RestartAck, Q931Pmes_RestartAck);
+ Q931SetMesProc(Q931mes_CONGESTION_CONTROL, i, Q931ProcCongestionControlNT, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+ Q931SetMesProc(Q931mes_INFORMATION, i, Q931ProcInformationNT, Q931Umes_Information, Q931Pmes_Information);
+ Q931SetMesProc(Q931mes_NOTIFY, i, Q931ProcNotifyNT, Q931Umes_Notify, Q931Pmes_Notify);
+ Q931SetMesProc(Q931mes_STATUS, i, Q931ProcStatusNT, Q931Umes_Status, Q931Pmes_Status);
+ Q931SetMesProc(Q931mes_STATUS_ENQUIRY, i, Q931ProcStatusEnquiryNT, Q931Umes_StatusEnquiry, Q931Pmes_StatusEnquiry);
+ Q931SetMesProc(Q931mes_SEGMENT, i, Q931ProcSegmentNT, Q931Umes_Segment, Q931Pmes_Segment);
+
+ Q931SetMesProc(Q932mes_FACILITY, i, Q932ProcFacilityNT, Q932Umes_Facility, Q932Pmes_Facility);
+ Q931SetMesProc(Q932mes_HOLD, i, Q932ProcHoldNT, Q932Umes_Hold, Q932Pmes_Hold);
+ Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE, i, Q932ProcHoldAckNT, Q932Umes_HoldAck, Q932Pmes_HoldAck);
+ Q931SetMesProc(Q932mes_HOLD_REJECT, i, Q932ProcHoldRejectNT, Q932Umes_HoldReject, Q932Pmes_HoldReject);
+ Q931SetMesProc(Q932mes_REGISTER, i, Q932ProcRegisterNT, Q932Umes_Register, Q932Pmes_Register);
+ Q931SetMesProc(Q932mes_RETRIEVE, i, Q932ProcRetrieveNT, Q932Umes_Retrieve, Q932Pmes_Retrieve);
+ Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckNT, Q932Umes_RetrieveAck, Q932Pmes_RetrieveAck);
+ Q931SetMesProc(Q932mes_RETRIEVE_REJECT, i, Q932ProcRetrieveRejectNT, Q932Umes_RetrieveReject, Q932Pmes_RetrieveReject);
+
+ /* Set up the IE encoder/decoder handle table.*/
+ Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE, i, Q931Pie_Segment, Q931Uie_Segment);
+ Q931SetIEProc(Q931ie_BEARER_CAPABILITY, i, Q931Pie_BearerCap, Q931Uie_BearerCap);
+ Q931SetIEProc(Q931ie_CAUSE, i, Q931Pie_Cause, Q931Uie_Cause);
+ Q931SetIEProc(Q931ie_CALL_IDENTITY, i, Q931Pie_CallID, Q931Uie_CallID);
+ Q931SetIEProc(Q931ie_CALL_STATE, i, Q931Pie_CallState, Q931Uie_CallState);
+ Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION, i, Q931Pie_ChanID, Q931Uie_ChanID);
+ Q931SetIEProc(Q931ie_PROGRESS_INDICATOR, i, Q931Pie_ProgInd, Q931Uie_ProgInd);
+ Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES, i, Q931Pie_NetFac, Q931Uie_NetFac);
+ Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR, i, Q931Pie_NotifInd, Q931Uie_NotifInd);
+ Q931SetIEProc(Q931ie_DISPLAY, i, Q931Pie_Display, Q931Uie_Display);
+ Q931SetIEProc(Q931ie_DATETIME, i, Q931Pie_DateTime, Q931Uie_DateTime);
+ Q931SetIEProc(Q931ie_KEYPAD_FACILITY, i, Q931Pie_KeypadFac, Q931Uie_KeypadFac);
+ Q931SetIEProc(Q931ie_SIGNAL, i, Q931Pie_Signal, Q931Uie_Signal);
+ Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER, i, Q931Pie_CallingNum, Q931Uie_CallingNum);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS, i, Q931Pie_CallingSub, Q931Uie_CallingSub);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER, i, Q931Pie_CalledNum, Q931Uie_CalledNum);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS, i, Q931Pie_CalledSub, Q931Uie_CalledSub);
+ Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_RESTART_INDICATOR, i, Q931Pie_RestartInd, Q931Uie_RestartInd);
+ Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY, i, Q931Pie_LLComp, Q931Uie_LLComp);
+ Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY, i, Q931Pie_HLComp, Q931Uie_HLComp);
+ Q931SetIEProc(Q931ie_USER_USER, i, Q931Pie_UserUser, Q931Uie_UserUser);
+ Q931SetIEProc(Q931ie_GENERIC_DIGITS, i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+ /* The following define a state machine. The point is that the Message */
+ /* procs can when search this to find out if the message/state */
+ /* combination is legale. If not, the proc for unexpected message apply.*/
+
+ /* TODO define state table here */
+}
Added: freeswitch/trunk/libs/openzap/src/isdn/DMSStateTE.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/DMSStateTE.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/DMSStateTE.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,284 @@
+/*****************************************************************************
+
+ FileName: DMSStateTE.c
+
+ Contents: DMS-100 ISDN State Engine for TE (User Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ This reference implementation uses a process per message,
+ meaning that each message must check call states. This
+ is easier for dialect maintenance as each message proc
+ can be replaced individually. A new TE variant only
+ need to copy the Q931CreateTE and replace those procs or
+ need to override.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "DMS.h"
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+ Function: DMSCreateTE
+
+ Description: Will create the National TE as a Dialect in the stack. The first
+ bulk set up the message handlers, the second bulk the IE
+ encoders/coders, and the last bulk set up the state table.
+
+ Parameters: i Dialect index
+*****************************************************************************/
+void DMSCreateTE(L3UCHAR i)
+{
+ Q931SetMesProc(Q931mes_ALERTING, i, Q931ProcAlertingTE, Q931Umes_Alerting, Q931Pmes_Alerting);
+ Q931SetMesProc(Q931mes_CALL_PROCEEDING, i, Q931ProcCallProceedingTE, Q931Umes_CallProceeding, Q931Pmes_CallProceeding);
+ Q931SetMesProc(Q931mes_CONNECT, i, DMSProc0x07TE, DMSUmes_0x07, DMSPmes_0x07);
+ Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i, DMSProc0x0fTE, DMSUmes_0x0f, DMSPmes_0x0f);
+ Q931SetMesProc(Q931mes_PROGRESS, i, Q931ProcProgressTE, Q931Umes_Progress, Q931Pmes_Progress);
+ Q931SetMesProc(Q931mes_SETUP, i, Q931ProcSetupTE, DMSUmes_Setup, DMSPmes_Setup);
+ Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE, i, Q931ProcSetupAckTE, Q931Umes_SetupAck, Q931Pmes_SetupAck);
+ Q931SetMesProc(Q931mes_RESUME, i, Q931ProcResumeTE, Q931Umes_Resume, Q931Pmes_Resume);
+ Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE, i, Q931ProcResumeAckTE, Q931Umes_ResumeAck, Q931Pmes_ResumeAck);
+ Q931SetMesProc(Q931mes_RESUME_REJECT, i, Q931ProcResumeRejectTE, Q931Umes_ResumeReject, Q931Pmes_ResumeReject);
+ Q931SetMesProc(Q931mes_SUSPEND, i, Q931ProcSuspendTE, Q931Umes_Suspend, Q931Pmes_Suspend);
+ Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE, i, Q931ProcSuspendAckTE, Q931Umes_SuspendAck, Q931Pmes_SuspendAck);
+ Q931SetMesProc(Q931mes_SUSPEND_REJECT, i, Q931ProcSuspendRejectTE, Q931Umes_SuspendReject, Q931Pmes_SuspendReject);
+ Q931SetMesProc(Q931mes_USER_INFORMATION, i, Q931ProcUserInformationTE, Q931Umes_UserInformation, Q931Pmes_UserInformation);
+ Q931SetMesProc(Q931mes_DISCONNECT, i, Q931ProcDisconnectTE, Q931Umes_Disconnect, Q931Pmes_Disconnect);
+ Q931SetMesProc(Q931mes_RELEASE, i, Q931ProcReleaseTE, Q931Umes_Release, Q931Pmes_Release);
+ Q931SetMesProc(Q931mes_RELEASE_COMPLETE, i, Q931ProcReleaseCompleteTE, Q931Umes_ReleaseComplete, Q931Pmes_ReleaseComplete);
+ Q931SetMesProc(Q931mes_RESTART, i, Q931ProcRestartTE, Q931Umes_Restart, Q931Pmes_Restart);
+ Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE, i, Q931ProcRestartAckTE, Q931Umes_RestartAck, Q931Pmes_RestartAck);
+ Q931SetMesProc(Q931mes_CONGESTION_CONTROL, i, Q931ProcCongestionControlTE, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+ Q931SetMesProc(Q931mes_INFORMATION, i, Q931ProcInformationTE, Q931Umes_Information, Q931Pmes_Information);
+ Q931SetMesProc(Q931mes_NOTIFY, i, Q931ProcNotifyTE, Q931Umes_Notify, Q931Pmes_Notify);
+ Q931SetMesProc(Q931mes_STATUS, i, Q931ProcStatusTE, Q931Umes_Status, Q931Pmes_Status);
+ Q931SetMesProc(Q931mes_STATUS_ENQUIRY, i, Q931ProcStatusEnquiryTE, Q931Umes_StatusEnquiry, Q931Pmes_StatusEnquiry);
+ Q931SetMesProc(Q931mes_SEGMENT, i, Q931ProcSegmentTE, Q931Umes_Segment, Q931Pmes_Segment);
+
+ Q931SetMesProc(Q932mes_FACILITY, i, Q932ProcFacilityTE, Q932Umes_Facility, Q932Pmes_Facility);
+ Q931SetMesProc(Q932mes_HOLD, i, Q932ProcHoldTE, Q932Umes_Hold, Q932Pmes_Hold);
+ Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE, i, Q932ProcHoldAckTE, Q932Umes_HoldAck, Q932Pmes_HoldAck);
+ Q931SetMesProc(Q932mes_HOLD_REJECT, i, Q932ProcHoldRejectTE, Q932Umes_HoldReject, Q932Pmes_HoldReject);
+ Q931SetMesProc(Q932mes_REGISTER, i, Q932ProcRegisterTE, Q932Umes_Register, Q932Pmes_Register);
+ Q931SetMesProc(Q932mes_RETRIEVE, i, Q932ProcRetrieveTE, Q932Umes_Retrieve, Q932Pmes_Retrieve);
+ Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckTE, Q932Umes_RetrieveAck, Q932Pmes_RetrieveAck);
+ Q931SetMesProc(Q932mes_RETRIEVE_REJECT, i, Q932ProcRetrieveRejectTE, Q932Umes_RetrieveReject, Q932Pmes_RetrieveReject);
+
+ /* Set up the IE encoder/decoder handle table.*/
+ Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE, i, Q931Pie_Segment, Q931Uie_Segment);
+ Q931SetIEProc(Q931ie_BEARER_CAPABILITY, i, Q931Pie_BearerCap, Q931Uie_BearerCap);
+ Q931SetIEProc(Q931ie_CAUSE, i, Q931Pie_Cause, Q931Uie_Cause);
+ Q931SetIEProc(Q931ie_CALL_IDENTITY, i, Q931Pie_CallID, Q931Uie_CallID);
+ Q931SetIEProc(Q931ie_CALL_STATE, i, Q931Pie_CallState, Q931Uie_CallState);
+ Q931SetIEProc(Q931ie_CHANGE_STATUS, i, Q931Pie_ChangeStatus, Q931Uie_ChangeStatus);
+ Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION, i, Q931Pie_ChanID, Q931Uie_ChanID);
+ Q931SetIEProc(Q931ie_PROGRESS_INDICATOR, i, Q931Pie_ProgInd, Q931Uie_ProgInd);
+ Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES, i, Q931Pie_NetFac, Q931Uie_NetFac);
+ Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR, i, Q931Pie_NotifInd, Q931Uie_NotifInd);
+ Q931SetIEProc(Q931ie_DISPLAY, i, Q931Pie_Display, Q931Uie_Display);
+ Q931SetIEProc(Q931ie_DATETIME, i, Q931Pie_DateTime, Q931Uie_DateTime);
+ Q931SetIEProc(Q931ie_KEYPAD_FACILITY, i, Q931Pie_KeypadFac, Q931Uie_KeypadFac);
+ Q931SetIEProc(Q931ie_SIGNAL, i, Q931Pie_Signal, Q931Uie_Signal);
+ Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER, i, Q931Pie_CallingNum, Q931Uie_CallingNum);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS, i, Q931Pie_CallingSub, Q931Uie_CallingSub);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER, i, Q931Pie_CalledNum, Q931Uie_CalledNum);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS, i, Q931Pie_CalledSub, Q931Uie_CalledSub);
+ Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_RESTART_INDICATOR, i, Q931Pie_RestartInd, Q931Uie_RestartInd);
+ Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY, i, Q931Pie_LLComp, Q931Uie_LLComp);
+ Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY, i, Q931Pie_HLComp, Q931Uie_HLComp);
+ Q931SetIEProc(Q931ie_USER_USER, i, Q931Pie_UserUser, Q931Uie_UserUser);
+ Q931SetIEProc(Q931ie_GENERIC_DIGITS, i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+ /* The following define a state machine. The point is that the Message */
+ /* procs can when search this to find out if the message/state */
+ /* combination is legale. If not, the proc for unexpected message apply.*/
+
+ /* State 0 Idle */
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RESUME, 2);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP, 2);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_STATUS, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE_COMPLETE, 4);
+
+ /* State 1 Call Initiating */
+ Q931AddStateEntry(i, Q931_U1, Q931mes_DISCONNECT, 2);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_SETUP_ACKNOWLEDGE, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_RELEASE_COMPLETE, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_CALL_PROCEEDING, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_CONNECT, 4);
+
+ /* State 2 Overlap Sending */
+ Q931AddStateEntry(i, Q931_U2, Q931mes_INFORMATION, 2);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_CALL_PROCEEDING, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_PROGRESS, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_CONNECT, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_RELEASE, 2);
+
+ /* State 3 Outgoing Call Proceeding */
+ Q931AddStateEntry(i, Q931_U3, Q931mes_PROGRESS, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_CONNECT, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_RELEASE, 2);
+
+ /* State 4 Call Delivered */
+ Q931AddStateEntry(i, Q931_U4, Q931mes_CONNECT, 4);
+
+ /* State 6 Call Precent */
+ Q931AddStateEntry(i, Q931_U6, Q931mes_INFORMATION, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_ALERTING, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_CALL_PROCEEDING, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_CONNECT, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE_COMPLETE, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_DISCONNECT, 4);
+
+ /* State 7 Call Received */
+ Q931AddStateEntry(i, Q931_U7, Q931mes_CONNECT, 2);
+
+ /* State 8 Connect request */
+ Q931AddStateEntry(i, Q931_U8, Q931mes_CONNECT_ACKNOWLEDGE, 4);
+
+ /* State 9 Incoming Call Proceeding */
+ Q931AddStateEntry(i, Q931_U9, Q931mes_CONNECT, 2);
+ Q931AddStateEntry(i, Q931_U9, Q931mes_ALERTING, 2);
+ Q931AddStateEntry(i, Q931_U9, Q931mes_PROGRESS, 2);
+
+ /* State 10 Active */
+ Q931AddStateEntry(i, Q931_U10, Q931mes_SUSPEND, 2);
+ Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY, 4);
+ Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY, 2);
+
+ /* State 11 Disconnect Request */
+ Q931AddStateEntry(i, Q931_U11, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U11, Q931mes_DISCONNECT, 4);
+ Q931AddStateEntry(i, Q931_U11, Q931mes_NOTIFY, 4);
+
+ /* State 12 Disconnect Ind */
+ Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 2);
+
+ /* State 15 Suspend Request */
+ Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_ACKNOWLEDGE, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_REJECT, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_DISCONNECT, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_RELEASE, 4);
+
+/* TODO
+ Q931AddStateEntry(i, Q931_U17,
+ Q931AddStateEntry(i, Q931_U19,
+ Q931AddStateEntry(i, Q931_U25,
+*/
+}
+
+/*****************************************************************************
+
+ Function: DMSProc0x0fTE
+
+*****************************************************************************/
+L3INT DMSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ if (pMes->ProtDisc == 8) {
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ }
+ if (iFrom == 4) {
+ /* TODO Add proc here*/
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here*/
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+
+ if (pMes->ProtDisc == 3 && pTrunk->autoServiceAck) {
+ Q931AckService(pTrunk, buf);
+ }
+ }
+ return ret;
+
+}
+
+/*****************************************************************************
+
+ Function: DMSProc0x07TE
+
+*****************************************************************************/
+L3INT DMSProc0x07TE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ if (pMes->ProtDisc == 8) {
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ }
+ if (iFrom == 4) {
+ /* TODO Add proc here*/
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here*/
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+
+}
Added: freeswitch/trunk/libs/openzap/src/isdn/DMSmes.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/DMSmes.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/DMSmes.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,344 @@
+/*****************************************************************************
+
+ FileName: DMSmes.c
+
+ Contents: Pack/Unpack functions. These functions will unpack a DMS-100 ISDN
+ message from the bit packed original format into structs
+ that contains variables sized by the user. It will also pack
+ the struct back into a Q.931 message as required.
+
+ See national.h for description.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ 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 Case Labs, Ltd 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.
+
+*****************************************************************************/
+
+#include "DMS.h"
+
+/*****************************************************************************
+
+ Function: DMSUmes_Setup
+
+*****************************************************************************/
+L3INT DMSUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT ir = 0;
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+ L3UCHAR last_codeset = 0, codeset = 0;
+ L3UCHAR shift_lock = 1;
+
+ while (IOff < Size) {
+ if (!shift_lock) {
+ codeset = last_codeset;
+ }
+
+ if ((IBuf[IOff] & 0xF0) == Q931ie_SHIFT ) {
+ shift_lock = (IBuf[IOff] & 0x08);
+ if (shift_lock) {
+ last_codeset = codeset;
+ }
+ codeset = ((IBuf[IOff] & 0x07));
+ IOff++;
+ }
+
+ if (codeset == 0) {
+ switch (IBuf[IOff]) {
+ case Q931ie_SENDING_COMPLETE:
+ case Q931ie_BEARER_CAPABILITY:
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_NETWORK_SPECIFIC_FACILITIES:
+ case Q931ie_DISPLAY:
+ case Q931ie_DATETIME:
+ case Q931ie_KEYPAD_FACILITY:
+ case Q931ie_SIGNAL:
+ case Q931ie_CALLING_PARTY_NUMBER:
+ case Q931ie_CALLING_PARTY_SUBADDRESS:
+ case Q931ie_CALLED_PARTY_NUMBER:
+ case Q931ie_CALLED_PARTY_SUBADDRESS:
+ case Q931ie_TRANSIT_NETWORK_SELECTION:
+ case Q931ie_LOW_LAYER_COMPATIBILITY:
+ case Q931ie_HIGH_LAYER_COMPATIBILITY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ case Q931ie_REPEAT_INDICATOR:
+ if (ir < 2) {
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ ir++;
+ } else {
+ return Q931E_ILLEGAL_IE;
+ }
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ } else if (codeset == 6) {
+ switch (IBuf[IOff]) {
+ case Q931ie_GENERIC_DIGITS:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+
+ } else {
+ return Q931E_ILLEGAL_IE;
+ }
+ }
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: DMSPmes_Setup
+
+ Decription: Pack a Q931mes_Generic into a real Q.931 message. The user will
+ set up a SETUP message and issue this to the stack where it
+ is processed by Q931ProcSetup that processes and validates
+ it before it actually sends it out. This function is called
+ to compute the real Q.931 message.
+
+ Parameters: IBuf[IN] Ptr to un-packed struct
+ ISize[IN] Size of input buffer (unpacked message).
+ OBuf[OUT] Ptr to packed 'octet' wise message.
+ OSize[OUT] Size of packed message.
+
+ Called By: Q931ProcSetup
+
+*****************************************************************************/
+L3INT DMSPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3INT rc = Q931E_NO_ERROR;
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Sending Complete */
+ if (Q931IsIEPresent(pMes->SendComplete)) {
+ OBuf[Octet++] = (L3UCHAR)(pMes->SendComplete & 0x00ff);
+ }
+
+ /* Repeat Indicator */
+ if (Q931IsIEPresent(pMes->RepeatInd)) {
+ OBuf[Octet++] = (L3UCHAR)(pMes->RepeatInd & 0x00ff);
+ }
+
+ /* Bearer capability */
+ if (Q931IsIEPresent(pMes->BearerCap)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ } else {
+ rc = Q931E_BEARERCAP;
+ }
+
+ /* Channel Identification */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Network spesific facilities */
+ if (Q931IsIEPresent(pMes->NetFac)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_NETWORK_SPECIFIC_FACILITIES](pTrunk, Q931GetIEPtr(pMes->NetFac,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Date/Time */
+ if (Q931IsIEPresent(pMes->DateTime)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Keypad Facility */
+ if (Q931IsIEPresent(pMes->KeypadFac)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Calling Party Number */
+ if (Q931IsIEPresent(pMes->CallingNum)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CallingNum,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Calling Party Subaddress */
+ if (Q931IsIEPresent(pMes->CallingSub)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CallingSub,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Called Party number */
+ if (Q931IsIEPresent(pMes->CalledNum)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+
+ /* Called party subaddress */
+ if (Q931IsIEPresent(pMes->CalledSub)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CalledSub,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Transit network selection */
+ if (Q931IsIEPresent(pMes->TransNetSel)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_TRANSIT_NETWORK_SELECTION](pTrunk, Q931GetIEPtr(pMes->TransNetSel,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Repeat Indicator */
+ if (Q931IsIEPresent(pMes->LLRepeatInd)) {
+ rc = Q931E_UNKNOWN_IE;/* TODO */
+ }
+
+ /* Low Layer Compatibility */
+ if (Q931IsIEPresent(pMes->LLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* High Layer Compatibility */
+ if (Q931IsIEPresent(pMes->HLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+
+/*****************************************************************************
+
+ Function: DMSUmes_0x0f
+
+*****************************************************************************/
+L3INT DMSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ if (mes->ProtDisc == 8) {
+ return Q931Umes_ConnectAck(pTrunk, IBuf, mes, IOff, Size);
+ }
+
+ if (mes->ProtDisc == 3) {
+ return Q931Umes_Service(pTrunk, IBuf, mes, IOff, Size);
+ }
+
+ return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+ Function: DMSPmes_0x0f
+
+*****************************************************************************/
+L3INT DMSPmes_0x0f(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *mes = (Q931mes_Generic *)IBuf;
+
+ if (mes->ProtDisc == 8) {
+ return Q931Pmes_ConnectAck(pTrunk, IBuf, ISize, OBuf, OSize);
+ }
+
+ if (mes->ProtDisc == 3) {
+ return Q931Pmes_Service(pTrunk, IBuf, ISize, OBuf, OSize);
+ }
+
+ return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+ Function: DMSUmes_0x07
+
+*****************************************************************************/
+L3INT DMSUmes_0x07(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ if (mes->ProtDisc == 8) {
+ return Q931Umes_Connect(pTrunk, IBuf, mes, IOff, Size);
+ }
+
+ if (mes->ProtDisc == 3) {
+ return Q931Umes_ServiceAck(pTrunk, IBuf, mes, IOff, Size);
+ }
+
+ return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+ Function: DMSPmes_0x07
+
+*****************************************************************************/
+L3INT DMSPmes_0x07(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *mes = (Q931mes_Generic *)IBuf;
+
+ if (mes->ProtDisc == 8) {
+ return Q931Pmes_Connect(pTrunk, IBuf, ISize, OBuf, OSize);
+ }
+
+ if (mes->ProtDisc == 3) {
+ return Q931Pmes_ServiceAck(pTrunk, IBuf, ISize, OBuf, OSize);
+ }
+
+ return Q931E_UNKNOWN_MESSAGE;
+}
Added: freeswitch/trunk/libs/openzap/src/isdn/EuroISDNStateNT.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/EuroISDNStateNT.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/EuroISDNStateNT.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,44 @@
+/*****************************************************************************
+
+ FileName: EuroISDNStateNT.c
+
+ Contents: EuroISDN State Engine for NT (Network Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "Q931.h"
Added: freeswitch/trunk/libs/openzap/src/isdn/EuroISDNStateTE.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/EuroISDNStateTE.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/EuroISDNStateTE.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,58 @@
+/*****************************************************************************
+
+ FileName: EuroISDNStateTE.c
+
+ Contents: EuroISDN State Engine for TE (User Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "Q931.h"
+
+/*
+ EuroISDN is a sub-set of Q.931. Q.931 is very generic as it embrase a lot,
+ while EuroISDN is more exact and make decitions on some of the
+ 'implementation options' in the original standard. EuroISDN will
+ however run smoothly under the generic space, so these functions are more
+ for show
+*/
+#if 0
+static void EuroISDNCreateTE(L3UCHAR i)
+{
+ Q931CreateTE(i);
+}
+#endif
Added: freeswitch/trunk/libs/openzap/src/isdn/Q921.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/Q921.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/Q921.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3517 @@
+/*****************************************************************************
+
+ FileName: q921.c
+
+ Description: Contains the implementation of a Q.921 protocol
+
+ Created: 27.dec.2000/JVB
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+
+*****************************************************************************/
+
+/****************************************************************************
+ * Changes:
+ *
+ * - June-August 2008: Stefan Knoblich <s.knoblich@axsentis.de>:
+ * Add PTMP TEI management (NT + TE mode)
+ * Add timers
+ * Add retransmit counters
+ * Add logging
+ * Various cleanups
+ * Queues, retransmission of I frames
+ * PTMP NT mode
+ *
+ *
+ * TODO:
+ *
+ * - Cleanup queueing, test retransmission
+ *
+ * - Q921Start() /-Stop() TEI acquire + release
+ * (move everything related into these functions)
+ *
+ * - Q.921 '97 Appendix I (and maybe III, IV)
+ *
+ * - More complete Appendix II
+ *
+ * - Test PTP mode
+ *
+ * - PTMP NT mode (in progress)
+ *
+ * - NT mode TEI management: (ab)use T202 for TEI Check Request retransmission
+ *
+ * - General cleanup (move all non-public declarations into private header file)
+ *
+ * - Statistics, per-Frame type debug message filter
+ *
+ ****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "Q921.h"
+#include "Q921priv.h"
+#include "mfifo.h"
+
+#ifdef WIN32
+#pragma warning(disable:4100 4244)
+#endif
+
+/******************************************************************************************************
+ * Actual code below this line
+ ******************************************************************************************************/
+
+
+/**
+ * Q921StateNames
+ * \brief Static array of state name / value mappings
+ */
+static struct Q921StateName {
+ Q921State_t value;
+ const char *name;
+} Q921StateNames[10] = {
+ { Q921_STATE_STOPPED, "Stopped" },
+ { Q921_STATE_TEI_UNASSIGNED, "TEI Unassigned" },
+ { Q921_STATE_TEI_AWAITING, "TEI Awaiting Assignment" },
+ { Q921_STATE_TEI_ESTABLISH, "TEI Awaiting Establishment" },
+ { Q921_STATE_TEI_ASSIGNED, "TEI Assigned" },
+ { Q921_STATE_AWAITING_ESTABLISHMENT, "Awaiting Establishment" },
+ { Q921_STATE_AWAITING_RELEASE, "Awaiting Release" },
+ { Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, "Multiple Frame Mode Established" },
+ { Q921_STATE_TIMER_RECOVERY, "Timer Recovery" },
+ { 0, 0 }
+};
+
+/**
+ * Q921State2Name
+ * \brief Convert state value to name
+ * \param[in] state the state value
+ * \return the state name or "Unknown"
+ *
+ * \author Stefan Knoblich
+ */
+static const char *Q921State2Name(Q921State_t state)
+{
+ struct Q921StateName *p = Q921StateNames;
+
+ while(p->name) {
+ if(p->value == state)
+ return p->name;
+ p++;
+ }
+
+ return "Unknown";
+}
+
+
+/**
+ * Q921SendEnquiry
+ */
+static int Q921SendEnquiry(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ /* send enquiry: begin */
+ if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+
+ Q921SendRNR(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
+ }
+ else {
+ Q921SendRR(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
+ }
+
+ /* clear acknowledge pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+ /* "Start" T200 */
+ Q921T200TimerReset(trunk, tei);
+
+ /* send enquiry: end */
+ return 1;
+}
+
+/**
+ * Q921SendEnquiryResponse
+ */
+static int Q921SendEnquiryResponse(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ /* send enquiry: begin */
+ if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+
+ Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+ }
+ else {
+ Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+
+ /* clear acknowledge pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+ }
+ /* send enquiry: end */
+ return 1;
+}
+
+/**
+ * Q921ResetExceptionConditions
+ * \brief Reset Q.921 Exception conditions procedure
+ * \param trunk Q.921 data structure
+ * \param tei TEI
+ * \todo Do something
+ */
+static void Q921ResetExceptionConditions(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ /* Clear peer receiver busy */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+ /* Clear reject exception */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_REJECT);
+
+ /* Clear own receiver busy */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_RECV_BUSY);
+
+ /* Clear acknowledge pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+ return;
+}
+
+/**
+ * Q921EstablishDataLink
+ * \brief Q.921 Establish data link procedure
+ * \param trunk Q.921 data structure
+ * \param tei TEI
+ * \return always 1 (success)
+ */
+static int Q921EstablishDataLink(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ /* reset exception conditions */
+ Q921ResetExceptionConditions(trunk, tei);
+
+ /* RC = 0 */
+ link->N200 = 0;
+
+ /* Send SABME */
+ Q921SendSABME(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
+
+ /* Restart T200, stop T203 */
+ Q921T200TimerReset(trunk, tei);
+ Q921T203TimerStop(trunk, tei);
+
+ return 1;
+}
+
+/**
+ * Q921NrErrorRecovery
+ * \brief NR(R) Error recovery procedure
+ * \param trunk Q.921 data structure
+ * \param tei TEI
+ * \return always 1 (success)
+ */
+static int Q921NrErrorRecovery(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ /* MDL Error indication (J) */
+
+ /* Establish datalink */
+ Q921EstablishDataLink(trunk, tei);
+
+ /* Clear L3 initiated */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+ return 1;
+}
+
+
+/**
+ * Q921InvokeRetransmission
+ * \brief I Frame retransmission procedure
+ * \param trunk Q.921 data structure
+ * \param tei TEI
+ * \param nr N(R) for retransmission
+ * \return always 1 (success)
+ */
+static int Q921InvokeRetransmission(L2TRUNK trunk, L2UCHAR tei, L2UCHAR nr)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+ L2UCHAR *mes;
+ L2INT qpos, qnum, size = 0;
+
+ qnum = MFIFOGetMesCount(link->IFrameResendQueue);
+ qpos = qnum - 1;
+
+ /*
+ * slightly different than what is shown in the spec
+ * (Q.921 '97 Annex B, Figure B.9, page 104)
+ *
+ * what the above mentioned figure probably means is:
+ * "as long as V(S) != N(R), move the pointer marking
+ * the first frame to start resending at to the previous
+ * frame"
+ *
+ * if we actually implemented it as shown in the figure, we'd be
+ * resending frames in the wrong order (moving backwards in time)
+ * meaning we'd have to add an incoming queue to reorder the frames
+ *
+ */
+ /*
+ * TODO: There's a "traditional" off-by-one error hidden in the original
+ * mfifo implementation + it's late, i'm tired and being lazy,
+ * so i'll probably have added another one :P
+ *
+ * wow, the first while loop sucks and can be removed
+ */
+ while(link->vs != nr && qpos > 0) { /* ???? */
+ /* V(S) = V(S) - 1 */
+ Q921_DEC_COUNTER(link->vs); /* huh? backwards? */
+
+ /* next frame in queue (backtrack along I queue) ??? */
+ qpos--;
+ }
+
+ /*
+ * being lazy and trying to avoid mod 128 math this way...
+ */
+ if(link->vs != nr && !qpos) {
+ /* fatal, we don't have enough history to resend all missing frames */
+ /* TODO: how to handle this? */
+ }
+
+ /*
+ * resend frames in correct order (oldest missing frame first,
+ * contrary to what the spec figure shows)
+ */
+ while(qpos < qnum) {
+ /* Grab frame's buffer ptr and size from queue */
+ mes = MFIFOGetMesPtrOffset(link->IFrameResendQueue, &size, qpos);
+ if(mes) {
+ /* requeue frame (TODO: check queue full condition) */
+ MFIFOWriteMes(link->IFrameQueue, mes, size);
+
+ /* set I frame queued */
+ }
+
+ qpos++;
+ }
+
+ return 1;
+}
+
+
+static int Q921AcknowledgePending(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ case Q921_STATE_TIMER_RECOVERY:
+ if(Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING)) {
+ /* clear acknowledge pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+ /* send RR */
+ Q921SendRR(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 0);
+
+ return 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+
+ Function: Q921_InitTrunk
+
+ Decription: Initialize a Q.921 trunk so it is ready for use. This
+ function MUST be called before you call any other functions.
+
+*****************************************************************************/
+int Q921_InitTrunk(L2TRUNK trunk,
+ L2UCHAR sapi,
+ L2UCHAR tei,
+ Q921NetUser_t NetUser,
+ Q921NetType_t NetType,
+ L2INT hsize,
+ Q921Tx21CB_t cb21,
+ Q921Tx23CB_t cb23,
+ void *priv21,
+ void *priv23)
+{
+ int numlinks = 0;
+
+ trunk->sapi = sapi;
+ trunk->tei = tei;
+ trunk->NetUser = NetUser;
+ trunk->NetType = NetType;
+ trunk->Q921Tx21Proc = cb21;
+ trunk->Q921Tx23Proc = cb23;
+ trunk->PrivateData21 = priv21;
+ trunk->PrivateData23 = priv23;
+ trunk->Q921HeaderSpace = hsize;
+
+ numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
+
+ if (trunk->initialized != INITIALIZED_MAGIC) {
+ MFIFOCreate(trunk->HDLCInQueue, Q921MAXHDLCSPACE, 10);
+
+ /*
+ * Allocate space for per-link context(s)
+ */
+ trunk->context = malloc(numlinks * sizeof(struct Q921_Link));
+ if(!trunk->context)
+ return -1;
+
+ trunk->initialized = INITIALIZED_MAGIC;
+ }
+
+ /* timeout default values */
+ trunk->T200Timeout = 1000; /* 1 second */
+ trunk->T203Timeout = 10000; /* 10 seconds */
+ trunk->T202Timeout = 2000; /* 2 seconds */
+ trunk->T201Timeout = 200000; /* 200 seconds */
+ trunk->TM01Timeout = 10000; /* 10 seconds */
+
+ /* octet / retransmit counter default limits */
+ trunk->N200Limit = 3; /* 3 retransmits */
+ trunk->N201Limit = 260; /* 260 octets */
+ trunk->N202Limit = 3; /* 3 retransmits */
+ trunk->k = 7; /* 7 outstanding ACKs */
+
+ /* reset counters, timers, etc. */
+ trunk->T202 = 0;
+ trunk->N202 = 0;
+
+ /* Reset per-link contexts */
+ memset(trunk->context, 0, numlinks * sizeof(struct Q921_Link));
+
+ /* clear tei map */
+ memset(trunk->tei_map, 0, Q921_TEI_MAX + 1);
+
+ if(Q921_IS_PTMP(trunk)) {
+ /*
+ * We're either the Network side (NT, TEI = 0)
+ * or user-side equipment (TE) which will get it's TEI via
+ * dynamic assignment
+ */
+ trunk->tei = 0;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Q921Tx21Proc
+ * \brief Submit frame to layer 1 (for sending)
+ * \param[in] trunk Pointer to trunk struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success; <= 0 on error
+ */
+static int Q921Tx21Proc(L2TRUNK trunk, L2UCHAR *Msg, L2INT size)
+{
+ Q921LogMesg(trunk, Q921_LOG_DEBUG, 0, Msg, size, "Sending frame");
+
+ return trunk->Q921Tx21Proc(trunk->PrivateData21, Msg, size);
+}
+
+
+/**
+ * Q921Tx23Proc
+ * \brief Submit frame to layer 3
+ * \param[in] trunk Pointer to trunk struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success; <= 0 on error
+ */
+static int Q921Tx23Proc(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *Msg, L2INT size)
+{
+ return trunk->Q921Tx23Proc(trunk->PrivateData23, ind, tei, Msg, size);
+}
+
+
+/**
+ * Q921LogProc
+ * \brief Used for logging, converts to string and submits to higher level log function via callback
+ * \param[in] trunk Pointer to trunk struct
+ * \param[in] level Q921 Loglevel
+ * \param[in] fmt format of logmessage
+ * \return >= 0 on success, < 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921Log(L2TRUNK trunk, Q921LogLevel_t level, const char *fmt, ...)
+{
+ char buf[Q921_LOGBUFSIZE];
+ L2INT len;
+ va_list ap;
+
+ if(!trunk->Q921LogProc)
+ return 0;
+
+ if(trunk->loglevel < level)
+ return 0;
+
+ va_start(ap, fmt);
+
+ len = vsnprintf(buf, sizeof(buf)-1, fmt, ap);
+ if(len <= 0) {
+ /* TODO: error handling */
+ return -1;
+ }
+ if(len >= sizeof(buf))
+ len = sizeof(buf) - 1;
+
+ buf[len] = '\0';
+
+ va_end(ap);
+
+ return trunk->Q921LogProc(trunk->PrivateDataLog, level, buf, len);
+}
+
+
+static int print_hex(char *buf, int bsize, const unsigned char *in, const int len)
+{
+ static const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+ int offset = 0;
+ int pos = 0;
+ int nr = 0;
+
+ buf[pos++] = '[';
+ bsize -= 3;
+
+ while((bsize - pos) > 0 && offset < len) {
+ buf[pos++] = hex[(in[offset] & 0xF0) >> 4];
+ buf[pos++] = hex[(in[offset++] & 0x0F)];
+
+ if(++nr == 32 && offset < len && (bsize - pos) > 3) {
+ nr = 0;
+ buf[pos++] = ']';
+ buf[pos++] = '\n';
+ buf[pos++] = '[';
+ }
+ else if(offset < len) {
+ buf[pos++] = ' ';
+ }
+ }
+
+ buf[pos++] = ']';
+ buf[pos++] = '\n';
+ buf[pos] = '\0';
+
+ return pos;
+}
+
+#define APPEND_MSG(buf, off, lef, fmt, ...) \
+ len = snprintf(buf + off, lef, fmt, ##__VA_ARGS__); \
+ if(len > 0) { \
+ off += len; \
+ lef -= len; \
+ } else { \
+ goto out; \
+ }
+
+/**
+ * Q921LogProcMesg
+ * \brief Used for logging, converts to string and submits to higher level log function via callback
+ * \param[in] trunk Pointer to trunk struct
+ * \param[in] level Q921 Loglevel
+ * \param[in] received direction of the message (received = 1, sending = 0)
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \param[in] fmt format of logmessage
+ * \return >= 0 on success, < 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921LogMesg(L2TRUNK trunk, Q921LogLevel_t level, L2UCHAR received, L2UCHAR *mes, L2INT size, const char *fmt, ...)
+{
+ char buf[Q921_LOGBUFSIZE];
+ size_t len, left;
+ va_list ap;
+
+ if(!trunk->Q921LogProc)
+ return 0;
+
+ if(trunk->loglevel < level)
+ return 0;
+
+ if(!mes)
+ return 0;
+
+ memset(buf, 0, sizeof(buf));
+
+ left = sizeof(buf) - 1;
+
+ va_start(ap, fmt);
+
+ len = vsnprintf(buf, left, fmt, ap);
+ if(len > 0)
+ left -= len;
+ else {
+ /* TODO: error handling */
+ return -1;
+ }
+
+ va_end(ap);
+
+ if(trunk->loglevel == Q921_LOG_DEBUG) {
+ char pbuf[1024];
+ size_t pleft, poffset;
+ L2UCHAR sapi, tei, cr;
+ L2UCHAR *pmes = mes + trunk->Q921HeaderSpace;
+ struct Q921_Link *link;
+
+ memset(pbuf, 0, sizeof(pbuf));
+
+ pleft = sizeof(pbuf);
+ poffset = 0;
+
+ /*
+ * Decode packet
+ */
+ sapi = (pmes[0] & 0xfc) >> 2;
+ cr = (pmes[0] & 0x02) >> 1;
+ tei = (pmes[1] & 0xfe) >> 1;
+ link = Q921_LINK_CONTEXT(trunk, tei);
+
+ /* make cr actually useful */
+ cr = (received) ? Q921_IS_COMMAND(trunk, cr) : Q921_IS_RESPONSE(trunk, cr);
+
+ /* filter */
+ if((pmes[2] & 0x01) == 0x00) {
+ ;
+ }
+ else if((pmes[2] & 0x03) == 0x01) {
+ ; //return 0;
+ }
+ else if((pmes[2] & 0x03) == 0x03) {
+ ;
+ }
+
+ APPEND_MSG(pbuf, poffset, pleft, "\n----------------- Q.921 Packet [%s%s] ---------------\n", received ? "Incoming" : "Outgoing",
+ (tei == link->tei || tei == Q921_TEI_BCAST) ? "" : ", Ignored" );
+
+ /* common header */
+ APPEND_MSG(pbuf, poffset, pleft, " SAPI: %u, TEI: %u, C/R: %s (%d)\n\n", sapi, tei, (cr) ? "Command" : "Response", (mes[0] & 0x02) >> 1 );
+
+ /*
+ * message specific
+ */
+ if((pmes[2] & 0x01) == 0x00) {
+ /*
+ * I frame
+ */
+ L2UCHAR pf = pmes[3] & 0x01; /* poll / final flag */
+ L2UCHAR nr = pmes[3] >> 1; /* receive sequence number */
+ L2UCHAR ns = pmes[2] >> 1; /* send sequence number */
+
+ APPEND_MSG(pbuf, poffset, pleft, " Type: I Frame\n P/F: %d, N(S): %d, N(R): %d [V(A): %d, V(R): %d, V(S): %d]\n", pf, ns, nr,
+ link->va, link->vr, link->vs);
+
+ /* Dump content of I Frames for foreign TEIs */
+ if(tei != link->tei) {
+ APPEND_MSG(pbuf, poffset, pleft, " CONTENT:\n");
+
+ len = print_hex(pbuf + poffset, (int)pleft, &pmes[4], size - (trunk->Q921HeaderSpace + 4));
+ poffset += len;
+ pleft -= len;
+ }
+ }
+ else if((pmes[2] & 0x03) == 0x01) {
+ /*
+ * S frame
+ */
+ L2UCHAR sv = (pmes[2] & 0x0c) >> 2; /* supervisory format id */
+ L2UCHAR pf = pmes[3] & 0x01; /* poll / final flag */
+ L2UCHAR nr = pmes[3] >> 1; /* receive sequence number */
+ const char *type;
+
+ switch(sv) {
+ case 0x00: /* RR : Receive Ready */
+ type = "RR (Receive Ready)";
+ break;
+
+ case 0x02: /* RNR : Receive Not Ready */
+ type = "RNR (Receiver Not Ready)";
+ break;
+
+ case 0x04: /* REJ : Reject */
+ type = "REJ (Reject)";
+ break;
+
+ default: /* Invalid / Unknown */
+ type = "Unknown";
+ break;
+ }
+
+ APPEND_MSG(pbuf, poffset, pleft, " Type: S Frame, SV: %s\n P/F: %d, N(R): %d [V(A): %d, V(R): %d, V(S): %d]\n", type, pf, nr,
+ link->va, link->vr, link->vs);
+ }
+ else if((pmes[2] & 0x03) == 0x03) {
+ /*
+ * U frame
+ */
+ L2UCHAR m = (pmes[2] & 0xe0) >> 3 | (pmes[2] & 0x0c) >> 2; /* modifier function id */
+ L2UCHAR pf = (pmes[2] & 0x10) >> 4; /* poll / final flag */
+ const char *type;
+
+ switch(m) {
+ case 0x00:
+ type = "UI (Unnumbered Information)";
+ break;
+
+ case 0x03:
+ type = "DM (Disconnected Mode)";
+ break;
+
+ case 0x08:
+ type = "DISC (Disconnect)";
+ break;
+
+ case 0x0c:
+ type = "UA (Unnumbered Acknowledgement)";
+ break;
+
+ case 0x0f:
+ type = "SABME";
+ break;
+
+ case 0x11:
+ type = "FRMR (Frame Reject)";
+ break;
+
+ case 0x17:
+ type = "XID (Exchange Identification)";
+ break;
+
+ default:
+ type = "Unknown";
+ }
+
+
+ APPEND_MSG(pbuf, poffset, pleft, " Type: U Frame (%s)\n P/F: %d\n", type, pf);
+
+ if(m == 0x00) {
+ switch(pmes[3]) {
+ case Q921_LAYER_ENT_ID_TEI:
+ type = "TEI Mgmt";
+ break;
+
+ case Q921_LAYER_ENT_ID_Q931:
+ type = "Q.931";
+ break;
+
+ default:
+ type = "Unknown";
+ }
+
+ if(pmes[3] == Q921_LAYER_ENT_ID_TEI) {
+ const char *command = "";
+
+ switch(pmes[6]) {
+ case Q921_TEI_ID_REQUEST:
+ command = "Request";
+ break;
+ case Q921_TEI_ID_VERIFY:
+ command = "Verify";
+ break;
+ case Q921_TEI_ID_CHECKREQ:
+ command = "Check req";
+ break;
+ case Q921_TEI_ID_CHECKRESP:
+ command = "Check resp";
+ break;
+ case Q921_TEI_ID_REMOVE:
+ command = "Remove";
+ break;
+ case Q921_TEI_ID_ASSIGNED:
+ command = "Assign";
+ break;
+ case Q921_TEI_ID_DENIED:
+ command = "Denied";
+ break;
+ }
+ APPEND_MSG(pbuf, poffset, pleft, " ENT ID: %d (%s), COMMAND: %d (%s), RI: %#x, AI: %d\n",
+ pmes[3], type, pmes[6], command, (int)((pmes[4] << 8) | pmes[5]), pmes[7] >> 1);
+ }
+ else {
+ APPEND_MSG(pbuf, poffset, pleft, " ENT ID: %d (%s), MESSAGE CONTENT:\n", pmes[3], type);
+
+ len = print_hex(pbuf + poffset, (int)pleft, &pmes[3], size - (trunk->Q921HeaderSpace + 3));
+ poffset += len;
+ pleft -= len;
+ }
+ }
+ }
+ else {
+ /*
+ * Unknown
+ */
+ strncat(pbuf + poffset, " -- unknown frame type --\n", pleft);
+
+ len = (sizeof(pbuf) - poffset) - strlen(pbuf + poffset);
+ if(len > 0) {
+ poffset += len;
+ pleft -= len;
+ } else
+ goto out;
+ }
+
+ APPEND_MSG(pbuf, poffset, pleft, "\n Q.921 state: \"%s\" (%d) [flags: %c%c%c%c]\n", Q921State2Name(link->state), link->state,
+ Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING) ? 'A' : '-',
+ Q921_CHECK_FLAG(link, Q921_FLAG_REJECT) ? 'R' : '-',
+ Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY) ? 'P' : '-',
+ Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY) ? 'B' : '-');
+
+ strncat(pbuf + poffset, "----------------------------------------------\n\n", pleft);
+
+ len = (sizeof(pbuf) - poffset) - strlen(pbuf + poffset);
+ if(len > 0) {
+ poffset += len;
+ pleft -= len;
+ } else
+ goto out;
+
+
+ /* concat buffers together */
+ len = strlen(pbuf);
+ if(len <= left)
+ strncat(buf, pbuf, left);
+ else
+ strncat(buf, "-- packet truncated --\n", left);
+ }
+
+out:
+ buf[sizeof(buf) - 1] = '\0';
+
+ return trunk->Q921LogProc(trunk->PrivateDataLog, level, buf, (int)strlen(buf));
+}
+
+/*****************************************************************************
+
+ Function: Q921TimeTick
+
+ Description: Called periodically from an external source to allow the
+ stack to process and maintain it's own timers.
+
+ Return Value: none
+
+*****************************************************************************/
+static L2ULONG (*Q921GetTimeProc) (void) = NULL; /* callback for func reading time in ms */
+static L2ULONG tLast = {0};
+
+static L2ULONG Q921GetTime(void)
+{
+ L2ULONG tNow = 0;
+
+ if(Q921GetTimeProc)
+ {
+ tNow = Q921GetTimeProc();
+ if(tNow < tLast) /* wrapped */
+ {
+ /* TODO */
+ }
+ tLast = tNow;
+ }
+ return tNow;
+}
+
+/*
+ * T200 handling (per-TEI in PTMP NT mode, tei=0 otherwise)
+ */
+static void Q921T200TimerStart(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ if (!link->T200) {
+ link->T200 = Q921GetTime() + trunk->T200Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T200 (timeout: %d msecs) started for TEI %d\n", trunk->T200Timeout, tei);
+ }
+}
+
+static void Q921T200TimerStop(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ link->T200 = 0;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T200 stopped for TEI %d\n", tei);
+}
+
+static void Q921T200TimerReset(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ link->T200 = Q921GetTime() + trunk->T200Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T200 (timeout: %d msecs) restarted for TEI %d\n", trunk->T200Timeout, tei);
+}
+
+/*
+ * T203 handling (per-TEI in PTMP NT mode, tei=0 otherwise)
+ */
+static void Q921T203TimerStart(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ if (!link->T203) {
+ link->T203 = Q921GetTime() + trunk->T203Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T203 (timeout: %d msecs) started for TEI %d\n", trunk->T203Timeout, tei);
+ }
+}
+
+static void Q921T203TimerStop(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ link->T203 = 0;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T203 stopped for TEI %d\n", tei);
+}
+
+static void Q921T203TimerReset(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ link->T203 = Q921GetTime() + trunk->T203Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T203 (timeout: %d msecs) restarted for TEI %d\n", trunk->T203Timeout, tei);
+}
+
+/*
+ * T202 handling (TEI message timeout, TE mode only)
+ */
+static void Q921T202TimerStart(L2TRUNK trunk)
+{
+ if (!trunk->T202) {
+ trunk->T202 = Q921GetTime() + trunk->T202Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T202 (timeout: %d msecs) started\n", trunk->T202Timeout);
+ }
+}
+
+static void Q921T202TimerStop(L2TRUNK trunk)
+{
+ trunk->T202 = 0;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T202 stopped\n");
+}
+
+static void Q921T202TimerReset(L2TRUNK trunk)
+{
+ trunk->T202 = Q921GetTime() + trunk->T202Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T202 (timeout: %d msecs) restarted\n", trunk->T202Timeout);
+}
+
+/*
+ * T201 handling (TEI management (NT side), per-TEI)
+ */
+static void Q921T201TimerStart(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ if (!link->T201) {
+ link->T201 = Q921GetTime() + trunk->T201Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T201 (timeout: %d msecs) started for TEI %d\n", trunk->T201Timeout, tei);
+ }
+}
+
+static void Q921T201TimerStop(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ link->T201 = 0;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T201 stopped for TEI %d\n", tei);
+}
+
+#ifdef __UNUSED_FOR_NOW__
+static void Q921T201TimerReset(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ link->T201 = Q921GetTime() + trunk->T201Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T201 (timeout: %d msecs) restarted for TEI %d\n", trunk->T201Timeout, tei);
+}
+#endif
+
+/*
+ * TM01 handling (Datalink inactivity shutdown timer)
+ */
+static void Q921TM01TimerStart(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ if (!link->TM01) {
+ link->TM01 = Q921GetTime() + trunk->TM01Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "TM01 (timeout: %d msecs) started for TEI %d\n", trunk->TM01Timeout, tei);
+ }
+}
+
+#ifdef __UNUSED_FOR_NOW__
+static void Q921TM01TimerStop(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ link->TM01 = 0;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "TM01 stopped for TEI %d\n", tei);
+}
+#endif
+
+static void Q921TM01TimerReset(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ link->TM01 = Q921GetTime() + trunk->TM01Timeout;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "TM01 (timeout: %d msecs) restarted for TEI %d\n", trunk->TM01Timeout, tei);
+}
+
+/*
+ * Expiry callbacks
+ */
+static void Q921T200TimerExpire(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+ struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T200 expired for TEI %d (trunk TEI %d)\n", tei, trlink->tei);
+
+ /* Stop timer first */
+ Q921T200TimerStop(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_AWAITING_ESTABLISHMENT:
+ if(link->N200 >= trunk->N200Limit) {
+ /* Discard I queue */
+ MFIFOClear(link->IFrameQueue);
+
+ /* MDL-Error indication (G) */
+ Q921Log(trunk, Q921_LOG_ERROR, "Failed to establish Q.921 link in %d retries\n", link->N200);
+
+ /* DL-Release indication */
+ Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+ } else {
+ /* Increment retry counter */
+ link->N200++;
+
+ /* Send SABME */
+ Q921SendSABME(trunk,
+ trunk->sapi,
+ Q921_COMMAND(trunk),
+ tei,
+ 1);
+
+ /* Start T200 */
+ Q921T200TimerStart(trunk, tei);
+ }
+ break;
+
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ link->N200 = 0;
+
+ if(!Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
+ /* get last transmitted I frame */
+
+ /* V(S) = V(S) - 1 */
+ Q921_DEC_COUNTER(link->vs);
+
+ /* retransmit I frame */
+
+ /* V(S) = V(S) + 1 (done by Q921SendI() ) */
+ //Q921_INC_COUNTER(link->vs);
+
+ /* clear acknowledge pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+ /* Start T200 */
+ Q921T200TimerStart(trunk, tei);
+ } else {
+ /* transmit enquiry */
+ Q921SendEnquiry(trunk, tei);
+ }
+
+ /* increment counter */
+ link->N200++;
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_TIMER_RECOVERY, tei);
+ break;
+
+ case Q921_STATE_TIMER_RECOVERY:
+ if(link->N200 == trunk->N200Limit) {
+ /* MDL Error indication (I) */
+
+ /* Establish data link */
+ Q921EstablishDataLink(trunk, tei);
+
+ /* Clear L3 initiated */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ } else {
+ if(link->vs == link->va) {
+ /* transmit enquiry */
+ Q921SendEnquiry(trunk, tei);
+
+ } else if(!Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
+ /* get last transmitted frame */
+
+ /* V(S) = V(S) - 1 */
+ Q921_DEC_COUNTER(link->vs);
+
+ /* retrans frame */
+
+ /* V(S) = V(S) + 1 (done by Q921SendI() ) */
+ //Q921_INC_COUNTER(link->vs);
+
+ /* clear acknowledge pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+ /* Start T200 */
+ Q921T200TimerStart(trunk, tei);
+ }
+
+ /* increment counter */
+ link->N200++;
+
+ /* no state change */
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void Q921T203TimerExpire(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+ struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T203 expired for TEI %d (trunk TEI %d)\n", tei, trlink->tei);
+
+ /* Stop Timer first */
+ Q921T203TimerStop(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ /* Send Enquiry */
+ Q921SendEnquiry(trunk, tei);
+
+ /* RC = 0 */
+ link->N200 = 0;
+
+ /* no state change */
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void Q921T202TimerExpire(L2TRUNK trunk)
+{
+ struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+
+ Q921T202TimerReset(trunk);
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T202 expired for Q.921 trunk with TEI %d\n", link->tei);
+
+ /* todo: implement resend counter */
+
+ switch(link->state) {
+ case Q921_STATE_TEI_ASSIGNED: /* Tei identity verify timeout */
+ Q921TeiSendVerifyRequest(trunk);
+ break;
+
+ default: /* Tei assignment request timeout (TODO: refine) */
+
+ if(trunk->N202 >= trunk->N202Limit) {
+ /* Too many retransmits, reset counter, stop timer and handle case (TODO) */
+ trunk->N202 = 0;
+
+ Q921T202TimerStop(trunk);
+
+ return;
+ }
+ Q921TeiSendAssignRequest(trunk);
+
+ trunk->N202++;
+ }
+}
+
+static void Q921T201TimerExpire(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+ struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "T201 expired for TEI %d (trunk TEI: %d)\n", tei, trlink->tei);
+
+ Q921T201TimerStop(trunk, tei);
+
+ /* NOTE: abusing N202 for this */
+ if(link->N202 < trunk->N202Limit) {
+ /* send check request */
+ Q921TeiSendCheckRequest(trunk, tei);
+
+ /* increment counter */
+ link->N202++;
+ } else {
+ /* put context in STOPPED state */
+ Q921ChangeState(trunk, Q921_STATE_STOPPED, tei);
+
+ /* NOTE: should we clear the link too? */
+ memset(link, 0, sizeof(struct Q921_Link));
+
+ /* mark TEI free */
+ trunk->tei_map[tei] = 0;
+ }
+}
+
+#ifdef __UNUSED_FOR_NOW__
+static void Q921TM01TimerExpire(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+ struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "TM01 expired for TEI %d (trunk TEI: %d)\n", tei, trlink->tei);
+
+ /* Restart TM01 */
+ Q921TM01TimerReset(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ case Q921_STATE_TIMER_RECOVERY:
+/*
+ * NT-only, needs more support from L3
+ */
+#if 0
+ /* No activity, shutdown link */
+ Q921SendDISC(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
+
+ /* clear I queue */
+ MFIFOClear(link->IFrameQueue);
+
+ /* change state */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_RELEASE, tei);
+#endif
+ break;
+
+ default:
+ break;
+ }
+}
+#endif
+
+/*
+ * Timer Tick function
+ */
+void Q921TimerTick(L2TRUNK trunk)
+{
+ struct Q921_Link *link;
+ L2ULONG tNow = Q921GetTime();
+ int numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
+ int x;
+
+ for(x = 0; x <= numlinks; x++) {
+ link = Q921_LINK_CONTEXT(trunk, x);
+
+ /* TODO: check if TEI is assigned and skip check if not (speedup!) */
+ if(link->state == Q921_STATE_STOPPED)
+ continue;
+
+ if (link->T200 && tNow > link->T200) {
+ Q921T200TimerExpire(trunk, link->tei);
+ }
+ if (link->T203 && tNow > link->T203) {
+ Q921T203TimerExpire(trunk, link->tei);
+ }
+
+ if(Q921_IS_PTMP_NT(trunk) && link->tei) {
+ if (link->T201 && tNow > link->T201) {
+ Q921T201TimerExpire(trunk, link->tei);
+ }
+ }
+
+ if(!Q921_IS_PTMP_NT(trunk)) {
+ if (trunk->T202 && tNow > trunk->T202) {
+ Q921T202TimerExpire(trunk);
+ }
+ }
+
+ /* Send enqueued I frame, if available */
+ Q921SendQueuedIFrame(trunk, link->tei);
+
+ /* Send ack if pending */
+ Q921AcknowledgePending(trunk, link->tei);
+ }
+
+}
+
+void Q921SetGetTimeCB(L2ULONG (*callback)(void))
+{
+ Q921GetTimeProc = callback;
+}
+
+/*****************************************************************************
+
+ Function: Q921QueueHDLCFrame
+
+ Description: Called to receive and queue an incoming HDLC frame. Will
+ queue this in Q921HDLCInQueue. The called must either call
+ Q921Rx12 directly afterwards or signal Q921Rx12 to be called
+ later. Q921Rx12 will read from the same queue and process
+ the frame.
+
+ This function assumes that the message contains header
+ space. This is removed for internal Q921 processing, but
+ must be keept for I frames.
+
+ Parameters: trunk trunk #
+ b ptr to frame;
+ size size of frame in bytes
+
+*****************************************************************************/
+int Q921QueueHDLCFrame(L2TRUNK trunk, L2UCHAR *b, L2INT size)
+{
+ return MFIFOWriteMes(trunk->HDLCInQueue, b, size);
+}
+
+/**
+ * Q921EnqueueI
+ * \brief Put I frame into transmit queue
+ *
+ */
+static int Q921EnqueueI(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR *mes, L2INT size)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
+
+ /* I frame header */
+ mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
+ mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
+ mes[trunk->Q921HeaderSpace+2] = 0x00;
+ mes[trunk->Q921HeaderSpace+3] = (pf & 0x01);
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Enqueueing I frame for TEI %d [%d]\n", link->tei, Tei);
+
+ /* transmit queue, (TODO: check for full condition!) */
+ MFIFOWriteMes(link->IFrameQueue, mes, size);
+
+ /* try to send queued frame */
+ Q921SendQueuedIFrame(trunk, link->tei);
+
+ return 1;
+}
+
+/**
+ * Q921SendQueuedIFrame
+ * \brief Try to transmit queued I frame (if available)
+ */
+static int Q921SendQueuedIFrame(L2TRUNK trunk, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ L2INT size = 0;
+ L2UCHAR *mes;
+
+ if(MFIFOGetMesCount(link->IFrameQueue) == 0) {
+ return 0;
+ }
+
+ /* Link ready? */
+ if(link->state != Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+ return 0;
+ }
+
+ /* peer receiver busy? */
+ if(Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
+ return 0;
+ }
+
+ /* V(S) = V(A) + k? */
+ if(link->vs == ((link->va + trunk->k) % 128)) {
+ Q921Log(trunk, Q921_LOG_WARNING, "Maximum number (%d) of outstanding I frames reached for TEI %d\n", trunk->k, tei);
+ return 0;
+ }
+
+ mes = MFIFOGetMesPtr(link->IFrameQueue, &size);
+ if(mes) {
+ /* Fill in + update counter values */
+ mes[trunk->Q921HeaderSpace+2] = link->vs << 1;
+ mes[trunk->Q921HeaderSpace+3] |= link->vr << 1;
+
+ if(MFIFOGetMesCount(link->IFrameQueue) == 0) {
+ /* clear I frame queued */
+ }
+
+ /* Send I frame */
+ Q921Tx21Proc(trunk, mes, size);
+
+ /* V(S) = V(S) + 1 */
+ Q921_INC_COUNTER(link->vs);
+
+ /* clear acknowledge pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+ /* T200 running? */
+ if(!link->T200) {
+ /* Stop T203, Start T200 */
+ Q921T200TimerStart(trunk, tei);
+ Q921T203TimerStop(trunk, tei);
+ }
+
+ /* put frame into resend queue */
+ MFIFOWriteMesOverwrite(link->IFrameResendQueue, mes, size);
+
+ /* dequeue frame */
+ MFIFOKillNext(link->IFrameQueue);
+
+ /* Restart TM01 */
+ if(Q921_IS_NT(trunk)) {
+ Q921TM01TimerReset(trunk, tei);
+ }
+
+ /* no state change */
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Q921SendS
+ * \brief Prepare and send S frame
+ */
+static int Q921SendS(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR sv, L2UCHAR *mes, L2INT size)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
+
+ if(!Q921_IS_READY(link)) {
+ /* don't even bother trying */
+ Q921Log(trunk, Q921_LOG_DEBUG, "Link not ready, discarding S frame for TEI %d\n", Tei);
+ return 0;
+ }
+
+ /* S frame header */
+ mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
+ mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
+ mes[trunk->Q921HeaderSpace+2] = ((sv << 2) & 0x0c) | 0x01;
+ mes[trunk->Q921HeaderSpace+3] = (link->vr << 1) | (pf & 0x01);
+
+ return Q921Tx21Proc(trunk, mes, size);
+}
+
+
+/**
+ * Q921SendU
+ * \brief Prepare and send U frame
+ */
+static int Q921SendU(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR m, L2UCHAR *mes, L2INT size)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
+
+ /* U frame header */
+ mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
+ mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
+ mes[trunk->Q921HeaderSpace+2] = ((m << 3) & 0xe0) | ((pf << 4) & 0x10) | ((m << 2) & 0x0c) | 0x03;
+
+ /* link not ready? enqueue non-TEI-mgmt UI (DL-UNIT DATA) frames */
+ if(m == 0x00 && Sapi != Q921_SAPI_TEI && link->state < Q921_STATE_TEI_ASSIGNED) {
+
+ /* write frame to queue */
+ MFIFOWriteMes(link->UIFrameQueue, mes, size);
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Link not ready, UI Frame of size %d bytes queued for TEI %d\n", size, Tei);
+ return 1;
+ }
+
+ return Q921Tx21Proc(trunk, mes, size);
+}
+
+/**
+ * TODO: NT mode handling? Need a way to get Link context from Q.931
+ */
+int Q921Rx32(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR * Mes, L2INT Size)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei); /* TODO: need real link tei for NT mode */
+ L2INT res = 0;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Got frame from Q.931, type: %d, tei: %d, size: %d\n", ind, tei, Size);
+
+ switch(ind) {
+ case Q921_DL_ESTABLISH:
+ /*
+ * Hmm...
+ */
+ switch(link->state) {
+ case Q921_STATE_TEI_ASSIGNED:
+ if(!Q921_IS_NT(trunk)) {
+ /* establish data link */
+ Q921EstablishDataLink(trunk, link->tei);
+
+ /* Set layer 3 initiated */
+ Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
+ }
+ break;
+
+ case Q921_STATE_AWAITING_ESTABLISHMENT:
+ if(!Q921_IS_NT(trunk)) {
+ /* Discard I queue */
+ MFIFOClear(link->IFrameQueue);
+
+ /* Set layer 3 initiated */
+ Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
+ }
+ break;
+
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ case Q921_STATE_TIMER_RECOVERY:
+ if(!Q921_IS_NT(trunk)) {
+ /* Discard I queue */
+ MFIFOClear(link->IFrameQueue);
+
+ /* establish data link */
+ Q921EstablishDataLink(trunk, link->tei);
+
+ /* Set layer 3 initiated */
+ Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case Q921_DL_RELEASE:
+ switch(link->state) {
+ case Q921_STATE_TEI_ASSIGNED:
+ /* send DL-RELEASE confirm */
+ Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
+ break;
+
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ case Q921_STATE_TIMER_RECOVERY:
+ if(!Q921_IS_NT(trunk)) {
+ /* Discard I queue */
+ MFIFOClear(link->IFrameQueue);
+
+ /* RC = 0 */
+ link->N200 = 0;
+
+ /* send DISC command */
+ Q921SendDISC(trunk, trunk->sapi, Q921_COMMAND(trunk), link->tei, 1);
+
+ /* Stop T203, restart T200 */
+ if(link->state == Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+ Q921T203TimerStop(trunk, link->tei);
+ }
+ Q921T200TimerReset(trunk, link->tei);
+
+ /* change state */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_RELEASE, link->tei);
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case Q921_DL_DATA: /* DL-DATA request */
+ res = Q921EnqueueI(trunk,
+ trunk->sapi,
+ Q921_COMMAND(trunk),
+ link->tei,
+ 0,
+ Mes,
+ Size);
+
+ if(link->state < Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+ /* Treat as implicit DL-ESTABLISH request */
+
+ /* establish data link */
+ Q921EstablishDataLink(trunk, link->tei);
+
+ /* Set layer 3 initiated */
+ Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
+ }
+ break;
+
+ case Q921_DL_UNIT_DATA: /* DL-UNIT DATA request */
+ res = Q921SendUN(trunk,
+ trunk->sapi,
+ Q921_COMMAND(trunk),
+ Q921_TEI_BCAST,
+ 0,
+ Mes,
+ Size);
+ /* NOTE: Let the other side initiate link establishment */
+ break;
+
+ default:
+ break;
+ }
+
+ return res;
+}
+/*****************************************************************************
+
+ Function: Q921SendRR
+
+ Description: Compose and send Receive Ready.
+
+ Parameters: trunk trunk #
+ Sapi Sapi
+ cr C/R field.
+ Tei Tei.
+ pf P/F fiels octet 5
+
+ Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+
+static int Q921SendRR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+ L2UCHAR mes[25];
+
+ return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x00, mes, trunk->Q921HeaderSpace+4);
+}
+
+/*****************************************************************************
+
+ Function: Q921SendRNR
+
+ Description: Compose and send Receive Nor Ready
+
+ Parameters: trunk trunk #
+ Sapi Sapi
+ cr C/R field.
+ Tei Tei.
+ pf P/F fiels octet 5
+
+ Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendRNR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+ L2UCHAR mes[25];
+
+ return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x01, mes, trunk->Q921HeaderSpace+4);
+}
+
+/*****************************************************************************
+
+ Function: Q921SendREJ
+
+ Description: Compose and Send Reject.
+
+ Parameters: trunk trunk #
+ Sapi Sapi
+ cr C/R field.
+ Tei Tei.
+ pf P/F fiels octet 5
+
+ Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendREJ(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+ L2UCHAR mes[25];
+
+ return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x03, mes, trunk->Q921HeaderSpace+4);
+}
+
+/*****************************************************************************
+
+ Function: Q921SendSABME
+
+ Description: Compose and send SABME
+
+ Parameters: trunk trunk #
+ Sapi Sapi
+ cr C/R field.
+ Tei Tei.
+ pf P fiels octet 4
+
+ Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendSABME(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+ L2UCHAR mes[25];
+
+ return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x0f, mes, trunk->Q921HeaderSpace+3);
+}
+
+
+/**
+ * Q921Start
+ * \brief Start trunk
+ * \param[in] trunk pointer to Q921 data struct
+ * \return > 0 on success; <= 0 on error
+ */
+int Q921Start(L2TRUNK trunk)
+{
+ int x, numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
+ struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+
+ if(trunk->initialized != INITIALIZED_MAGIC)
+ return 0;
+
+ memset(trunk->context, 0, numlinks * sizeof(struct Q921_Link));
+
+ /* Common init part */
+ for(x = 0; x <= numlinks; x++) {
+ link = Q921_LINK_CONTEXT(trunk, x);
+
+ link->state = Q921_STATE_TEI_UNASSIGNED;
+ link->tei = 0;
+
+ /* Initialize per-TEI I + UI queues */
+ MFIFOCreate(link->UIFrameQueue, Q921MAXHDLCSPACE, 10);
+ MFIFOCreate(link->IFrameQueue, Q921MAXHDLCSPACE, 10);
+ MFIFOCreate(link->IFrameResendQueue, Q921MAXHDLCSPACE, 10);
+ }
+
+ if(Q921_IS_PTMP_TE(trunk)) {
+ link->state = Q921_STATE_TEI_UNASSIGNED;
+ link->tei = 0;
+ }
+ else if(Q921_IS_PTMP_NT(trunk)) {
+ link = Q921_TRUNK_CONTEXT(trunk);
+
+ link->state = Q921_STATE_TEI_ASSIGNED;
+ link->tei = trunk->tei;
+
+ /* clear tei map */
+ memset(trunk->tei_map, 0, Q921_TEI_MAX + 1);
+ }
+ else {
+ link->state = Q921_STATE_TEI_ASSIGNED;
+ link->tei = trunk->tei;
+ }
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Starting trunk %p (sapi: %d, tei: %d, mode: %s %s)\n",
+ trunk,
+ trunk->sapi,
+ link->tei,
+ Q921_IS_PTMP(trunk) ? "PTMP" : "PTP",
+ Q921_IS_TE(trunk) ? "TE" : "NT");
+
+ if(Q921_IS_PTP(trunk)) {
+ Q921Log(trunk, Q921_LOG_DEBUG, "Sending SABME\n");
+
+ return Q921SendSABME(trunk,
+ trunk->sapi,
+ Q921_COMMAND(trunk),
+ link->tei,
+ 1);
+
+ } else if(Q921_IS_PTMP_NT(trunk)) {
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Revoking all TEIs\n");
+
+ return Q921TeiSendRemoveRequest(trunk, Q921_TEI_BCAST); /* Revoke all TEIs in use */
+ } else {
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Requesting TEI\n");
+
+ return Q921TeiSendAssignRequest(trunk);
+ }
+}
+
+
+/**
+ * Q921Stop
+ * \brief Stop trunk
+ * \param[in] trunk pointer to Q921 data struct
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+int Q921Stop(L2TRUNK trunk)
+{
+ struct Q921_Link *link;
+ int x, numlinks;
+
+ if(!trunk)
+ return -1;
+
+ link = Q921_TRUNK_CONTEXT(trunk);
+ numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
+
+ if(Q921_IS_STOPPED(link))
+ return 0;
+
+ /* Release TEI */
+ if(Q921_IS_PTMP_TE(trunk)) {
+ /* send verify request */
+ Q921TeiSendVerifyRequest(trunk);
+
+ /* drop TEI */
+ link->tei = 0;
+ }
+
+ /* Stop timers, stop link, flush queues */
+ for(x = 0; x <= numlinks; x++) {
+ Q921T200TimerStop(trunk, x);
+ Q921T203TimerStop(trunk, x);
+ Q921T201TimerStop(trunk, x);
+
+ /* Change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_STOPPED, x);
+
+ /* Flush per-tei I/UI queues */
+ MFIFOClear(link->UIFrameQueue);
+ MFIFOClear(link->IFrameQueue);
+ MFIFOClear(link->IFrameResendQueue);
+ }
+ Q921T202TimerStop(trunk);
+
+ /* Flush HDLC queue */
+ MFIFOClear(trunk->HDLCInQueue);
+
+ return 0;
+}
+
+
+/*****************************************************************************
+
+ Function: Q921SendDM
+
+ Description: Compose and Send DM (Disconnected Mode)
+
+ Parameters: trunk trunk #
+ Sapi Sapi
+ cr C/R field.
+ Tei Tei.
+ pf F fiels octet 4
+
+ Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendDM(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+ L2UCHAR mes[25];
+
+ return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x03, mes, trunk->Q921HeaderSpace+3);
+}
+
+/*****************************************************************************
+
+ Function: Q921SendDISC
+
+ Description: Compose and Send Disconnect
+
+ Parameters: trunk trunk #
+ Sapi Sapi
+ cr C/R field.
+ Tei Tei.
+ pf P fiels octet 4
+
+ Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendDISC(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+ L2UCHAR mes[25];
+
+ return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x08, mes, trunk->Q921HeaderSpace+3);
+}
+
+/*****************************************************************************
+
+ Function: Q921SendUA
+
+ Description: Compose and Send UA
+
+ Parameters: trunk trunk #
+ Sapi Sapi
+ cr C/R field.
+ Tei Tei.
+ pf F fiels octet 4
+
+ Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendUA(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+ L2UCHAR mes[25];
+
+ return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x0c, mes, trunk->Q921HeaderSpace+3);
+}
+
+static int Q921SendUN(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf, L2UCHAR *mes, L2INT size)
+{
+ return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x00, mes, size+trunk->Q921HeaderSpace+3);
+}
+
+
+/**
+ * Q921ProcSABME
+ * \brief Handle incoming SABME
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success, <= 0 on error
+ */
+static int Q921ProcSABME(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR pf = (mes[2] & 0x10) >> 4; /* poll / final flag */
+ L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_TEI_ASSIGNED:
+ /* send UA */
+ Q921SendUA(trunk,
+ trunk->sapi,
+ Q921_RESPONSE(trunk), /* or command? */
+ tei, pf);
+
+ /* clear counters */
+ link->vr=0;
+ link->vs=0;
+ link->va=0;
+
+ /* TODO: send DL-Establish indication to Q.931 */
+ Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
+
+ /* start T203 */
+ Q921T203TimerStart(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+ break;
+
+ case Q921_STATE_AWAITING_ESTABLISHMENT:
+ /* send UA */
+ Q921SendUA(trunk,
+ trunk->sapi,
+ Q921_RESPONSE(trunk),
+ tei, pf);
+
+ /* no state change */
+ break;
+
+ case Q921_STATE_AWAITING_RELEASE:
+ /* send DM */
+ Q921SendDM(trunk,
+ trunk->sapi,
+ Q921_RESPONSE(trunk),
+ tei, pf);
+
+ /* no state change */
+ break;
+
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ case Q921_STATE_TIMER_RECOVERY:
+ /* send UA */
+ Q921SendUA(trunk,
+ trunk->sapi,
+ Q921_RESPONSE(trunk),
+ tei, pf);
+
+ /* clear exception conditions */
+ Q921ResetExceptionConditions(trunk, tei);
+
+ /* send MDL-Error indication */
+
+ /* V(S) == V(A) ? */
+ if(link->vs != link->va) {
+ /* clear I queue */
+ MFIFOClear(link->IFrameQueue);
+
+ /* DL-Establish indication */
+ Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
+ }
+
+ /* clear counters */
+ link->vr=0;
+ link->vs=0;
+ link->va=0;
+
+ /* Stop T200, start T203 */
+ Q921T200TimerStop(trunk, tei);
+ Q921T203TimerStart(trunk, tei);
+
+ /* state change only if in TIMER_RECOVERY state */
+ if(link->state == Q921_STATE_TIMER_RECOVERY)
+ Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+ break;
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+
+/**
+ * Q921ProcDM
+ * \brief Handle incoming DM
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success, <= 0 on error
+ */
+static int Q921ProcDM(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR pf = (mes[2] & 0x10) >> 4; /* poll / final flag */
+ L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_TEI_ASSIGNED:
+ if(!pf) {
+ /* to next state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ case Q921_STATE_AWAITING_ESTABLISHMENT:
+ case Q921_STATE_AWAITING_RELEASE:
+ if(pf) {
+ if(link->state == Q921_STATE_AWAITING_ESTABLISHMENT) {
+ /* Discard I queue */
+ MFIFOClear(link->IFrameQueue);
+ }
+
+ /* Send DL-Release indication to Q.931 */
+ Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
+
+ /* Stop T200 */
+ Q921T200TimerStop(trunk, tei);
+
+ /* Change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+ }
+ break;
+
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ if(pf) {
+ /* MDL-Error indication (B) */
+
+ /* no state change */
+ } else {
+ /* MDL-Error indication (E) */
+
+ /* establish data link */
+ Q921EstablishDataLink(trunk, tei);
+
+ /* clear L3 initiated */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+ /* change state (no action?) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ case Q921_STATE_TIMER_RECOVERY:
+ if(pf) {
+ /* MDL Error indication (B) */
+ } else {
+ /* MDL Error indication (E) */
+ }
+
+ /* establish data link */
+ Q921EstablishDataLink(trunk, tei);
+
+ /* clear layer 3 initiated */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+ /* change state */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ break;
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+/**
+ * Q921ProcUA
+ * \brief Handle incoming UA
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success, <= 0 on error
+ */
+static int Q921ProcUA(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR pf = (mes[2] & 0x10) >> 4; /* poll / final flag */
+ L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_TEI_ASSIGNED:
+ case Q921_STATE_TIMER_RECOVERY:
+ /* MDL Error indication (C, D) */
+ Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame in invalid state\n");
+ break;
+
+ case Q921_STATE_AWAITING_ESTABLISHMENT:
+ if(pf) {
+ /* TODO: other fancy stuff (see docs) */
+ if(Q921_CHECK_FLAG(link, Q921_FLAG_L3_INITIATED)) { /* layer3 initiated */
+ link->vr = 0;
+
+ /* DL-Establish confirm */
+ Q921Tx23Proc(trunk, Q921_DL_ESTABLISH_CONFIRM, tei, NULL, 0);
+
+ } else if(link->vs != link->va) {
+
+ /* discard I queue */
+ MFIFOClear(link->IFrameQueue);
+
+ /* DL-Establish indication */
+ Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
+ }
+
+ /* Stop T200, start T203 */
+ Q921T200TimerStop(trunk, tei);
+ Q921T203TimerStart(trunk, tei);
+
+ link->vs = 0;
+ link->va = 0;
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+ } else {
+ /* MDL Error indication (C, D) */
+ Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame is not a response to a request\n");
+
+ /* no state change */
+ }
+ break;
+
+ case Q921_STATE_AWAITING_RELEASE:
+ if(pf) {
+ /* DL Release confirm */
+ Q921Tx23Proc(trunk, Q921_DL_RELEASE_CONFIRM, tei, NULL, 0);
+
+ /* Stop T200 */
+ Q921T200TimerStop(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+ } else {
+ /* MDL Error indication (D) */
+ Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame is not a response to a request\n");
+
+ /* no state change */
+ }
+ break;
+
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ /* MDL Error indication (C, D) */
+ Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame in invalid state\n");
+
+ /* no state change */
+ break;
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+
+/**
+ * Q921ProcDISC
+ * \brief Handle incoming DISC
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success, <= 0 on error
+ */
+static int Q921ProcDISC(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR pf = (mes[2] & 0x10) >> 4; /* poll / final flag */
+ L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_TEI_ASSIGNED:
+ case Q921_STATE_AWAITING_ESTABLISHMENT:
+ /* Send DM */
+ Q921SendDM(trunk,
+ trunk->sapi,
+ Q921_RESPONSE(trunk),
+ tei, pf);
+
+ /* no state change */
+ break;
+
+ case Q921_STATE_AWAITING_RELEASE:
+ Q921SendUA(trunk,
+ trunk->sapi,
+ Q921_RESPONSE(trunk),
+ tei, pf);
+
+ /* no state change */
+ break;
+
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ case Q921_STATE_TIMER_RECOVERY:
+ /* Discard I queue */
+ MFIFOClear(link->IFrameQueue);
+
+ /* send UA */
+ Q921SendUA(trunk,
+ trunk->sapi,
+ Q921_RESPONSE(trunk),
+ tei, pf);
+
+ /* DL Release indication */
+ Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
+
+ /* Stop T200 */
+ Q921T200TimerStop(trunk, tei);
+
+ if(link->state == Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+ /* Stop T203 */
+ Q921T203TimerStop(trunk, tei);
+ }
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+ break;
+
+ default:
+ Q921Log(trunk, Q921_LOG_ERROR, "Invalid DISC received in state \"%s\" (%d)", Q921State2Name(link->state), link->state);
+ break;
+ }
+
+ return 1;
+}
+
+
+/**
+ * Q921ProcRR
+ * \brief Handle incoming RR
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success, <= 0 on error
+ */
+static int Q921ProcRR(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR cr = (mes[0] & 0x02) >> 1;
+ L2UCHAR pf = mes[3] & 0x01; /* poll / final flag */
+ L2UCHAR nr = (mes[3] >> 1);
+// L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
+ L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ /* clear receiver peer busy */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+ if (Q921_IS_COMMAND(trunk, cr)) { /* if this is a command */
+ if(pf) {
+ /* Enquiry response */
+ Q921SendEnquiryResponse(trunk, tei);
+ }
+ } else {
+ if(pf) {
+ /* MDL Error indication */
+ }
+ }
+
+ /* */
+ if(link->va <= nr && nr <= link->vs) {
+
+ if(nr == link->vs) {
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ /* Stop T200, restart T203 */
+ Q921T200TimerStop(trunk, tei);
+ Q921T203TimerReset(trunk, tei);
+
+ } else if(nr == link->va) {
+
+ /* do nothing */
+
+ } else {
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ /* Restart T200 */
+ Q921T200TimerReset(trunk, tei);
+ }
+ /* no state change */
+
+ } else {
+ /* N(R) Error recovery */
+ Q921NrErrorRecovery(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ case Q921_STATE_TIMER_RECOVERY:
+ /* clear receiver peer busy */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+ /* command + P? */
+ if(Q921_IS_COMMAND(trunk, cr) && pf) {
+ /* Enquiry response */
+ Q921SendEnquiryResponse(trunk, tei);
+ }
+
+ /* */
+ if(link->va <= nr && nr <= link->vs) {
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ if(!Q921_IS_COMMAND(trunk, cr) && pf) {
+ /* Stop T200, start T203 */
+ Q921T200TimerStop(trunk, tei);
+ Q921T203TimerStart(trunk, tei);
+
+ /* Invoke retransmission */
+ Q921InvokeRetransmission(trunk, tei, nr);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+ }
+ /* no state change otherwise */
+ } else {
+ /* N(R) Error recovery */
+ Q921NrErrorRecovery(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return 1;
+}
+
+
+/**
+ * Q921ProcREJ
+ * \brief Handle incoming REJ
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success, <= 0 on error
+ */
+static int Q921ProcREJ(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR cr = (mes[0] & 0x02) >> 1;
+ L2UCHAR pf = mes[3] & 0x01; /* poll / final flag */
+ L2UCHAR nr = (mes[3] >> 1);
+// L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
+ L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ /* clear receiver peer busy */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+ /* command? */
+ if(Q921_IS_COMMAND(trunk, cr)) {
+ if(pf) {
+ /* Enquiry response */
+ Q921SendEnquiryResponse(trunk, tei);
+ }
+ } else {
+ if(pf) {
+ /* MDL Error indication (A) */
+ }
+ }
+
+ /* */
+ if(link->va <= nr && nr <= link->vs) {
+
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ /* Stop T200, start T203 */
+ Q921T200TimerStop(trunk, tei);
+ Q921T203TimerStart(trunk, tei);
+
+ /* Invoke retransmission of frame >N(R) (?) */
+ Q921InvokeRetransmission(trunk, tei, nr);
+
+ /* no state change */
+ } else {
+ /* N(R) Error recovery */
+ Q921NrErrorRecovery(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ case Q921_STATE_TIMER_RECOVERY:
+ /* clear receiver peer busy */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+ /* command + P ? */
+ if(Q921_IS_COMMAND(trunk, cr) && pf) {
+ /* Enquiry response */
+ Q921SendEnquiryResponse(trunk, tei);
+ }
+
+ /* */
+ if(link->va <= nr && nr <= link->vs) {
+
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ if(!Q921_IS_COMMAND(trunk, cr) && pf) {
+ /* Stop T200, start T203 */
+ Q921T200TimerStop(trunk, tei);
+ Q921T203TimerStart(trunk, tei);
+
+ /* Invoke retransmission */
+ Q921InvokeRetransmission(trunk, tei, nr);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+ }
+ /* no state change otherwise */
+ } else {
+ /* N(R) Error recovery */
+ Q921NrErrorRecovery(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+
+/**
+ * Q921ProcRNR
+ * \brief Handle incoming RNR
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success, <= 0 on error
+ */
+static int Q921ProcRNR(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR cr = (mes[0] & 0x02) >> 1;
+ L2UCHAR pf = mes[3] & 0x01; /* poll / final flag */
+ L2UCHAR nr = (mes[3] >> 1);
+// L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
+ L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ /* set peer receiver busy */
+ Q921_SET_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+ /* command? */
+ if(Q921_IS_COMMAND(trunk, cr)) {
+ if(pf) {
+ /* Enquiry response */
+ Q921SendEnquiryResponse(trunk, tei);
+ }
+ } else {
+ if(pf) {
+ /* MDL Error indication (A) */
+ }
+ }
+
+ /* */
+ if(link->va <= nr && nr <= link->vs) {
+
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ /* Stop T203, restart T200 */
+ Q921T200TimerReset(trunk, tei);
+ Q921T203TimerStop(trunk, tei);
+
+ /* no state change */
+ } else {
+ /* N(R) Error recovery */
+ Q921NrErrorRecovery(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ case Q921_STATE_TIMER_RECOVERY:
+ /* set peer receiver busy */
+ Q921_SET_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+ /* command + P? */
+ if(Q921_IS_COMMAND(trunk, cr) && pf) {
+ /* Enquiry response */
+ Q921SendEnquiryResponse(trunk, tei);
+ }
+
+ /* */
+ if(link->va <= nr && nr <= link->vs) {
+
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ if(!Q921_IS_COMMAND(trunk, cr) && pf) {
+ /* Restart T200 */
+ Q921T200TimerReset(trunk, tei);
+
+ /* Invoke retransmission */
+ Q921InvokeRetransmission(trunk, tei, nr);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+ }
+ /* no state change otherwise */
+ } else {
+ /* N(R) Error recovery */
+ Q921NrErrorRecovery(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+#if 0
+static int Q921SetReceiverBusy(L2TRUNK trunk)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ if(!Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+ /* set own receiver busy */
+ Q921_SET_FLAG(link, Q921_FLAG_RECV_BUSY);
+
+ /* send RR response */
+ Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
+
+ /* clear ack pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+ }
+ break;
+
+ case Q921_STATE_TIMER_RECOVERY:
+ if(!Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+ /* set own receiver busy */
+ Q921_SET_FLAG(link, Q921_FLAG_RECV_BUSY);
+
+ /* send RNR response */
+ Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
+
+ /* clear ack pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int Q921ClearReceiverBusy(L2TRUNK trunk)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ switch(link->state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ case Q921_STATE_TIMER_RECOVERY:
+ if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+ /* clear own receiver busy */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_RECV_BUSY);
+
+ /* send RNR response */
+ Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
+
+ /* clear ack pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+#endif
+
+static int Q921ProcIFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ /* common fields: get sapi, tei and cr */
+// L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
+// L2UCHAR cr = (mes[0] & 0x02) >> 1;
+ L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+ L2UCHAR pf = mes[3] & 0x01; /* poll / final flag */
+ L2UCHAR nr = mes[3] >> 1; /* receive sequence number */
+ L2UCHAR ns = mes[2] >> 1; /* send sequence number */
+ L2UCHAR discard = 0;
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ /* Ignore I frames in earlier states */
+ if(link->state < Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+ Q921Log(trunk, Q921_LOG_NOTICE, "I frame in invalid state ignored\n");
+ return 0;
+ }
+
+ /* Receiver busy? */
+ if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+ /* discard information */
+ discard = 1;
+
+ if(pf) {
+ /* send RNR Response */
+ Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+
+ /* Clear ack pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+ }
+ }
+ else {
+ if(ns != link->vr) {
+ /* discard information */
+ discard = 1;
+
+ if(Q921_CHECK_FLAG(link, Q921_FLAG_REJECT) && pf) {
+
+ /* Send RR response */
+ Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+
+ /* clear ack pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+ }
+ else if(!Q921_CHECK_FLAG(link, Q921_FLAG_REJECT)){
+
+ /* set reject exception */
+ Q921_SET_FLAG(link, Q921_FLAG_REJECT);
+
+ /* Send REJ response */
+ Q921SendREJ(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, pf);
+
+ /* clear ack pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+ }
+ }
+ else {
+ /* V(R) = V(R) + 1 */
+ Q921_INC_COUNTER(link->vr);
+
+ /* clear reject exception */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_REJECT);
+
+ /* DL-Data indication */
+ Q921Tx23Proc(trunk, Q921_DL_DATA, tei, mes, size);
+
+ if(pf) {
+ /* Send RR response */
+ Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+
+ /* clear ack pending */
+ Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+ }
+ else if(!Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING)) {
+ /* ack pending */
+
+ /* Send RR response */
+ Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 0);
+
+ /* set ack pending*/
+ Q921_SET_FLAG(link, Q921_FLAG_ACK_PENDING);
+ }
+ }
+ }
+
+
+ switch(link->state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ if(link->va <= nr && nr <= link->vs) {
+ if(Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
+ link->va = nr;
+ }
+ else if(nr == link->vs) {
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ /* stop t200, restart t203 */
+ Q921T200TimerStop(trunk, tei);
+ Q921T203TimerReset(trunk, tei);
+ }
+ else if(nr != link->va) {
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ /* restart T200 */
+ Q921T200TimerReset(trunk, tei);
+ }
+
+ /* Restart TM01 */
+ if(Q921_IS_NT(trunk)) {
+ Q921TM01TimerReset(trunk, tei);
+ }
+ }
+ else {
+ /* N(R) error recovery */
+ Q921NrErrorRecovery(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ case Q921_STATE_TIMER_RECOVERY:
+ if(link->va <= nr && nr <= link->vs) {
+ /* V(A) = N(R) */
+ link->va = nr;
+
+ /* Restart TM01 */
+ if(Q921_IS_NT(trunk)) {
+ Q921TM01TimerReset(trunk, tei);
+ }
+ }
+ else {
+ /* N(R) error recovery */
+ Q921NrErrorRecovery(trunk, tei);
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+static int Q921ProcSFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR sv = (mes[2] & 0x0c) >> 2; /* supervisory format id */
+ //L2UCHAR pf = mes[3] & 0x01; /* poll / final flag */
+ //L2UCHAR nr = mes[3] >> 1; /* receive sequence number */
+ L2INT res = -1;
+
+ switch(sv) {
+ case 0x00: /* RR : Receive Ready */
+ res = Q921ProcRR(trunk, mes, size);
+ break;
+
+ case 0x02: /* RNR : Receive Not Ready */
+ res = Q921ProcRNR(trunk, mes, size);
+ break;
+
+ case 0x04: /* REJ : Reject */
+ res = Q921ProcREJ(trunk, mes, size);
+ break;
+
+ default: /* Invalid / Unknown */
+ Q921Log(trunk, Q921_LOG_ERROR, "Invalid S frame type %d\n", sv);
+ break;
+ }
+
+ return res;
+}
+
+
+
+static int Q921ProcUFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR m = (mes[2] & 0xe0) >> 3 | (mes[2] & 0x0c) >> 2; /* modifier function id */
+// L2UCHAR pf = (mes[2] & 0x10) >> 4; /* poll / final flag */
+ L2INT res = -1;
+
+ switch(m) {
+ case 0x00: /* UN : Unnumbered Information */
+ if(mes[3] == Q921_LAYER_ENT_ID_TEI)
+ {
+ if(!Q921_IS_PTMP(trunk)) {
+ /* wtf? nice try */
+ return res;
+ }
+
+ switch(mes[6]) {
+ case Q921_TEI_ID_REQUEST: /* (TE ->) NT */
+ res = Q921TeiProcAssignRequest(trunk, mes, size);
+ break;
+
+ case Q921_TEI_ID_ASSIGNED: /* (NT ->) TE */
+ case Q921_TEI_ID_DENIED:
+ res = Q921TeiProcAssignResponse(trunk, mes, size);
+ break;
+
+ case Q921_TEI_ID_CHECKREQ: /* (NT ->) TE */
+ res = Q921TeiProcCheckRequest(trunk, mes, size);
+ break;
+
+ case Q921_TEI_ID_CHECKRESP: /* (TE ->) NT */
+ res = Q921TeiProcCheckResponse(trunk, mes, size);
+ break;
+
+ case Q921_TEI_ID_REMOVE: /* (NT ->) TE */
+ res = Q921TeiProcRemoveRequest(trunk, mes, size);
+ break;
+
+ case Q921_TEI_ID_VERIFY: /* (TE ->) NT */
+ res = Q921TeiProcVerifyRequest(trunk, mes, size);
+ break;
+
+ default: /* Invalid / Unknown */
+ Q921Log(trunk, Q921_LOG_ERROR, "Invalid UN message from TEI management/endpoint\n");
+ break;
+ }
+ }
+ else if(mes[3] == Q921_LAYER_ENT_ID_Q931) {
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "UI Frame for Layer 3 received\n");
+
+ res = Q921Tx23Proc(trunk, Q921_DL_UNIT_DATA, 0, mes, size);
+ }
+ break;
+
+ case 0x03: /* DM : Disconnect Mode */
+ res = Q921ProcDM(trunk, mes, size);
+ break;
+
+ case 0x08: /* DISC : Disconnect */
+ res = Q921ProcDISC(trunk, mes, size);
+ break;
+
+ case 0x0c: /* UA : Unnumbered Acknowledgement */
+ res = Q921ProcUA(trunk, mes, size);
+ break;
+
+ case 0x0f: /* SABME : Set Asynchronous Balanced Mode Extend */
+ res = Q921ProcSABME(trunk, mes, size);
+ break;
+
+ case 0x11: /* FRMR : Frame Reject */
+ case 0x17: /* XID : Exchange Identification */
+ res = 0;
+ break;
+
+ default: /* Unknown / Invalid */
+ Q921Log(trunk, Q921_LOG_ERROR, "Invalid U frame type: %d\n", m);
+ break;
+ }
+
+ return res;
+}
+
+
+/*****************************************************************************
+
+ Function: Q921Rx12
+
+ Description: Called to process a message frame from layer 1. Will
+ identify the message and call the proper 'processor' for
+ layer 2 messages and forward I frames to the layer 3 entity.
+
+ Q921Rx12 will check the input fifo for a message, and if a
+ message exist process one message before it exits. The caller
+ must either call Q921Rx12 polling or keep track on #
+ messages in the queue.
+
+ Parameters: trunk trunk #.
+
+ Return Value: # messages processed (always 1 or 0).
+
+*****************************************************************************/
+int Q921Rx12(L2TRUNK trunk)
+{
+ L2INT size; /* receive size & Q921 frame size*/
+ L2UCHAR *smes = MFIFOGetMesPtr(trunk->HDLCInQueue, &size);
+
+ if(smes)
+ {
+ struct Q921_Link *link;
+ L2UCHAR sapi, tei;
+ L2UCHAR *mes;
+ L2INT rs;
+
+ rs = size - trunk->Q921HeaderSpace;
+ mes = &smes[trunk->Q921HeaderSpace];
+
+ Q921LogMesg(trunk, Q921_LOG_DEBUG, 1, mes, rs, "New packet received (%d bytes)", rs);
+
+ /* common fields: get sapi, tei and cr */
+ sapi = (mes[0] & 0xfc) >> 2;
+ tei = (mes[1] & 0xfe) >> 1;
+ link = Q921_LINK_CONTEXT(trunk, tei);
+
+ if(Q921_IS_PTMP_TE(trunk) && (
+ (link->state >= Q921_STATE_TEI_ASSIGNED && tei != link->tei && tei != Q921_TEI_BCAST) || /* Assigned TEI: Only BCAST and directed */
+ (link->state == Q921_STATE_TEI_UNASSIGNED && tei != Q921_TEI_BCAST))) /* No assigned TEI: Only BCAST */
+ {
+ /* Ignore Messages with foreign TEIs */
+ goto out;
+ }
+
+ if((mes[2] & 0x01) == 0x00) { /* I frame */
+ Q921ProcIFrame(trunk, mes, rs);
+ }
+ else if((mes[2] & 0x03) == 0x01) { /* S frame */
+ Q921ProcSFrame(trunk, mes, rs);
+ }
+ else if((mes[2] & 0x03) == 0x03) { /* U frame */
+ Q921ProcUFrame(trunk, mes, rs);
+ }
+ else {
+ Q921Log(trunk, Q921_LOG_ERROR, "Invalid frame type: %d\n", (int)(mes[2] & 0x03));
+ /* TODO: send FRMR or REJ */
+ }
+
+out:
+ MFIFOKillNext(trunk->HDLCInQueue);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Misc
+ */
+/**
+ * Q921SetLogCB
+ * \brief Set logging callback
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] func pointer to logging callback function
+ * \param[in] priv pointer to private data
+ *
+ * \author Stefan Knoblich
+ */
+void Q921SetLogCB(L2TRUNK trunk, Q921LogCB_t func, void *priv)
+{
+ if(!trunk)
+ return;
+
+ trunk->Q921LogProc = func;
+ trunk->PrivateDataLog = priv;
+}
+
+/**
+ * Q921SetLogLevel
+ * \brief Set loglevel of Q.921 logging functions
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] level new loglevel
+ *
+ * \author Stefan Knoblich
+ */
+void Q921SetLogLevel(L2TRUNK trunk, Q921LogLevel_t level)
+{
+ if(!trunk)
+ return;
+
+ if (level < Q921_LOG_NONE) {
+ level = Q921_LOG_NONE;
+ } else if (level > Q921_LOG_DEBUG) {
+ level = Q921_LOG_DEBUG;
+ }
+
+ trunk->loglevel = level;
+}
+
+
+/**
+ * Q921ChangeState
+ * \brief Change state, invoke neccessary actions
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] state state to change to
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921ChangeState(L2TRUNK trunk, Q921State_t state, L2UCHAR tei)
+{
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+ Q921State_t oldstate = link->state;
+ int res = 0;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Changing state from \"%s\" (%d) to \"%s\" (%d) for TEI %d\n",
+ Q921State2Name(oldstate), oldstate,
+ Q921State2Name(state), state,
+ tei);
+
+ /*
+ * generic actions (depending on the target state only)
+ */
+ switch(state) {
+ case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+ /* Start TM01 */
+ if(Q921_IS_NT(trunk)) {
+ Q921TM01TimerStart(trunk, tei);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * actions that depend on type of the old -> new state transition
+ */
+ switch(oldstate) {
+ case Q921_STATE_STOPPED:
+
+ switch(state) {
+ case Q921_STATE_TEI_UNASSIGNED:
+ if(Q921_IS_PTMP_TE(trunk)) {
+ res = Q921TeiSendAssignRequest(trunk);
+ }
+ break;
+
+ case Q921_STATE_TEI_ASSIGNED:
+ if(Q921_IS_PTMP_NT(trunk)) {
+ res = Q921TeiSendRemoveRequest(trunk, Q921_TEI_BCAST);
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ link->state = state;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Q921ChangeState() returns %d, new state is \"%s\" (%d) for TEI %d\n", res, Q921State2Name(state), state, tei);
+
+ return res;
+}
+
+/*
+ * TEI Management functions
+ * \note All TEI-mgmt UN frames are sent with cr = command!
+ */
+static int Q921TeiSend(L2TRUNK trunk, L2UCHAR type, L2USHORT ri, L2UCHAR ai)
+{
+ L2UCHAR mes[10];
+ L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+
+ mes[offset++] = Q921_LAYER_ENT_ID_TEI; /* layer management entity identifier */
+ mes[offset++] = (ri & 0xff00) >> 8; /* reference number upper part */
+ mes[offset++] = ri & 0xff; /* reference number lower part */
+ mes[offset++] = type; /* message type: Identity Request */
+ mes[offset++] = ai << 1 | 0x01; /* action indicator: TEI */
+
+ return Q921SendU(trunk, Q921_SAPI_TEI, Q921_COMMAND(trunk), Q921_TEI_BCAST, 0, 0x00, mes, offset);
+}
+
+
+/**
+ * Q921TeiSendAssignRequest
+ * \brief Ask for new TEI (TE mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \return > 0 on success, <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiSendAssignRequest(L2TRUNK trunk)
+{
+ struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+ L2INT res;
+
+ if (!Q921_IS_PTMP_TE(trunk)) /* only ptmp te mode*/
+ return 0;
+
+#ifndef WIN32
+ link->ri = (L2USHORT)(random() % 0xffff);
+#else
+ link->ri = (L2USHORT)(rand() % 0xffff); //todo
+#endif
+
+ /* send TEI assign request */
+ res = Q921TeiSend(trunk, Q921_TEI_ID_REQUEST, link->ri, Q921_TEI_BCAST);
+
+ /* start T202 */
+ Q921T202TimerStart(trunk);
+
+ return res;
+}
+
+
+/**
+ * Q921TeiProcessAssignResponse
+ * \brief Process assign response (TE mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiProcAssignResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+ L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+ L2USHORT ri = 0;
+
+ if (!Q921_IS_PTMP_TE(trunk)) /* PTMP TE only */
+ return 0;
+
+ ri = (mes[offset + 1] << 8) | mes[offset + 2];
+
+ if(ri != link->ri) {
+ /* hmmm ..., not our response i guess */
+ return 0;
+ }
+
+ switch(mes[offset + 3]) {
+ case Q921_TEI_ID_ASSIGNED:
+ /* Yay, use the new TEI and change state to assigned */
+ link->tei = mes[offset + 4] >> 1;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Assigned TEI %d, setting state to TEI_ASSIGNED\n", link->tei);
+
+ Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, link->tei);
+ break;
+
+ case Q921_TEI_ID_DENIED:
+ /* oops, what to do now? */
+ if ((mes[offset + 4] >> 1) == Q921_TEI_BCAST) {
+ /* No more free TEIs? this is bad */
+
+ //Q921TeiSendVerifyRequest(trunk, Q921_TEI_BCAST); /* TODO: does this work ?? */
+ } else {
+ /* other reason, this is fatal, shutdown link */
+ }
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "TEI assignment has been denied, reason: %s\n",
+ ((mes[offset +4] >> 1) == Q921_TEI_BCAST) ? "No free TEIs available" : "Unknown");
+
+ Q921ChangeState(trunk, Q921_STATE_TEI_UNASSIGNED, link->tei);
+ break;
+
+ default:
+ return 0;
+ }
+
+ /* stop T202 */
+ Q921T202TimerStop(trunk);
+
+ return 1;
+}
+
+
+/**
+ * Q921TeiSendVerifyRequest
+ * \brief Verify TEI (TE mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiSendVerifyRequest(L2TRUNK trunk)
+{
+ struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+ L2INT res;
+
+ if (!Q921_IS_PTMP_TE(trunk)) /* only ptmp te mode*/
+ return 0;
+
+ /* Request running? */
+ if (trunk->T202)
+ return 0;
+
+ /* Send TEI verify request */
+ res = Q921TeiSend(trunk, Q921_TEI_ID_VERIFY, link->ri, link->tei);
+
+ /* start T202 */
+ Q921T202TimerStart(trunk);
+
+ return res;
+}
+
+
+/**
+ * Q921TeiProcCheckRequest
+ * \brief Process Check Request (TE mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiProcCheckRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+ L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+ L2UCHAR tei = (mes[offset + 4] >> 1); /* action indicator => tei */
+ L2INT res = 0;
+
+ if (!Q921_IS_PTMP_TE(trunk)) /* ptmp te mode only */
+ return 0;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Received TEI Check request for TEI %d\n", tei);
+
+ if (tei == Q921_TEI_BCAST || tei == link->tei) {
+ /*
+ * Broadcast TEI check or for our assigned TEI
+ */
+
+ /* send TEI check reponse */
+ res = Q921TeiSend(trunk, Q921_TEI_ID_CHECKRESP, link->ri, link->tei);
+
+ Q921T202TimerStop(trunk);
+ }
+
+ return res;
+}
+
+
+/**
+ * Q921TeiProcRemoveRequest
+ * \brief Process remove Request (TE mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiProcRemoveRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+ L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+ L2UCHAR tei = (mes[offset + 4] >> 1); /* action indicator => tei */
+ L2INT res = 0;
+
+ if (!Q921_IS_PTMP_TE(trunk)) /* ptmp te mode only */
+ return 0;
+
+ Q921Log(trunk, Q921_LOG_DEBUG, "Received TEI Remove request for TEI %d\n", tei);
+
+ if (tei == Q921_TEI_BCAST || tei == link->tei) {
+ /*
+ * Broadcast TEI remove or for our assigned TEI
+ */
+
+ /* reset tei */
+ link->tei = 0;
+
+ /* change state (no action) */
+ Q921ChangeState(trunk, Q921_STATE_TEI_UNASSIGNED, link->tei);
+
+ /* TODO: hmm, request new one ? */
+ res = Q921TeiSendAssignRequest(trunk);
+ }
+ return res;
+}
+
+
+/**
+ * Q921TeiProcAssignRequest
+ * \brief Process assign request from peer (NT mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiProcAssignRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+ L2USHORT ri = 0;
+ L2UCHAR tei = 0;
+
+ if (!Q921_IS_PTMP_NT(trunk)) /* PTMP NT only */
+ return 0;
+
+ ri = (mes[offset + 1] << 8) | mes[offset + 2];
+ tei = mes[offset + 4] >> 1;
+
+ if(tei == Q921_TEI_BCAST) {
+ int x;
+
+ /* dynamically allocate TEI */
+ for(x = Q921_TEI_DYN_MIN, tei = 0; x <= Q921_TEI_MAX; x++) {
+ if(!trunk->tei_map[x]) {
+ tei = x;
+ break;
+ }
+ }
+ }
+ else if(!(tei > 0 && tei < Q921_TEI_DYN_MIN)) {
+ /* reject TEIs that are not in the static area */
+ Q921TeiSendDenyResponse(trunk, 0, ri);
+
+ return 0;
+ }
+
+ if(!tei) {
+ /* no free TEI found */
+ Q921TeiSendDenyResponse(trunk, Q921_TEI_BCAST, ri);
+ }
+ else {
+ struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+ /* mark used */
+ trunk->tei_map[tei] = 1;
+
+ /* assign tei */
+ link->tei = tei;
+
+ /* put context in TEI ASSIGNED state */
+ Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+
+ /* send assign response */
+ Q921TeiSendAssignedResponse(trunk, tei, ri);
+
+ /* Start T201 */
+ Q921T201TimerStart(trunk, tei);
+ }
+ return 0;
+}
+
+/**
+ * Q921TeiSendCheckRequest
+ * \brief Send check request (NT mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] tei TEI to check
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiSendCheckRequest(L2TRUNK trunk, L2UCHAR tei)
+{
+ L2INT res = 0;
+
+ if (!Q921_IS_PTMP_NT(trunk)) /* PTMP NT only */
+ return 0;
+
+ /* send TEI check request */
+ res = Q921TeiSend(trunk, Q921_TEI_ID_CHECKREQ, 0, tei);
+
+ /* (Re-)Start T201 timer */
+ Q921T201TimerStart(trunk, tei);
+
+ return res;
+}
+
+/**
+ * Q921TeiProcCheckResponse
+ * \brief Process Check Response (NT mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiProcCheckResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ struct Q921_Link *link;
+ L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+ L2USHORT ri = 0;
+ L2UCHAR tei = 0;
+
+ if (!Q921_IS_PTMP_NT(trunk)) /* PTMP NT mode only */
+ return 0;
+
+ ri = (mes[offset + 1] << 8) | mes[offset + 2];
+ tei = mes[offset + 4] >> 1;
+
+ /* restart T201 */
+ Q921T201TimerStop(trunk, tei);
+
+ /* reset counter */
+ link = Q921_LINK_CONTEXT(trunk, tei);
+ link->N202 = 0;
+
+ if(!(tei > 0 && tei < Q921_TEI_MAX) || !trunk->tei_map[tei]) {
+ /* TODO: Should we send a DISC first? */
+
+ /* TEI not assigned? Invalid TEI? */
+ Q921TeiSendRemoveRequest(trunk, tei);
+
+ /* change state */
+ Q921ChangeState(trunk, Q921_STATE_STOPPED, tei);
+
+ /* clear */
+ memset(link, 0, sizeof(struct Q921_Link));
+ } else {
+ /* Start T201 */
+ Q921T201TimerStart(trunk, tei);
+ }
+
+ return 0;
+}
+
+
+/**
+ * Q921TeiProcVerifyRequest
+ * \brief Process Verify Request (NT mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] mes pointer to message buffer
+ * \param[in] size size of message
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiProcVerifyRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+ L2UCHAR resp[25];
+ L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+ L2UCHAR tei = 0;
+
+ if (!Q921_IS_PTMP_NT(trunk)) /* PTMP NT mode only */
+ return 0;
+
+ tei = mes[offset + 4] >> 1;
+
+ /* todo: handle response... verify assigned TEI */
+ resp[offset + 0] = 0;
+
+ return 0;
+}
+
+/**
+ * Q921TeiSendDenyResponse
+ * \brief Send Deny Response (NT mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiSendDenyResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri)
+{
+ if (!Q921_IS_PTMP_NT(trunk)) /* PTMP NT only */
+ return 0;
+
+ return Q921TeiSend(trunk, Q921_TEI_ID_DENIED, ri, tei);
+}
+
+
+/**
+ * Q921TeiSendAssignedResponse
+ * \brief Send Assigned Response (NT mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] tei TEI to assign
+ * \param[in] ri RI of request
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiSendAssignedResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri)
+{
+ if (!Q921_IS_PTMP_NT(trunk)) /* PTMP NT only */
+ return 0;
+
+ return Q921TeiSend(trunk, Q921_TEI_ID_ASSIGNED, ri, tei);
+}
+
+/**
+ * Q921TeiSendRemoveRequest
+ * \brief Send Remove Request (NT mode only)
+ * \param[in] trunk pointer to Q921 data struct
+ * \param[in] tei TEI to remove
+ * \return > 0 on success; <= 0 on error
+ *
+ * \author Stefan Knoblich
+ */
+static int Q921TeiSendRemoveRequest(L2TRUNK trunk, L2UCHAR tei)
+{
+ if (!Q921_IS_PTMP_NT(trunk)) /* PTMP NT only */
+ return 0;
+
+ return Q921TeiSend(trunk, Q921_TEI_ID_REMOVE, 0, tei);
+}
Added: freeswitch/trunk/libs/openzap/src/isdn/Q931.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/Q931.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/Q931.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,888 @@
+/*****************************************************************************
+
+ FileName: Q931.c
+
+ Contents: Implementation of Q.931 stack main interface functions.
+ See q931.h for description.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "Q921.h"
+#include "Q931.h"
+#include "national.h"
+#include "DMS.h"
+#include "5ESS.h"
+
+
+/*****************************************************************************
+
+ Dialect function pointers tables.
+
+ The following function pointer arrays define pack/unpack functions and
+ processing furnctions for the different Q.931 based dialects.
+
+ The arrays are initialized with pointers to dummy functions and later
+ overrided with pointers to actual functions as new dialects are added.
+
+ The initial Q.931 will as an example define 2 dialects as it treats User
+ and Network mode as separate ISDN dialects.
+
+ The API messages Q931AddProc, Q931AddMes, Q931AddIE are used to initialize
+ these table entries during system inititialization of a stack.
+
+*****************************************************************************/
+q931proc_func_t *Q931Proc[Q931MAXDLCT][Q931MAXMES];
+
+q931umes_func_t *Q931Umes[Q931MAXDLCT][Q931MAXMES];
+q931pmes_func_t *Q931Pmes[Q931MAXDLCT][Q931MAXMES];
+
+q931uie_func_t *Q931Uie[Q931MAXDLCT][Q931MAXIE];
+q931pie_func_t *Q931Pie[Q931MAXDLCT][Q931MAXIE];
+
+q931timeout_func_t *Q931Timeout[Q931MAXDLCT][Q931MAXTIMER];
+q931timer_t Q931Timer[Q931MAXDLCT][Q931MAXTIMER];
+
+void (*Q931CreateDialectCB[Q931MAXDLCT])(L3UCHAR iDialect) = { NULL, NULL };
+
+Q931State Q931st[Q931MAXSTATE];
+
+/*****************************************************************************
+
+ Core system tables and variables.
+
+*****************************************************************************/
+
+L3INT Q931L4HeaderSpace = {0}; /* header space to be ignoder/inserted */
+ /* at head of each message. */
+
+L3INT Q931L2HeaderSpace = {4}; /* Q921 header space, sapi, tei etc */
+
+/*****************************************************************************
+
+ Main interface callback functions.
+
+*****************************************************************************/
+
+Q931ErrorCB_t Q931ErrorProc; /* callback for error messages. */
+L3ULONG (*Q931GetTimeProc) (void) = NULL; /* callback for func reading time in ms */
+
+/*****************************************************************************
+
+ Function: Q931SetL4HeaderSpace
+
+ Description: Set the # of bytes to be inserted/ignored at the head of
+ each message. Q931 will issue a message with space for header
+ and the user will use this to fill in whatever header info
+ is required to support the architecture used.
+
+*****************************************************************************/
+void Q931SetL4HeaderSpace(L3INT space)
+{
+ Q931L4HeaderSpace = space;
+}
+
+/*****************************************************************************
+
+ Function: Q931SetL2HeaderSpace
+
+ Description: Set the # of bytes to be inserted/ignored at the head of
+ each message. Q931 will issue a message with space for header
+ and the user will use this to fill in whatever header info
+ is required to support the architecture used.
+
+*****************************************************************************/
+void Q931SetL2HeaderSpace(L3INT space)
+{
+ Q931L2HeaderSpace = space;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcDummy
+
+ Description: Dummy function for message processing.
+
+*****************************************************************************/
+L3INT Q931ProcDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b,L3INT c)
+{
+ return Q931E_INTERNAL;
+}
+
+/*****************************************************************************
+
+ Function: Q931UmesDummy
+
+ Description: Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931UmesDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size)
+{
+ return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+ Function: Q931UieDummy
+
+ Description: Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931UieDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ return Q931E_UNKNOWN_IE;
+}
+
+/*****************************************************************************
+
+ Function: Q931PmesDummy
+
+ Description: Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931PmesDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+ Function: Q931PieDummy
+
+ Description: Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931PieDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ return Q931E_UNKNOWN_IE;
+}
+
+/*****************************************************************************
+
+ Function: Q931TxDummy
+
+ Description: Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931TxDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT n)
+{
+ return Q931E_MISSING_CB;
+}
+
+/*****************************************************************************
+
+ Function: Q931ErrorDummy
+
+ Description: Dummy function for error processing
+
+*****************************************************************************/
+L3INT Q931ErrorDummy(void *priv, L3INT a, L3INT b, L3INT c)
+{
+ return 0;
+}
+
+/*****************************************************************************
+
+ Function: Q931Initialize
+
+ Description: This function Initialize the stack.
+
+ Will set up the trunk array, channel
+ arrays and initialize Q931 function arrays before it finally
+ set up EuroISDN processing with User as dialect 0 and
+ Network as dialect 1.
+
+ Note: Initialization of other stacks should be inserted after
+ the initialization of EuroISDN.
+
+*****************************************************************************/
+void Q931Initialize()
+{
+ L3INT x,y;
+
+ /* Secure the callbacks to default procs */
+ Q931ErrorProc = Q931ErrorDummy;
+
+ /* The user will only add the message handlers and IE handlers he need,
+ * so we need to initialize every single entry to a default function
+ * that will throw an appropriate error if they are ever called.
+ */
+ for (x = 0; x < Q931MAXDLCT; x++) {
+ for (y = 0; y < Q931MAXMES; y++) {
+ Q931Proc[x][y] = Q931ProcDummy;
+ Q931Umes[x][y] = Q931UmesDummy;
+ Q931Pmes[x][y] = Q931PmesDummy;
+ }
+ for (y = 0; y < Q931MAXIE; y++) {
+ Q931Pie[x][y] = Q931PieDummy;
+ Q931Uie[x][y] = Q931UieDummy;
+ }
+ for (y = 0; y < Q931MAXTIMER; y++) {
+ Q931Timeout[x][y] = Q931TimeoutDummy;
+ Q931Timer[x][y] = 0;
+ }
+ }
+
+ if (Q931CreateDialectCB[Q931_Dialect_Q931 + Q931_TE] == NULL)
+ Q931AddDialect(Q931_Dialect_Q931 + Q931_TE, Q931CreateTE);
+
+ if (Q931CreateDialectCB[Q931_Dialect_Q931 + Q931_NT] == NULL)
+ Q931AddDialect(Q931_Dialect_Q931 + Q931_NT, Q931CreateNT);
+
+ if (Q931CreateDialectCB[Q931_Dialect_National + Q931_TE] == NULL)
+ Q931AddDialect(Q931_Dialect_National + Q931_TE, nationalCreateTE);
+
+ if (Q931CreateDialectCB[Q931_Dialect_National + Q931_NT] == NULL)
+ Q931AddDialect(Q931_Dialect_National + Q931_NT, nationalCreateNT);
+
+ if (Q931CreateDialectCB[Q931_Dialect_DMS + Q931_TE] == NULL)
+ Q931AddDialect(Q931_Dialect_DMS + Q931_TE, DMSCreateTE);
+
+ if (Q931CreateDialectCB[Q931_Dialect_DMS + Q931_NT] == NULL)
+ Q931AddDialect(Q931_Dialect_DMS + Q931_NT, DMSCreateNT);
+
+ if (Q931CreateDialectCB[Q931_Dialect_5ESS + Q931_TE] == NULL)
+ Q931AddDialect(Q931_Dialect_5ESS + Q931_TE, ATT5ESSCreateTE);
+
+ if (Q931CreateDialectCB[Q931_Dialect_5ESS + Q931_NT] == NULL)
+ Q931AddDialect(Q931_Dialect_5ESS + Q931_NT, ATT5ESSCreateNT);
+
+ /* The last step we do is to call the callbacks to create the dialects */
+ for (x = 0; x < Q931MAXDLCT; x++) {
+ if (Q931CreateDialectCB[x] != NULL) {
+ Q931CreateDialectCB[x]((L3UCHAR)x);
+ }
+ }
+}
+
+/**
+ * Q931TimerTick
+ * \brief Periodically called to update and check for expired timers
+ * \param pTrunk Q.931 trunk
+ */
+void Q931TimerTick(Q931_TrunkInfo_t *pTrunk)
+{
+ struct Q931_Call *call = NULL;
+ L3ULONG now = 0;
+ L3INT x;
+
+ /* TODO: Loop through all active calls, check timers and call timout procs
+ * if timers are expired.
+ * Implement a function array so each dialect can deal with their own
+ * timeouts.
+ */
+ now = Q931GetTime();
+
+ for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
+ call = &pTrunk->call[x];
+
+ if (!call->InUse || !call->Timer || !call->TimerID)
+ continue;
+
+ if (call->Timer <= now) {
+ /* Stop Timer */
+ Q931StopTimer(pTrunk, x, call->TimerID);
+
+ /* Invoke dialect timeout callback */
+ Q931Timeout[pTrunk->Dialect][call->TimerID](pTrunk, x);
+ }
+ }
+}
+
+/*****************************************************************************
+
+ Function: Q931Rx23
+
+ Description: Receive message from layer 2 (LAPD). Receiving a message
+ is always done in 2 steps. First the message must be
+ interpreted and translated to a static struct. Secondly
+ the message is processed and responded to.
+
+ The Q.931 message contains a static header that is
+ interpreted in this function. The rest is interpreted
+ in a sub function according to mestype.
+
+ Parameters: pTrunk [IN] Ptr to trunk info.
+ buf [IN] Ptr to buffer containing message.
+ Size [IN] Size of message.
+
+ Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+ see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931Rx23(Q931_TrunkInfo_t *pTrunk, L3INT ind, L3UCHAR tei, L3UCHAR * buf, L3INT Size)
+{
+ L3UCHAR *Mes = NULL;
+ L3INT RetCode = Q931E_NO_ERROR;
+ Q931mes_Generic *m = (Q931mes_Generic *) pTrunk->L3Buf;
+ L3INT ISize;
+ L3INT IOff = 0;
+ L3INT L2HSize = Q931L2HeaderSpace;
+
+ switch (ind) {
+ case Q921_DL_UNIT_DATA: /* DL-UNITDATA indication (UI frame, 3 byte header) */
+ L2HSize = 3;
+
+ case Q921_DL_DATA: /* DL-DATA indication (I frame, 4 byte header) */
+ /* Reset our decode buffer */
+ memset(pTrunk->L3Buf, 0, sizeof(pTrunk->L3Buf));
+
+ /* L2 Header Offset */
+ Mes = &buf[L2HSize];
+
+ /* Protocol Discriminator */
+ m->ProtDisc = Mes[IOff++];
+
+ /* CRV */
+ m->CRVFlag = (Mes[IOff + 1] >> 7) & 0x01;
+ m->CRV = Q931Uie_CRV(pTrunk, Mes, m->buf, &IOff, &ISize);
+
+ /* Message Type */
+ m->MesType = Mes[IOff++];
+
+ /* Store tei */
+ m->Tei = tei;
+
+ /* d'oh a little ugly but this saves us from:
+ * a) doing Q.921 work in the lower levels (extracting the TEI ourselves)
+ * b) adding a tei parameter to _all_ Proc functions
+ */
+ if (tei) {
+ L3INT callIndex = 0;
+
+ /* Find the call using CRV */
+ RetCode = Q931FindCRV(pTrunk, m->CRV, &callIndex);
+ if (RetCode == Q931E_NO_ERROR && !pTrunk->call[callIndex].Tei) {
+ pTrunk->call[callIndex].Tei = tei;
+ }
+ }
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Received message from Q.921 (ind %d, tei %d, size %d)\nMesType: %d, CRVFlag %d (%s), CRV %d (Dialect: %d)\n", ind, m->Tei, Size,
+ m->MesType, m->CRVFlag, m->CRVFlag ? "Terminator" : "Originator", m->CRV, pTrunk->Dialect);
+
+ RetCode = Q931Umes[pTrunk->Dialect][m->MesType](pTrunk, Mes, (Q931mes_Generic *)pTrunk->L3Buf, IOff, Size - L2HSize);
+ if (RetCode >= Q931E_NO_ERROR) {
+ RetCode = Q931Proc[pTrunk->Dialect][m->MesType](pTrunk, pTrunk->L3Buf, 2);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q931Tx34
+
+ Description: Called from the stack to send a message to layer 4.
+
+ Parameters: Mes[IN] Ptr to message buffer.
+ Size[IN] Message size in bytes.
+
+ Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+ see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931Tx34(Q931_TrunkInfo_t *pTrunk, L3UCHAR * Mes, L3INT Size)
+{
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Sending message to Layer4 (size: %d)\n", Size);
+
+ if (pTrunk->Q931Tx34CBProc) {
+ return pTrunk->Q931Tx34CBProc(pTrunk->PrivateData34, Mes, Size);
+ }
+ return Q931E_MISSING_CB;
+}
+
+/*****************************************************************************
+
+ Function: Q931Rx43
+
+ Description: Receive message from Layer 4 (application).
+
+ Parameters: pTrunk[IN] Trunk #.
+ buf[IN] Message Pointer.
+ Size[IN] Message size in bytes.
+
+ Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+ see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931Rx43(Q931_TrunkInfo_t *pTrunk,L3UCHAR * buf, L3INT Size)
+{
+ Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+ L3INT RetCode = Q931E_NO_ERROR;
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Receiving message from Layer4 (size: %d, type: %d)\n", Size, ptr->MesType);
+
+ RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Q931Rx43 return code: %d\n", RetCode);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q931Tx32
+
+ Description: Called from the stack to send a message to L2. The input is
+ always a non-packed message so it will first make a proper
+ call to create a packed message before it transmits that
+ message to layer 2.
+
+ Parameters: pTrunk[IN] Trunk #
+ buf[IN] Ptr to message buffer.
+ Size[IN] Message size in bytes.
+
+ Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+ see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931Tx32Data(Q931_TrunkInfo_t *pTrunk, L3UCHAR bcast, L3UCHAR * Mes, L3INT Size)
+{
+ Q931mes_Generic *ptr = (Q931mes_Generic*)Mes;
+ L3INT RetCode = Q931E_NO_ERROR;
+ L3INT iDialect = pTrunk->Dialect;
+ L3INT Offset = bcast ? (Q931L2HeaderSpace - 1) : Q931L2HeaderSpace;
+ L3INT OSize;
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Sending message to Q.921 (size: %d)\n", Size);
+
+ memset(pTrunk->L2Buf, 0, sizeof(pTrunk->L2Buf));
+
+ /* Call pack function through table. */
+ RetCode = Q931Pmes[iDialect][ptr->MesType](pTrunk, (Q931mes_Generic *)Mes, Size, &pTrunk->L2Buf[Offset], &OSize);
+ if (RetCode >= Q931E_NO_ERROR) {
+ L3INT callIndex;
+ L3UCHAR tei = 0;
+
+ if (ptr->CRV) {
+ /* Find the call using CRV */
+ RetCode = Q931FindCRV(pTrunk, ptr->CRV, &callIndex);
+ if (RetCode != Q931E_NO_ERROR)
+ return RetCode;
+
+ tei = pTrunk->call[callIndex].Tei;
+ }
+
+ if (pTrunk->Q931Tx32CBProc) {
+ RetCode = pTrunk->Q931Tx32CBProc(pTrunk->PrivateData32, bcast ? Q921_DL_UNIT_DATA : Q921_DL_DATA, tei, pTrunk->L2Buf, OSize + Offset);
+ } else {
+ RetCode = Q931E_MISSING_CB;
+ }
+ }
+
+ return RetCode;
+}
+
+
+/*****************************************************************************
+
+ Function: Q931SetError
+
+ Description: Called from the stack to indicate an error.
+
+ Parameters: ErrID ID of ie or message causing error.
+ ErrPar1 Error parameter 1
+ ErrPar2 Error parameter 2.
+
+
+*****************************************************************************/
+void Q931SetError(Q931_TrunkInfo_t *pTrunk,L3INT ErrID, L3INT ErrPar1, L3INT ErrPar2)
+{
+ if (pTrunk->Q931ErrorCBProc) {
+ pTrunk->Q931ErrorCBProc(pTrunk->PrivateData34, ErrID, ErrPar1, ErrPar2);
+ } else {
+ Q931ErrorProc(pTrunk->PrivateData34, ErrID, ErrPar1, ErrPar2);
+ }
+}
+
+void Q931SetDefaultErrorCB(Q931ErrorCB_t Q931ErrorPar)
+{
+ Q931ErrorProc = Q931ErrorPar;
+}
+
+/*****************************************************************************
+
+ Function: Q931CreateCRV
+
+ Description: Create a CRV entry and return it's index. The function will
+ locate a free entry in the call tables allocate it and
+ allocate a unique CRV value attached to it.
+
+ Parameters: pTrunk [IN] Trunk number
+ callindex [OUT] return call table index.
+
+ Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+ see q931errors.h for details.
+****************************************************************************/
+L3INT Q931CreateCRV(Q931_TrunkInfo_t *pTrunk, L3INT * callIndex)
+{
+ L3INT CRV = Q931GetUniqueCRV(pTrunk);
+
+ return Q931AllocateCRV(pTrunk, CRV, callIndex);
+}
+
+
+L3INT Q931ReleaseCRV(Q931_TrunkInfo_t *pTrunk, L3INT CRV)
+{
+ int callIndex;
+
+ if ((Q931FindCRV(pTrunk, CRV, &callIndex)) == Q931E_NO_ERROR) {
+ pTrunk->call[callIndex].InUse = 0;
+ return Q931E_NO_ERROR;
+ }
+
+ return Q931E_INVALID_CRV;
+}
+
+/*****************************************************************************
+
+ Function: Q931AllocateCRV
+
+ Description: Allocate a call table entry and assigns the given CRV value
+ to it.
+
+ Parameters: pTrunk [IN] Trunk number
+ iCRV [IN] Call Reference Value.
+ callindex [OUT] return call table index.
+
+ Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+ see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931AllocateCRV(Q931_TrunkInfo_t *pTrunk, L3INT iCRV, L3INT * callIndex)
+{
+ L3INT x;
+ for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
+ if (!pTrunk->call[x].InUse) {
+ pTrunk->call[x].CRV = iCRV;
+ pTrunk->call[x].BChan = 255;
+ pTrunk->call[x].State = 0; /* null state - idle */
+ pTrunk->call[x].TimerID = 0; /* no timer running */
+ pTrunk->call[x].Timer = 0;
+ pTrunk->call[x].InUse = 1; /* mark as used */
+ *callIndex = x;
+ return Q931E_NO_ERROR;
+ }
+ }
+ return Q931E_TOMANYCALLS;
+}
+
+/*****************************************************************************
+
+ Function: Q931GetCallState
+
+ Description: Look up CRV and return current call state. A non existing
+ CRV is the same as state zero (0).
+
+ Parameters: pTrunk [IN] Trunk number.
+ iCRV [IN] CRV
+
+ Return Value: Call State.
+
+*****************************************************************************/
+L3INT Q931GetCallState(Q931_TrunkInfo_t *pTrunk, L3INT iCRV)
+{
+ L3INT x;
+ for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
+ if (pTrunk->call[x].InUse) {
+ if (pTrunk->call[x].CRV == iCRV) {
+ return pTrunk->call[x].State;
+ }
+ }
+ }
+ return 0; /* assume state zero for non existing CRV's */
+}
+
+/**
+ * Q931StartTimer
+ * \brief Start a timer
+ * \param pTrunk Q.931 trunk
+ * \param callindex Index of the call
+ * \param iTimerID ID of timer
+ * \return always 0
+ */
+L3INT Q931StartTimer(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3USHORT iTimerID)
+{
+#if 0
+ L3ULONG duration = Q931Timer[pTrunk->Dialect][iTimerID];
+
+ if (duration) {
+ pTrunk->call[callIndex].Timer = Q931GetTime() + duration;
+ pTrunk->call[callIndex].TimerID = iTimerID;
+ }
+#endif
+ return 0;
+}
+
+/**
+ * Q931StopTimer
+ * \brief Stop a timer
+ * \param pTrunk Q.931 trunk
+ * \param callindex Index of the call
+ * \param iTimerID ID of timer
+ * \return always 0
+ */
+L3INT Q931StopTimer(Q931_TrunkInfo_t *pTrunk, L3INT callindex, L3USHORT iTimerID)
+{
+ if (pTrunk->call[callindex].TimerID == iTimerID)
+ pTrunk->call[callindex].TimerID = 0;
+
+ return 0;
+}
+
+L3INT Q931SetState(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3INT iState)
+{
+ pTrunk->call[callIndex].State = iState;
+
+ return 0;
+}
+
+L3ULONG Q931GetTime()
+{
+ L3ULONG tNow = 0;
+ static L3ULONG tLast = 0;
+
+ if (Q931GetTimeProc != NULL) {
+ tNow = Q931GetTimeProc();
+ if (tNow < tLast) { /* wrapped */
+ /* TODO */
+ }
+ tLast = tNow;
+ }
+ return tNow;
+}
+
+void Q931SetGetTimeCB(L3ULONG (*callback)(void))
+{
+ Q931GetTimeProc = callback;
+}
+
+L3INT Q931FindCRV(Q931_TrunkInfo_t *pTrunk, L3INT crv, L3INT *callindex)
+{
+ L3INT x;
+ for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
+ if (pTrunk->call[x].InUse) {
+ if (pTrunk->call[x].CRV == crv) {
+ *callindex = x;
+ return Q931E_NO_ERROR;
+ }
+ }
+ }
+ return Q931E_INVALID_CRV;
+}
+
+
+void Q931AddDialect(L3UCHAR i, void (*callback)(L3UCHAR iD ))
+{
+ if (i < Q931MAXDLCT) {
+ Q931CreateDialectCB[i] = callback;
+ }
+}
+
+/*****************************************************************************
+ Function: Q931AddStateEntry
+
+ Description: Find an empty entry in the dialects state table and add this
+ entry.
+*****************************************************************************/
+void Q931AddStateEntry(L3UCHAR iD, L3INT iState, L3INT iMes, L3UCHAR cDir)
+{
+ int x;
+ for (x = 0; x < Q931MAXSTATE; x++) {
+ if (Q931st[x].Message == 0) {
+ Q931st[x].State = iState;
+ Q931st[x].Message = iMes;
+ Q931st[x].Direction = cDir;
+ /* TODO Sort table and use bsearch */
+ return;
+ }
+ }
+}
+
+/*****************************************************************************
+ Function: Q931IsEventLegal
+
+ Description: Check state table for matching criteria to indicate if this
+ Message is legal in this state or not.
+
+ Note: Someone write a bsearch or invent something smart here
+ please - sequential is ok for now.
+*****************************************************************************/
+L3BOOL Q931IsEventLegal(L3UCHAR iD, L3INT iState, L3INT iMes, L3UCHAR cDir)
+{
+ int x;
+ /* TODO Sort table and use bsearch */
+ for (x = 0; x < Q931MAXSTATE; x++) {
+ if (Q931st[x].State == iState && Q931st[x].Message == iMes &&
+ Q931st[x].Direction == cDir) {
+ return L3TRUE;
+ }
+ }
+ return L3FALSE;
+}
+
+/*****************************************************************************
+ Function: q931_error_to_name()
+
+ Description: Check state table for matching criteria to indicate if this
+ Message is legal in this state or not.
+
+ Note: Someone write a bsearch or invent something smart here
+ please - sequential is ok for now.
+*****************************************************************************/
+static const char *q931_error_names[] = {
+ "Q931E_NO_ERROR", /* 0 */
+
+ "Q931E_UNKNOWN_MESSAGE", /* -3001 */
+ "Q931E_ILLEGAL_IE", /* -3002 */
+ "Q931E_UNKNOWN_IE", /* -3003 */
+ "Q931E_BEARERCAP", /* -3004 */
+ "Q931E_HLCOMP", /* -3005 */
+ "Q931E_LLCOMP", /* -3006 */
+ "Q931E_INTERNAL", /* -3007 */
+ "Q931E_MISSING_CB", /* -3008 */
+ "Q931E_UNEXPECTED_MESSAGE", /* -3009 */
+ "Q931E_ILLEGAL_MESSAGE", /* -3010 */
+ "Q931E_TOMANYCALLS", /* -3011 */
+ "Q931E_INVALID_CRV", /* -3012 */
+ "Q931E_CALLID", /* -3013 */
+ "Q931E_CALLSTATE", /* -3014 */
+ "Q931E_CALLEDSUB", /* -3015 */
+ "Q931E_CALLEDNUM", /* -3016 */
+ "Q931E_CALLINGNUM", /* -3017 */
+ "Q931E_CALLINGSUB", /* -3018 */
+ "Q931E_CAUSE", /* -3019 */
+ "Q931E_CHANID", /* -3020 */
+ "Q931E_DATETIME", /* -3021 */
+ "Q931E_DISPLAY", /* -3022 */
+ "Q931E_KEYPADFAC", /* -3023 */
+ "Q931E_NETFAC", /* -3024 */
+ "Q931E_NOTIFIND", /* -3025 */
+ "Q931E_PROGIND", /* -3026 */
+ "Q931E_RESTARTIND", /* -3027 */
+ "Q931E_SEGMENT", /* -3028 */
+ "Q931E_SIGNAL", /* -3029 */
+ "Q931E_GENERIC_DIGITS" /* -3030 */
+
+};
+
+#define Q931_MAX_ERROR 30
+
+const char *q931_error_to_name(q931_error_t error)
+{
+ int index = 0;
+ if ((int)error < 0) {
+ index = (((int)error * -1) -3000);
+ }
+ if (index < 0 || index > Q931_MAX_ERROR) {
+ return "";
+ }
+ return q931_error_names[index];
+}
+/*
+ * Logging
+ */
+#include <stdarg.h>
+
+L3INT Q931Log(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level, const char *fmt, ...)
+{
+ char buf[Q931_LOGBUFSIZE];
+ L3INT len;
+ va_list ap;
+
+ if (!trunk->Q931LogCBProc)
+ return 0;
+
+ if (trunk->loglevel < level)
+ return 0;
+
+ va_start(ap, fmt);
+
+ len = vsnprintf(buf, sizeof(buf)-1, fmt, ap);
+ if (len <= 0) {
+ /* TODO: error handling */
+ return -1;
+ }
+ if (len >= sizeof(buf))
+ len = sizeof(buf) - 1;
+
+ buf[len] = '\0';
+
+ va_end(ap);
+
+ return trunk->Q931LogCBProc(trunk->PrivateDataLog, level, buf, len);
+}
+
+/**
+ * Q921SetLogCB
+ * \brief Set Logging callback function and private data
+ */
+void Q931SetLogCB(Q931_TrunkInfo_t *trunk, Q931LogCB_t func, void *priv)
+{
+ trunk->Q931LogCBProc = func;
+ trunk->PrivateDataLog = priv;
+}
+
+/**
+ * Q921SetLogLevel
+ * \brief Set Loglevel
+ */
+void Q931SetLogLevel(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level)
+{
+ if(!trunk)
+ return;
+
+ if (level < Q931_LOG_NONE) {
+ level = Q931_LOG_NONE;
+ } else if (level > Q931_LOG_DEBUG) {
+ level = Q931_LOG_DEBUG;
+ }
+
+ trunk->loglevel = level;
+}
+
+/**
+ * Q931TimeoutDummy
+ * \brief Dummy handler for timeouts
+ * \param pTrunk Q.931 trunk
+ * \param callIndex Index of call
+ */
+L3INT Q931TimeoutDummy(Q931_TrunkInfo_t *pTrunk, L3INT callIndex)
+{
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Timer %d of call %d (CRV: %d) timed out\n", pTrunk->call[callIndex].TimerID, callIndex, pTrunk->call[callIndex].CRV);
+
+ return 0;
+}
Added: freeswitch/trunk/libs/openzap/src/isdn/Q931StateNT.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/Q931StateNT.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/Q931StateNT.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1218 @@
+/*****************************************************************************
+
+ FileName: q931StateNT.c
+
+ Contents: Q.931 State Engine for NT (Network Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "Q931.h"
+
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+ Function: Q931CreateNT
+
+ Description: Will create the Q931 NT as a Dialect in the stack. The first
+ bulk set up the message handlers, the second bulk the IE
+ encoders/coders, and the last bulk set up the state table.
+
+ Parameters: i Dialect index
+*****************************************************************************/
+void Q931CreateNT(L3UCHAR i)
+{
+ Q931SetMesProc(Q931mes_ALERTING, i, Q931ProcAlertingNT, Q931Umes_Alerting, Q931Pmes_Alerting);
+ Q931SetMesProc(Q931mes_CALL_PROCEEDING, i, Q931ProcCallProceedingNT, Q931Umes_CallProceeding, Q931Pmes_CallProceeding);
+ Q931SetMesProc(Q931mes_CONNECT, i, Q931ProcConnectNT, Q931Umes_Connect, Q931Pmes_Connect);
+ Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i, Q931ProcConnectAckNT, Q931Umes_ConnectAck, Q931Pmes_ConnectAck);
+ Q931SetMesProc(Q931mes_PROGRESS, i, Q931ProcProgressNT, Q931Umes_Progress, Q931Pmes_Progress);
+ Q931SetMesProc(Q931mes_SETUP, i, Q931ProcSetupNT, Q931Umes_Setup, Q931Pmes_Setup);
+ Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE, i, Q931ProcSetupAckNT, Q931Umes_SetupAck, Q931Pmes_SetupAck);
+ Q931SetMesProc(Q931mes_RESUME, i, Q931ProcResumeNT, Q931Umes_Resume, Q931Pmes_Resume);
+ Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE, i, Q931ProcResumeAckNT, Q931Umes_ResumeAck, Q931Pmes_ResumeAck);
+ Q931SetMesProc(Q931mes_RESUME_REJECT, i, Q931ProcResumeRejectNT, Q931Umes_ResumeReject, Q931Pmes_ResumeReject);
+ Q931SetMesProc(Q931mes_SUSPEND, i, Q931ProcSuspendNT, Q931Umes_Suspend, Q931Pmes_Suspend);
+ Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE, i, Q931ProcSuspendAckNT, Q931Umes_SuspendAck, Q931Pmes_SuspendAck);
+ Q931SetMesProc(Q931mes_SUSPEND_REJECT, i, Q931ProcSuspendRejectNT, Q931Umes_SuspendReject, Q931Pmes_SuspendReject);
+ Q931SetMesProc(Q931mes_USER_INFORMATION, i, Q931ProcUserInformationNT, Q931Umes_UserInformation, Q931Pmes_UserInformation);
+ Q931SetMesProc(Q931mes_DISCONNECT, i, Q931ProcDisconnectNT, Q931Umes_Disconnect, Q931Pmes_Disconnect);
+ Q931SetMesProc(Q931mes_RELEASE, i, Q931ProcReleaseNT, Q931Umes_Release, Q931Pmes_Release);
+ Q931SetMesProc(Q931mes_RELEASE_COMPLETE, i, Q931ProcReleaseCompleteNT, Q931Umes_ReleaseComplete, Q931Pmes_ReleaseComplete);
+ Q931SetMesProc(Q931mes_RESTART, i, Q931ProcRestartNT, Q931Umes_Restart, Q931Pmes_Restart);
+ Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE, i, Q931ProcRestartAckNT, Q931Umes_RestartAck, Q931Pmes_RestartAck);
+ Q931SetMesProc(Q931mes_CONGESTION_CONTROL, i, Q931ProcCongestionControlNT, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+ Q931SetMesProc(Q931mes_INFORMATION, i, Q931ProcInformationNT, Q931Umes_Information, Q931Pmes_Information);
+ Q931SetMesProc(Q931mes_NOTIFY, i, Q931ProcNotifyNT, Q931Umes_Notify, Q931Pmes_Notify);
+ Q931SetMesProc(Q931mes_STATUS, i, Q931ProcStatusNT, Q931Umes_Status, Q931Pmes_Status);
+ Q931SetMesProc(Q931mes_STATUS_ENQUIRY, i, Q931ProcStatusEnquiryNT, Q931Umes_StatusEnquiry, Q931Pmes_StatusEnquiry);
+ Q931SetMesProc(Q931mes_SEGMENT, i, Q931ProcSegmentNT, Q931Umes_Segment, Q931Pmes_Segment);
+
+ Q931SetMesProc(Q932mes_FACILITY, i, Q932ProcFacilityNT, Q932Umes_Facility, Q932Pmes_Facility);
+ Q931SetMesProc(Q932mes_HOLD, i, Q932ProcHoldNT, Q932Umes_Hold, Q932Pmes_Hold);
+ Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE, i, Q932ProcHoldAckNT, Q932Umes_HoldAck, Q932Pmes_HoldAck);
+ Q931SetMesProc(Q932mes_HOLD_REJECT, i, Q932ProcHoldRejectNT, Q932Umes_HoldReject, Q932Pmes_HoldReject);
+ Q931SetMesProc(Q932mes_REGISTER, i, Q932ProcRegisterNT, Q932Umes_Register, Q932Pmes_Register);
+ Q931SetMesProc(Q932mes_RETRIEVE, i, Q932ProcRetrieveNT, Q932Umes_Retrieve, Q932Pmes_Retrieve);
+ Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckNT, Q932Umes_RetrieveAck, Q932Pmes_RetrieveAck);
+ Q931SetMesProc(Q932mes_RETRIEVE_REJECT, i, Q932ProcRetrieveRejectNT, Q932Umes_RetrieveReject, Q932Pmes_RetrieveReject);
+
+ /* Set up the IE encoder/decoder handle table.*/
+ Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE, i, Q931Pie_Segment, Q931Uie_Segment);
+ Q931SetIEProc(Q931ie_BEARER_CAPABILITY, i, Q931Pie_BearerCap, Q931Uie_BearerCap);
+ Q931SetIEProc(Q931ie_CAUSE, i, Q931Pie_Cause, Q931Uie_Cause);
+ Q931SetIEProc(Q931ie_CALL_IDENTITY, i, Q931Pie_CallID, Q931Uie_CallID);
+ Q931SetIEProc(Q931ie_CALL_STATE, i, Q931Pie_CallState, Q931Uie_CallState);
+ Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION, i, Q931Pie_ChanID, Q931Uie_ChanID);
+ Q931SetIEProc(Q931ie_PROGRESS_INDICATOR, i, Q931Pie_ProgInd, Q931Uie_ProgInd);
+ Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES, i, Q931Pie_NetFac, Q931Uie_NetFac);
+ Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR, i, Q931Pie_NotifInd, Q931Uie_NotifInd);
+ Q931SetIEProc(Q931ie_DISPLAY, i, Q931Pie_Display, Q931Uie_Display);
+ Q931SetIEProc(Q931ie_DATETIME, i, Q931Pie_DateTime, Q931Uie_DateTime);
+ Q931SetIEProc(Q931ie_KEYPAD_FACILITY, i, Q931Pie_KeypadFac, Q931Uie_KeypadFac);
+ Q931SetIEProc(Q931ie_SIGNAL, i, Q931Pie_Signal, Q931Uie_Signal);
+ Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER, i, Q931Pie_CallingNum, Q931Uie_CallingNum);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS, i, Q931Pie_CallingSub, Q931Uie_CallingSub);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER, i, Q931Pie_CalledNum, Q931Uie_CalledNum);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS, i, Q931Pie_CalledSub, Q931Uie_CalledSub);
+ Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_RESTART_INDICATOR, i, Q931Pie_RestartInd, Q931Uie_RestartInd);
+ Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY, i, Q931Pie_LLComp, Q931Uie_LLComp);
+ Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY, i, Q931Pie_HLComp, Q931Uie_HLComp);
+ Q931SetIEProc(Q931ie_USER_USER, i, Q931Pie_UserUser, Q931Uie_UserUser);
+
+ Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_FACILITY, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_REDIRECTING_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+
+ /* The following define a state machine. The point is that the Message
+ * procs can when search this to find out if the message/state
+ * combination is legale. If not, the proc for unexpected message apply.
+ */
+
+ /* TODO define state table here */
+
+ /* Timer default values */
+ Q931SetTimerDefault(i, Q931_TIMER_T301, 180000); /* T301: 180s */
+ Q931SetTimerDefault(i, Q931_TIMER_T302, 15000); /* T302: 15s */
+ Q931SetTimerDefault(i, Q931_TIMER_T303, 4000); /* T303: 4s */
+ Q931SetTimerDefault(i, Q931_TIMER_T304, 20000); /* T304: 20s */
+ Q931SetTimerDefault(i, Q931_TIMER_T305, 30000); /* T305: 30s */
+ Q931SetTimerDefault(i, Q931_TIMER_T306, 30000); /* T306: 30s */
+ Q931SetTimerDefault(i, Q931_TIMER_T307, 180000); /* T307: 180s */
+ Q931SetTimerDefault(i, Q931_TIMER_T308, 4000); /* T308: 4s */
+ Q931SetTimerDefault(i, Q931_TIMER_T309, 60000); /* T309: 60s */
+ Q931SetTimerDefault(i, Q931_TIMER_T310, 10000); /* T310: 10s */
+ Q931SetTimerDefault(i, Q931_TIMER_T312, 12000); /* T312: 12s */
+ Q931SetTimerDefault(i, Q931_TIMER_T314, 4000); /* T314: 4s */
+ Q931SetTimerDefault(i, Q931_TIMER_T316, 120000); /* T316: 120s */
+ Q931SetTimerDefault(i, Q931_TIMER_T317, 90000); /* T317: 90s */
+ Q931SetTimerDefault(i, Q931_TIMER_T320, 30000); /* T320: 30s */
+ Q931SetTimerDefault(i, Q931_TIMER_T321, 30000); /* T321: 30s */
+ Q931SetTimerDefault(i, Q931_TIMER_T322, 4000); /* T322: 4s */
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcAlertingNT
+
+*****************************************************************************/
+L3INT Q931ProcAlertingNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* Reset 4 sec timer. */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcCallProceedingNT
+
+*****************************************************************************/
+L3INT Q931ProcCallProceedingNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcConnectNT
+
+*****************************************************************************/
+L3INT Q931ProcConnectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcConnectAckNT
+
+*****************************************************************************/
+L3INT Q931ProcConnectAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcProgressNT
+
+*****************************************************************************/
+L3INT Q931ProcProgressNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSetupNT
+
+ Description: Process a SETUP message.
+
+ *****************************************************************************/
+L3INT Q931ProcSetupNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+ L3INT rc = 0;
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Reject SETUP on existing calls */
+ if (Q931GetCallState(pTrunk, pMes->CRV) != Q931_U0) {
+ Q931Disconnect(pTrunk, iFrom, pMes->CRV, 81);
+ return Q931E_UNEXPECTED_MESSAGE;
+ }
+
+ /* outgoing call */
+ if (iFrom == 4) {
+ ret = Q931CreateCRV(pTrunk, &callIndex);
+ if (ret)
+ return ret;
+
+ pMes->CRV = pTrunk->call[callIndex].CRV;
+
+ /*
+ * Outgoing SETUP message will be broadcasted in PTMP mode
+ */
+ ret = Q931Tx32Data(pTrunk, Q931_IS_PTP(pTrunk) ? 0 : 1, buf, pMes->Size);
+ if (ret)
+ return ret;
+
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ Q931SetState(pTrunk, callIndex, Q931_U1);
+ }
+ /* incoming call */
+ else {
+ /* Locate free CRV entry and store info */
+ ret = Q931AllocateCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR) {
+ /* Not possible to allocate CRV entry, so must reject call */
+ Q931Disconnect(pTrunk, iFrom, pMes->CRV, 42);
+ return ret;
+ }
+
+ /* store TEI in call */
+ pTrunk->call[callIndex].Tei = pMes->Tei;
+
+ /* Send setup indication to user */
+ ret = Q931Tx34(pTrunk, (L3UCHAR*)pMes, pMes->Size);
+ if (ret != Q931E_NO_ERROR) {
+ return ret;
+ } else {
+ /* Must be full queue, meaning we can't process the call */
+ /* so we must disconnect */
+ Q931Disconnect(pTrunk, iFrom, pMes->CRV, 81);
+ return ret;
+ }
+#if 0
+ /* TODO: Unreachable code??? */
+ /* Set state U6 */
+ Q931SetState(pTrunk, callIndex, Q931_U6);
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+#endif
+ }
+
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSetupAckNT
+
+ Description: Used to acknowedge a SETUP. Usually the first initial
+ response recevide back used to buy some time.
+
+ Note that ChanID (B Channel Assignment) might come here from
+ NT side.
+
+*****************************************************************************/
+L3INT Q931ProcSetupAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcResumeNT
+
+*****************************************************************************/
+L3INT Q931ProcResumeNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcResumeAckNT
+
+*****************************************************************************/
+L3INT Q931ProcResumeAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcResumeRejectNT
+
+*****************************************************************************/
+L3INT Q931ProcResumeRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSuspendNT
+
+*****************************************************************************/
+L3INT Q931ProcSuspendNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSuspendAckNT
+
+*****************************************************************************/
+L3INT Q931ProcSuspendAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSuspendRejectNT
+
+*****************************************************************************/
+L3INT Q931ProcSuspendRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcInformationNT
+
+*****************************************************************************/
+L3INT Q931ProcUserInformationNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcDisconnectNT
+
+*****************************************************************************/
+L3INT Q931ProcDisconnectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcReleaseNT
+
+*****************************************************************************/
+L3INT Q931ProcReleaseNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcReleaseCompleteNT
+
+*****************************************************************************/
+L3INT Q931ProcReleaseCompleteNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcRestartNT
+
+*****************************************************************************/
+L3INT Q931ProcRestartNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcRestartAckNT
+
+*****************************************************************************/
+L3INT Q931ProcRestartAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcCongestionControlNT
+
+*****************************************************************************/
+L3INT Q931ProcCongestionControlNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcInformationNT
+
+*****************************************************************************/
+L3INT Q931ProcInformationNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcNotifyNT
+
+*****************************************************************************/
+L3INT Q931ProcNotifyNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcStatusNT
+
+*****************************************************************************/
+L3INT Q931ProcStatusNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcStatusEnquiryNT
+
+*****************************************************************************/
+L3INT Q931ProcStatusEnquiryNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSegmentNT
+
+*****************************************************************************/
+L3INT Q931ProcSegmentNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/****************************************************************************/
+/******************* Q.932 - Supplementary Services *************************/
+/****************************************************************************/
+
+/*****************************************************************************
+
+ Function: Q932ProcFacilityNT
+
+*****************************************************************************/
+L3INT Q932ProcFacilityNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcHoldNT
+
+*****************************************************************************/
+L3INT Q932ProcHoldNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcHoldAckNT
+
+*****************************************************************************/
+L3INT Q932ProcHoldAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcHoldRejectNT
+
+*****************************************************************************/
+L3INT Q932ProcHoldRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcRegisterTE
+
+*****************************************************************************/
+L3INT Q932ProcRegisterNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcRetrieveNT
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcRetrieveAckNT
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcRetrieveRejectNT
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here*/
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
Added: freeswitch/trunk/libs/openzap/src/isdn/Q931StateTE.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/Q931StateTE.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/Q931StateTE.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1310 @@
+/*****************************************************************************
+
+ FileName: q931StateTE.c
+
+ Contents: Q.931 State Engine for TE (User Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ This reference implementation uses a process per message,
+ meaning that each message must check call states. This
+ is easier for dialect maintenance as each message proc
+ can be replaced individually. A new TE variant only
+ need to copy the Q931CreateTE and replace those procs or
+ need to override.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "Q931.h"
+
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+ Function: Q931CreateTE
+
+ Description: Will create the Q931 TE as a Dialect in the stack. The first
+ bulk set up the message handlers, the second bulk the IE
+ encoders/coders, and the last bulk set up the state table.
+
+ Parameters: i Dialect index
+*****************************************************************************/
+void Q931CreateTE(L3UCHAR i)
+{
+ Q931SetMesProc(Q931mes_ALERTING, i, Q931ProcAlertingTE, Q931Umes_Alerting, Q931Pmes_Alerting);
+ Q931SetMesProc(Q931mes_CALL_PROCEEDING, i, Q931ProcCallProceedingTE, Q931Umes_CallProceeding, Q931Pmes_CallProceeding);
+ Q931SetMesProc(Q931mes_CONNECT, i, Q931ProcConnectTE, Q931Umes_Connect, Q931Pmes_Connect);
+ Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i, Q931ProcConnectAckTE, Q931Umes_ConnectAck, Q931Pmes_ConnectAck);
+ Q931SetMesProc(Q931mes_PROGRESS, i, Q931ProcProgressTE, Q931Umes_Progress, Q931Pmes_Progress);
+ Q931SetMesProc(Q931mes_SETUP, i, Q931ProcSetupTE, Q931Umes_Setup, Q931Pmes_Setup);
+ Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE, i, Q931ProcSetupAckTE, Q931Umes_SetupAck, Q931Pmes_SetupAck);
+ Q931SetMesProc(Q931mes_RESUME, i, Q931ProcResumeTE, Q931Umes_Resume, Q931Pmes_Resume);
+ Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE, i, Q931ProcResumeAckTE, Q931Umes_ResumeAck, Q931Pmes_ResumeAck);
+ Q931SetMesProc(Q931mes_RESUME_REJECT, i, Q931ProcResumeRejectTE, Q931Umes_ResumeReject, Q931Pmes_ResumeReject);
+ Q931SetMesProc(Q931mes_SUSPEND, i, Q931ProcSuspendTE, Q931Umes_Suspend, Q931Pmes_Suspend);
+ Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE, i, Q931ProcSuspendAckTE, Q931Umes_SuspendAck, Q931Pmes_SuspendAck);
+ Q931SetMesProc(Q931mes_SUSPEND_REJECT, i, Q931ProcSuspendRejectTE, Q931Umes_SuspendReject, Q931Pmes_SuspendReject);
+ Q931SetMesProc(Q931mes_USER_INFORMATION, i, Q931ProcUserInformationTE, Q931Umes_UserInformation, Q931Pmes_UserInformation);
+ Q931SetMesProc(Q931mes_DISCONNECT, i, Q931ProcDisconnectTE, Q931Umes_Disconnect, Q931Pmes_Disconnect);
+ Q931SetMesProc(Q931mes_RELEASE, i, Q931ProcReleaseTE, Q931Umes_Release, Q931Pmes_Release);
+ Q931SetMesProc(Q931mes_RELEASE_COMPLETE, i, Q931ProcReleaseCompleteTE, Q931Umes_ReleaseComplete, Q931Pmes_ReleaseComplete);
+ Q931SetMesProc(Q931mes_RESTART, i, Q931ProcRestartTE, Q931Umes_Restart, Q931Pmes_Restart);
+ Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE, i, Q931ProcRestartAckTE, Q931Umes_RestartAck, Q931Pmes_RestartAck);
+ Q931SetMesProc(Q931mes_CONGESTION_CONTROL, i, Q931ProcCongestionControlTE, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+ Q931SetMesProc(Q931mes_INFORMATION, i, Q931ProcInformationTE, Q931Umes_Information, Q931Pmes_Information);
+ Q931SetMesProc(Q931mes_NOTIFY, i, Q931ProcNotifyTE, Q931Umes_Notify, Q931Pmes_Notify);
+ Q931SetMesProc(Q931mes_STATUS, i, Q931ProcStatusTE, Q931Umes_Status, Q931Pmes_Status);
+ Q931SetMesProc(Q931mes_STATUS_ENQUIRY, i, Q931ProcStatusEnquiryTE, Q931Umes_StatusEnquiry, Q931Pmes_StatusEnquiry);
+ Q931SetMesProc(Q931mes_SEGMENT, i, Q931ProcSegmentTE, Q931Umes_Segment, Q931Pmes_Segment);
+
+ Q931SetMesProc(Q932mes_FACILITY, i, Q932ProcFacilityTE, Q932Umes_Facility, Q932Pmes_Facility);
+ Q931SetMesProc(Q932mes_HOLD, i, Q932ProcHoldTE, Q932Umes_Hold, Q932Pmes_Hold);
+ Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE, i, Q932ProcHoldAckTE, Q932Umes_HoldAck, Q932Pmes_HoldAck);
+ Q931SetMesProc(Q932mes_HOLD_REJECT, i, Q932ProcHoldRejectTE, Q932Umes_HoldReject, Q932Pmes_HoldReject);
+ Q931SetMesProc(Q932mes_REGISTER, i, Q932ProcRegisterTE, Q932Umes_Register, Q932Pmes_Register);
+ Q931SetMesProc(Q932mes_RETRIEVE, i, Q932ProcRetrieveTE, Q932Umes_Retrieve, Q932Pmes_Retrieve);
+ Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckTE, Q932Umes_RetrieveAck, Q932Pmes_RetrieveAck);
+ Q931SetMesProc(Q932mes_RETRIEVE_REJECT, i, Q932ProcRetrieveRejectTE, Q932Umes_RetrieveReject, Q932Pmes_RetrieveReject);
+
+ /* Set up the IE encoder/decoder handle table.*/
+ Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE, i, Q931Pie_Segment, Q931Uie_Segment);
+ Q931SetIEProc(Q931ie_BEARER_CAPABILITY, i, Q931Pie_BearerCap, Q931Uie_BearerCap);
+ Q931SetIEProc(Q931ie_CAUSE, i, Q931Pie_Cause, Q931Uie_Cause);
+ Q931SetIEProc(Q931ie_CALL_IDENTITY, i, Q931Pie_CallID, Q931Uie_CallID);
+ Q931SetIEProc(Q931ie_CALL_STATE, i, Q931Pie_CallState, Q931Uie_CallState);
+ Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION, i, Q931Pie_ChanID, Q931Uie_ChanID);
+ Q931SetIEProc(Q931ie_PROGRESS_INDICATOR, i, Q931Pie_ProgInd, Q931Uie_ProgInd);
+ Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES, i, Q931Pie_NetFac, Q931Uie_NetFac);
+ Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR, i, Q931Pie_NotifInd, Q931Uie_NotifInd);
+ Q931SetIEProc(Q931ie_DISPLAY, i, Q931Pie_Display, Q931Uie_Display);
+ Q931SetIEProc(Q931ie_DATETIME, i, Q931Pie_DateTime, Q931Uie_DateTime);
+ Q931SetIEProc(Q931ie_KEYPAD_FACILITY, i, Q931Pie_KeypadFac, Q931Uie_KeypadFac);
+ Q931SetIEProc(Q931ie_SIGNAL, i, Q931Pie_Signal, Q931Uie_Signal);
+ Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER, i, Q931Pie_CallingNum, Q931Uie_CallingNum);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS, i, Q931Pie_CallingSub, Q931Uie_CallingSub);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER, i, Q931Pie_CalledNum, Q931Uie_CalledNum);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS, i, Q931Pie_CalledSub, Q931Uie_CalledSub);
+ Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_RESTART_INDICATOR, i, Q931Pie_RestartInd, Q931Uie_RestartInd);
+ Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY, i, Q931Pie_LLComp, Q931Uie_LLComp);
+ Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY, i, Q931Pie_HLComp, Q931Uie_HLComp);
+ Q931SetIEProc(Q931ie_USER_USER, i, Q931Pie_UserUser, Q931Uie_UserUser);
+
+ Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_FACILITY, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_REDIRECTING_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+
+ /* The following define a state machine. The point is that the Message
+ * procs can when search this to find out if the message/state
+ * combination is legale. If not, the proc for unexpected message apply.
+ */
+
+ /* State 0 Idle */
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RESUME, 2);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP, 2);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_STATUS, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE_COMPLETE, 4);
+
+ /* State 1 Call Initiating */
+ Q931AddStateEntry(i, Q931_U1, Q931mes_DISCONNECT, 2);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_SETUP_ACKNOWLEDGE, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_RELEASE_COMPLETE, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_CALL_PROCEEDING, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_CONNECT, 4);
+
+ /* State 2 Overlap Sending */
+ Q931AddStateEntry(i, Q931_U2, Q931mes_INFORMATION, 2);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_CALL_PROCEEDING, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_PROGRESS, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_CONNECT, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_RELEASE, 2);
+
+ /* State 3 Outgoing Call Proceeding */
+ Q931AddStateEntry(i, Q931_U3, Q931mes_PROGRESS, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_CONNECT, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_RELEASE, 2);
+
+ /* State 4 Call Delivered */
+ Q931AddStateEntry(i, Q931_U4, Q931mes_CONNECT, 4);
+
+ /* State 6 Call Precent */
+ Q931AddStateEntry(i, Q931_U6, Q931mes_INFORMATION, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_ALERTING, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_CALL_PROCEEDING, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_CONNECT, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE_COMPLETE, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_DISCONNECT, 4);
+
+ /* State 7 Call Received */
+ Q931AddStateEntry(i, Q931_U7, Q931mes_CONNECT, 2);
+
+ /* State 8 Connect request */
+ Q931AddStateEntry(i, Q931_U8, Q931mes_CONNECT_ACKNOWLEDGE, 4);
+
+ /* State 9 Incoming Call Proceeding */
+ Q931AddStateEntry(i, Q931_U9, Q931mes_CONNECT, 2);
+ Q931AddStateEntry(i, Q931_U9, Q931mes_ALERTING, 2);
+ Q931AddStateEntry(i, Q931_U9, Q931mes_PROGRESS, 2);
+
+ /* State 10 Active */
+ Q931AddStateEntry(i, Q931_U10, Q931mes_SUSPEND, 2);
+ Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY, 4);
+ Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY, 2);
+
+ /* State 11 Disconnect Request */
+ Q931AddStateEntry(i, Q931_U11, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U11, Q931mes_DISCONNECT, 4);
+ Q931AddStateEntry(i, Q931_U11, Q931mes_NOTIFY, 4);
+
+ /* State 12 Disconnect Ind */
+ Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 2);
+
+ /* State 15 Suspend Request */
+ Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_ACKNOWLEDGE, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_REJECT, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_DISCONNECT, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_RELEASE, 4);
+
+/* TODO
+ Q931AddStateEntry(i, Q931_U17,
+ Q931AddStateEntry(i, Q931_U19,
+ Q931AddStateEntry(i, Q931_U25,
+*/
+
+ /* Timer default values */
+ Q931SetTimerDefault(i, Q931_TIMER_T301, 180000); /* T301: 180s */
+ Q931SetTimerDefault(i, Q931_TIMER_T302, 15000); /* T302: 15s */
+ Q931SetTimerDefault(i, Q931_TIMER_T303, 4000); /* T303: 4s */
+ Q931SetTimerDefault(i, Q931_TIMER_T304, 30000); /* T304: 30s */
+ Q931SetTimerDefault(i, Q931_TIMER_T305, 30000); /* T305: 30s */
+ Q931SetTimerDefault(i, Q931_TIMER_T308, 4000); /* T308: 4s */
+ Q931SetTimerDefault(i, Q931_TIMER_T309, 60000); /* T309: 60s */
+ Q931SetTimerDefault(i, Q931_TIMER_T310, 60000); /* T310: 60s */
+ Q931SetTimerDefault(i, Q931_TIMER_T313, 4000); /* T313: 4s */
+ Q931SetTimerDefault(i, Q931_TIMER_T314, 4000); /* T314: 4s */
+ Q931SetTimerDefault(i, Q931_TIMER_T316, 120000); /* T316: 120s */
+ Q931SetTimerDefault(i, Q931_TIMER_T317, 90000); /* T317: 90s */
+ Q931SetTimerDefault(i, Q931_TIMER_T318, 4000); /* T318: 4s */
+ Q931SetTimerDefault(i, Q931_TIMER_T319, 4000); /* T319: 4s */
+ Q931SetTimerDefault(i, Q931_TIMER_T321, 30000); /* T321: 30s */
+ Q931SetTimerDefault(i, Q931_TIMER_T322, 4000); /* T322: 4s */
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcAlertingTE
+
+*****************************************************************************/
+L3INT Q931ProcAlertingTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* Reset 4 sec timer. */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcCallProceedingTE
+
+*****************************************************************************/
+L3INT Q931ProcCallProceedingTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcConnectTE
+
+*****************************************************************************/
+L3INT Q931ProcConnectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ if (pTrunk->autoConnectAck) {
+ Q931AckConnect(pTrunk, buf);
+ }
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcConnectAckTE
+
+*****************************************************************************/
+L3INT Q931ProcConnectAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcProgressTE
+
+*****************************************************************************/
+L3INT Q931ProcProgressTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSetupTE
+
+*****************************************************************************/
+L3INT Q931ProcSetupTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+ L3INT rc = 0;
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Reject SETUP on existing calls */
+ if (Q931GetCallState(pTrunk, pMes->CRV) != Q931_U0) {
+ Q931Disconnect(pTrunk, iFrom, pMes->CRV, 81);
+ return Q931E_UNEXPECTED_MESSAGE;
+ }
+
+ /* outgoing call */
+ if (iFrom == 4) {
+ ret = Q931CreateCRV(pTrunk, &callIndex);
+ if (ret)
+ return ret;
+ pMes->CRV = pTrunk->call[callIndex].CRV;
+
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ if (ret)
+ return ret;
+
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+
+ /* TODO: Add this back when we get the state stuff more filled out */
+ /*Q931SetState(pTrunk, callIndex, Q931_U1);*/
+ }
+ /* incoming call */
+ else {
+ /* Locate free CRV entry and store info */
+ ret = Q931AllocateCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR) {
+ /* Not possible to allocate CRV entry, so must reject call */
+ Q931Disconnect(pTrunk, iFrom, pMes->CRV, 42);
+ return ret;
+ }
+
+ /* Send setup indication to user */
+ ret = Q931Tx34(pTrunk, (L3UCHAR*)pMes, pMes->Size);
+ if (ret != Q931E_NO_ERROR) {
+ if (pTrunk->autoSetupAck) {
+ Q931AckSetup(pTrunk, buf);
+ }
+ return ret;
+ } else {
+ /* Must be full queue, meaning we can't process the call */
+ /* so we must disconnect */
+ Q931Disconnect(pTrunk, iFrom, pMes->CRV, 81);
+ return ret;
+ }
+#if 0
+ /* TODO: Unreachable code??? */
+ /* Set state U6 */
+ Q931SetState(pTrunk, callIndex, Q931_U6);
+
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+#endif
+ }
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSetupAckTE
+
+ Description: Used to acknowedge a SETUP. Usually the first initial
+ response recevide back used to buy some time. L4 sending this
+ should only be passed on. L2 sending this means that we set
+ a new timer (and pass it to L4).
+
+ Note that ChanID (B Channel Assignment) might come here from
+ NT side.
+
+*****************************************************************************/
+L3INT Q931ProcSetupAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcResumeTE
+
+*****************************************************************************/
+L3INT Q931ProcResumeTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Generic * pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ if (Q931GetCallState(pTrunk, pMes->CRV) == Q931_U0 && iFrom ==4) {
+ /* Call reference selection */
+ ret = Q931CreateCRV(pTrunk, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+ pMes->CRV = pTrunk->call[callIndex].CRV;
+
+ /* Send RESUME to network */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* Start timer T318 */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T318);
+
+ /* set state U17 */
+ Q931SetState(pTrunk, callIndex, Q931_U17);
+ } else {
+ return Q931E_ILLEGAL_MESSAGE;
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcResumeAckTE
+
+*****************************************************************************/
+L3INT Q931ProcResumeAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcResumeRejectTE
+
+*****************************************************************************/
+L3INT Q931ProcResumeRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSuspendTE
+
+*****************************************************************************/
+L3INT Q931ProcSuspendTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSuspendAckTE
+
+*****************************************************************************/
+L3INT Q931ProcSuspendAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSuspendRejectTE
+
+*****************************************************************************/
+L3INT Q931ProcSuspendRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcInformationTE
+
+*****************************************************************************/
+L3INT Q931ProcUserInformationTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcDisconnectTE
+
+*****************************************************************************/
+L3INT Q931ProcDisconnectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Processing DISCONNECT message from %s for CRV: %d (%#hx)\n",
+ iFrom == 4 ? "Local" : "Remote", pMes->CRV, pMes->CRV);
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcReleaseTE
+
+*****************************************************************************/
+L3INT Q931ProcReleaseTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT state = Q931GetCallState(pTrunk, pMes->CRV);
+ L3INT ret = Q931E_NO_ERROR;
+
+ if (iFrom == 4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (state == Q931_U0 && iFrom == 2) {
+ Q931Tx34(pTrunk, buf, pMes->Size);
+ ret = Q931ReleaseComplete(pTrunk, buf);
+ } else {
+ ret = Q931ProcUnexpectedMessage(pTrunk, buf, iFrom);
+ }
+ if (pMes->CRV && iFrom == 2) {
+ /* Find the call using CRV */
+ if ((Q931FindCRV(pTrunk, pMes->CRV, &callIndex)) != Q931E_NO_ERROR)
+ return ret;
+ pTrunk->call[callIndex].InUse = 0;
+ }
+
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcReleaseCompleteTE
+
+*****************************************************************************/
+L3INT Q931ProcReleaseCompleteTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ } else {
+ if (pMes->CRV) {
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+ pTrunk->call[callIndex].InUse = 0;
+
+ /* TODO: experimental, send RELEASE_COMPLETE message */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcRestartTE
+
+*****************************************************************************/
+L3INT Q931ProcRestartTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ if (pMes->CRV) {
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ }
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+
+ if (pTrunk->autoRestartAck) {
+ Q931AckRestart(pTrunk, buf);
+ }
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcRestartAckTE
+
+*****************************************************************************/
+L3INT Q931ProcRestartAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ if (pMes->CRV) {
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ }
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcCongestionControlTE
+
+*****************************************************************************/
+L3INT Q931ProcCongestionControlTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcInformationTE
+
+*****************************************************************************/
+L3INT Q931ProcInformationTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcNotifyTE
+
+*****************************************************************************/
+L3INT Q931ProcNotifyTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcStatusTE
+
+*****************************************************************************/
+L3INT Q931ProcStatusTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcStatusEnquiryTE
+
+*****************************************************************************/
+L3INT Q931ProcStatusEnquiryTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcSegmentTE
+
+*****************************************************************************/
+L3INT Q931ProcSegmentTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/****************************************************************************/
+/******************* Q.932 - Supplementary Services *************************/
+/****************************************************************************/
+
+/*****************************************************************************
+
+ Function: Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcFacilityTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcHoldTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcHoldAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcHoldRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcRegisterTE
+
+*****************************************************************************/
+L3INT Q932ProcRegisterTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcRetrieveAckTE
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
+
+/*****************************************************************************
+
+ Function: Q931ProcRetrieveRejectTE
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+ Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+ L3INT callIndex;
+ L3INT ret = Q931E_NO_ERROR;
+
+ /* Find the call using CRV */
+ ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+ if (ret != Q931E_NO_ERROR)
+ return ret;
+
+ /* TODO chack against state table for illegal or unexpected message here */
+
+ /* TODO - Set correct timer here */
+ Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+ if (iFrom ==4) {
+ /* TODO Add proc here */
+ ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+ }
+ else if (iFrom == 2) {
+ /* TODO Add proc here */
+ ret = Q931Tx34(pTrunk, buf, pMes->Size);
+ }
+ return ret;
+}
Added: freeswitch/trunk/libs/openzap/src/isdn/Q931api.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/Q931api.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/Q931api.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,598 @@
+/*****************************************************************************
+
+ FileName: Q931api.c
+
+ Contents: api (Application Programming Interface) functions.
+ See q931.h for description.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "Q931.h"
+#include "memory.h"
+
+extern L3INT Q931L4HeaderSpace;
+
+/*
+L3INT Q931CreateMesIndex(L3INT mc)
+{
+ if(mc < 0 || mc > 127 )
+ return Q931E_INTERNAL;
+
+ if(Q931MesCount >127)
+ return Q931E_INTERNAL;
+
+ Q931MesIndex[mc] = Q931MesCount ++;
+
+ return Q931E_NO_ERROR;
+}
+*/
+/*
+L3INT Q931CreateIEIndex(L3INT iec)
+{
+ if(iec < 0 || iec > 127 )
+ return Q931E_INTERNAL;
+
+ if(Q931IECount > 127)
+ return Q931E_INTERNAL;
+
+ Q931IEIndex[iec] = Q931IECount ++;
+
+ return Q931E_NO_ERROR;
+}
+*/
+
+L3INT Q931Api_InitTrunk(Q931_TrunkInfo_t *pTrunk,
+ Q931Dialect_t Dialect,
+ Q931NetUser_t NetUser,
+ Q931_TrunkType_t TrunkType,
+ Q931Tx34CB_t Q931Tx34CBProc,
+ Q931Tx32CB_t Q931Tx32CBProc,
+ Q931ErrorCB_t Q931ErrorCBProc,
+ void *PrivateData32,
+ void *PrivateData34)
+{
+ int y, dchannel, maxchans, has_sync = 0;
+
+ switch(TrunkType)
+ {
+ case Q931_TrType_E1:
+ dchannel = 16;
+ maxchans = 31;
+ has_sync = 1;
+ break;
+
+ case Q931_TrType_T1:
+ case Q931_TrType_J1:
+ dchannel = 24;
+ maxchans = 24;
+ break;
+
+ case Q931_TrType_BRI:
+ case Q931_TrType_BRI_PTMP:
+ dchannel = 3;
+ maxchans = 3;
+ break;
+
+ default:
+ return 0;
+ }
+
+ pTrunk->Q931Tx34CBProc = Q931Tx34CBProc;
+ pTrunk->Q931Tx32CBProc = Q931Tx32CBProc;
+ pTrunk->Q931ErrorCBProc = Q931ErrorCBProc;
+ pTrunk->PrivateData32 = PrivateData32;
+ pTrunk->PrivateData34 = PrivateData34;
+
+ pTrunk->LastCRV = 0;
+ pTrunk->Dialect = Dialect + NetUser;
+ pTrunk->Enabled = 0;
+ pTrunk->TrunkType = TrunkType;
+ pTrunk->NetUser = NetUser;
+ pTrunk->TrunkState = 0;
+ pTrunk->autoRestartAck = 0;
+ for(y=0; y < Q931MAXCHPERTRUNK; y++)
+ {
+ pTrunk->ch[y].Available = 1;
+
+ if(has_sync && y == 0)
+ {
+ pTrunk->ch[y].ChanType = Q931_ChType_Sync;
+ }
+ else if(y == dchannel)
+ {
+ pTrunk->ch[y].ChanType = Q931_ChType_D;
+ }
+ else if(y > maxchans)
+ {
+ pTrunk->ch[y].ChanType = Q931_ChType_NotUsed;
+ }
+ else
+ {
+ pTrunk->ch[y].ChanType = Q931_ChType_B;
+ }
+ }
+
+ for(y=0; y < Q931MAXCALLPERTRUNK; y++)
+ {
+ pTrunk->call[y].InUse = 0;
+
+ }
+ return 1;
+}
+
+void Q931SetMesProc(L3UCHAR mes, L3UCHAR dialect, q931proc_func_t *Q931ProcFunc, q931umes_func_t *Q931UmesFunc, q931pmes_func_t *Q931PmesFunc)
+{
+ if(Q931ProcFunc != NULL)
+ Q931Proc[dialect][mes] = Q931ProcFunc;
+ if(Q931UmesFunc != NULL)
+ Q931Umes[dialect][mes] = Q931UmesFunc;
+ if(Q931PmesFunc != NULL)
+ Q931Pmes[dialect][mes] = Q931PmesFunc;
+}
+
+void Q931SetIEProc(L3UCHAR iec, L3UCHAR dialect, q931pie_func_t *Q931PieProc, q931uie_func_t *Q931UieProc)
+{
+ if(Q931PieProc != NULL)
+ Q931Pie[dialect][iec] = Q931PieProc;
+ if(Q931UieProc != NULL)
+ Q931Uie[dialect][iec] = Q931UieProc;
+}
+
+void Q931SetTimeoutProc(L3UCHAR dialect, L3UCHAR timer, q931timeout_func_t *Q931TimeoutProc)
+{
+ if(Q931Timeout != NULL)
+ Q931Timeout[dialect][timer] = Q931TimeoutProc;
+}
+
+void Q931SetTimerDefault(L3UCHAR dialect, L3UCHAR timer, q931timer_t timeout)
+{
+ Q931Timer[dialect][timer] = timeout;
+}
+
+L3INT Q931GetMesSize(Q931mes_Generic *pMes)
+{
+
+ L3UCHAR *p = &pMes->buf[0];
+ L3INT Size = (L3INT)(p - (L3UCHAR *)pMes);
+ return Size;
+}
+
+/*****************************************************************************
+
+ Function: q931AppendIE
+
+ Description: Append IE to the message.
+
+ Parameters: pm Ptr to message.
+ pi Ptr to information element
+
+ Return Value ie setting
+
+*****************************************************************************/
+
+ie Q931AppendIE( L3UCHAR *pm, L3UCHAR *pi)
+{
+ ie IE = 0;
+ Q931mes_Generic * pMes= (Q931mes_Generic *)pm;
+ Q931ie_BearerCap * pIE= (Q931ie_BearerCap *)pi;
+ L3INT iISize = pIE->Size;
+
+ L3UCHAR *pBuf = &pMes->buf[0];
+ L3INT Off = (L3INT)(pMes->Size - (pBuf - pm));
+ IE = (ie)(Off | 0x8000);
+
+ memcpy(&pm[pMes->Size], pi, iISize);
+
+ pMes->Size += iISize;
+
+ return IE;
+}
+
+/*****************************************************************************
+*****************************************************************************/
+static L3INT crv={1};
+
+L3INT Q931GetUniqueCRV(Q931_TrunkInfo_t *pTrunk)
+{
+ L3INT max = (Q931_IS_BRI(pTrunk)) ? Q931_BRI_MAX_CRV : Q931_PRI_MAX_CRV;
+
+ crv++;
+ crv = (crv <= max) ? crv : 1;
+
+ return crv;
+}
+
+L3INT Q931InitMesGeneric(Q931mes_Generic *pMes)
+{
+ memset(pMes, 0, sizeof(*pMes));
+ pMes->ProtDisc = 0x08;
+ pMes->Size = Q931GetMesSize(pMes);
+
+ return 0;
+}
+
+L3INT Q931InitMesResume(Q931mes_Generic * pMes)
+{
+ pMes->ProtDisc = 0x08;
+ pMes->CRV = 0; /* CRV to be allocated, might be receive*/
+ pMes->MesType = Q931mes_RESUME;
+
+ pMes->Size = Q931GetMesSize(pMes);
+ pMes->CallID = 0; /* Channel Identification */
+ return 0;
+}
+
+L3INT Q931InitMesRestartAck(Q931mes_Generic * pMes)
+{
+ pMes->ProtDisc = 0x08;
+ pMes->CRV = 0; /* CRV to be allocated, might be receive*/
+ pMes->MesType = Q931mes_RESTART_ACKNOWLEDGE;
+
+ pMes->Size = Q931GetMesSize(pMes);
+ pMes->ChanID = 0; /* Channel Identification */
+ pMes->Display = 0;
+ pMes->RestartInd = 0;
+ pMes->RestartWin = 0;
+ return 0;
+}
+
+L3INT Q931InitIEBearerCap(Q931ie_BearerCap *pIE)
+{
+ pIE->IEId = Q931ie_BEARER_CAPABILITY;
+ pIE->Size = sizeof(Q931ie_BearerCap);
+ pIE->CodStand = 0;
+ pIE->ITC = 0;
+ pIE->TransMode = 0;
+ pIE->ITR = 0x10;
+ pIE->RateMul = 0;
+
+ pIE->Layer1Ident = 0;
+ pIE->UIL1Prot = 0; /* User Information Layer 1 Protocol */
+ pIE->SyncAsync = 0; /* Sync/Async */
+ pIE->Negot = 0;
+ pIE->UserRate = 0;
+ pIE->InterRate = 0; /* Intermediate Rate */
+ pIE->NIConTx = 0;
+ pIE->NIConRx = 0;
+ pIE->FlowCtlTx = 0; /* Flow control on Tx */
+ pIE->FlowCtlRx = 0; /* Flow control on Rx */
+ pIE->HDR = 0;
+ pIE->MultiFrame = 0; /* Multi frame support */
+ pIE->Mode = 0;
+ pIE->LLInegot = 0;
+ pIE->Assignor = 0; /* Assignor/assignee */
+ pIE->InBandNeg = 0; /* In-band/out-band negot. */
+ pIE->NumStopBits = 0; /* Number of stop bits */
+ pIE->NumDataBits = 0; /* Number of data bits. */
+ pIE->Parity = 0;
+ pIE->DuplexMode = 0;
+ pIE->ModemType = 0;
+ pIE->Layer2Ident = 0;
+ pIE->UIL2Prot = 0; /* User Information Layer 2 Protocol */
+ pIE->Layer3Ident = 0;
+ pIE->UIL3Prot = 0; /* User Information Layer 3 Protocol */
+ pIE->AL3Info1 = 0;
+ pIE->AL3Info2 = 0;
+
+ return 0;
+}
+
+L3INT Q931InitIEChanID(Q931ie_ChanID *pIE)
+{
+ pIE->IEId = Q931ie_CHANNEL_IDENTIFICATION;
+ pIE->Size = sizeof(Q931ie_ChanID);
+ pIE->IntIDPresent = 0; /* Int. id. present */
+ pIE->IntType = 0; /* Int. type */
+ pIE->PrefExcl = 0; /* Pref./Excl. */
+ pIE->DChanInd = 0; /* D-channel ind. */
+ pIE->InfoChanSel = 0; /* Info. channel selection */
+ pIE->InterfaceID = 0; /* Interface identifier */
+ pIE->CodStand = 0; /* Code standard */
+ pIE->NumMap = 0; /* Number/Map */
+ pIE->ChanMapType = 0; /* Channel type/Map element type */
+ pIE->ChanSlot = 0; /* Channel number/Slot map */
+
+ return 0;
+}
+
+L3INT Q931InitIEProgInd(Q931ie_ProgInd * pIE)
+{
+ pIE->IEId = Q931ie_PROGRESS_INDICATOR;
+ pIE->Size = sizeof(Q931ie_ProgInd);
+ pIE->CodStand = 0; /* Coding standard */
+ pIE->Location = 0; /* Location */
+ pIE->ProgDesc = 0; /* Progress description */
+
+ return 0;
+}
+
+L3INT Q931InitIENetFac(Q931ie_NetFac * pIE)
+{
+ pIE->IEId = Q931ie_NETWORK_SPECIFIC_FACILITIES;
+ pIE->Size = sizeof(Q931ie_NetFac);
+ pIE->LenNetID = 0; /* Length of network facilities id. */
+ pIE->TypeNetID = 0; /* Type of network identification */
+ pIE->NetIDPlan = 0; /* Network identification plan. */
+ pIE->NetFac = 0; /* Network specific facility spec. */
+ pIE->NetID[0] = 0;
+ return 0;
+}
+
+L3INT Q931InitIEDisplay(Q931ie_Display * pIE)
+{
+ pIE->IEId = Q931ie_DISPLAY;
+ pIE->Size = sizeof(Q931ie_Display);
+ pIE->Display[0] = 0;
+ return 0;
+}
+
+L3INT Q931InitIEDateTime(Q931ie_DateTime * pIE)
+{
+ pIE->IEId = Q931ie_DATETIME;
+ pIE->Size = sizeof(Q931ie_DateTime);
+ pIE->Year = 0; /* Year */
+ pIE->Month = 0; /* Month */
+ pIE->Day = 0; /* Day */
+ pIE->Hour = 0; /* Hour */
+ pIE->Minute = 0; /* Minute */
+ pIE->Second = 0; /* Second */
+
+ return 0;
+}
+
+L3INT Q931InitIEKeypadFac(Q931ie_KeypadFac * pIE)
+{
+ pIE->IEId = Q931ie_KEYPAD_FACILITY;
+ pIE->Size = sizeof(Q931ie_KeypadFac);
+ pIE->KeypadFac[0] = 0;
+ return 0;
+}
+
+L3INT Q931InitIESignal(Q931ie_Signal * pIE)
+{
+ pIE->IEId = Q931ie_SIGNAL;
+ pIE->Size = sizeof(Q931ie_Signal);
+ pIE->Signal = 0;
+ return 0;
+}
+
+L3INT Q931InitIECallingNum(Q931ie_CallingNum * pIE)
+{
+ pIE->IEId = Q931ie_CALLING_PARTY_NUMBER;
+ pIE->Size = sizeof(Q931ie_CallingNum);
+ pIE->TypNum = 0; /* Type of number */
+ pIE->NumPlanID = 0; /* Numbering plan identification */
+ pIE->PresInd = 0; /* Presentation indicator */
+ pIE->ScreenInd = 0; /* Screening indicator */
+ pIE->Digit[0] = 0; /* Number digits (IA5) */
+
+ return 0;
+}
+
+L3INT Q931InitIECallingSub(Q931ie_CallingSub * pIE)
+{
+ pIE->IEId = Q931ie_CALLING_PARTY_SUBADDRESS;
+ pIE->Size = sizeof(Q931ie_CallingSub);
+ pIE->TypNum = 0; /* Type of subaddress */
+ pIE->OddEvenInd = 0; /* Odd/Even indicator */
+ pIE->Digit[0] = 0; /* Digits */
+
+ return 0;
+}
+
+L3INT Q931InitIECalledNum(Q931ie_CalledNum * pIE)
+{
+ pIE->IEId = Q931ie_CALLED_PARTY_NUMBER;
+ pIE->Size = sizeof(Q931ie_CalledNum);
+ pIE->TypNum = 0; /* Type of Number */
+ pIE->NumPlanID = 0; /* Numbering plan identification */
+ pIE->Digit[0] = 0; /* Digit (IA5) */
+
+ return 0;
+}
+
+L3INT Q931InitIECalledSub(Q931ie_CalledSub * pIE)
+{
+ pIE->IEId = Q931ie_CALLED_PARTY_SUBADDRESS;
+ pIE->Size = sizeof(Q931ie_CalledSub);
+ pIE->TypNum = 0; /* Type of subaddress */
+ pIE->OddEvenInd = 0; /* Odd/Even indicator */
+ pIE->Digit[0] = 0; /* Digits */
+
+ return 0;
+}
+
+L3INT Q931InitIETransNetSel(Q931ie_TransNetSel * pIE)
+{
+ pIE->IEId = Q931ie_TRANSIT_NETWORK_SELECTION;
+ pIE->Size = sizeof(Q931ie_TransNetSel);
+ pIE->Type = 0; /* Type of network identifier */
+ pIE->NetIDPlan = 0; /* Network idetification plan */
+ pIE->NetID[0] = 0; /* Network identification(IA5) */
+
+ return 0;
+}
+
+L3INT Q931InitIELLComp(Q931ie_LLComp * pIE)
+{
+ pIE->IEId = Q931ie_LOW_LAYER_COMPATIBILITY;
+ pIE->Size = sizeof(Q931ie_LLComp);
+
+ pIE->CodStand = 0; /* Coding standard */
+ pIE->ITransCap = 0; /* Information transfer capability */
+ pIE->NegotInd = 0; /* Negot indic. */
+ pIE->TransMode = 0; /* Transfer Mode */
+ pIE->InfoRate = 0; /* Information transfer rate */
+ pIE->RateMul = 0; /* Rate multiplier */
+ pIE->Layer1Ident = 0; /* Layer 1 ident. */
+ pIE->UIL1Prot = 0; /* User information layer 1 protocol */
+ pIE->SyncAsync = 0; /* Synch/asynch */
+ pIE->Negot = 0; /* Negot */
+ pIE->UserRate = 0; /* User rate */
+ pIE->InterRate = 0; /* Intermediate rate */
+ pIE->NIConTx = 0; /* NIC on Tx */
+ pIE->NIConRx = 0; /* NIC on Rx */
+ pIE->FlowCtlTx = 0; /* Flow control on Tx */
+ pIE->FlowCtlRx = 0; /* Flow control on Rx */
+ pIE->HDR = 0; /* Hdr/no hdr */
+ pIE->MultiFrame = 0; /* Multiframe */
+ pIE->ModeL1 = 0; /* Mode L1 */
+ pIE->NegotLLI = 0; /* Negot. LLI */
+ pIE->Assignor = 0; /* Assignor/Assignor ee */
+ pIE->InBandNeg = 0; /* In-band negot. */
+ pIE->NumStopBits = 0; /* Number of stop bits */
+ pIE->NumDataBits = 0; /* Number of data bits */
+ pIE->Parity = 0; /* Parity */
+ pIE->DuplexMode = 0; /* Duplex Mode */
+ pIE->ModemType = 0; /* Modem type */
+ pIE->Layer2Ident = 0; /* Layer 2 ident. */
+ pIE->UIL2Prot = 0; /* User information layer 2 protocol */
+ pIE->ModeL2 = 0; /* ModeL2 */
+ pIE->Q933use = 0; /* Q.9333 use */
+ pIE->UsrSpcL2Prot = 0; /* User specified layer 2 protocol info */
+ pIE->WindowSize = 0; /* Window size (k) */
+ pIE->Layer3Ident = 0; /* Layer 3 ident */
+ pIE->OptL3Info = 0; /* Optional layer 3 protocol info. */
+ pIE->ModeL3 = 0; /* Mode of operation */
+#if 0
+ pIE->ModeX25op = 0; /* Mode of operation X.25 */
+#endif
+ pIE->DefPackSize = 0; /* Default packet size */
+ pIE->PackWinSize = 0; /* Packet window size */
+ pIE->AddL3Info = 0; /* Additional Layer 3 protocol info */
+
+ return 0;
+}
+
+L3INT Q931InitIEHLComp(Q931ie_HLComp * pIE)
+{
+ pIE->IEId = Q931ie_HIGH_LAYER_COMPATIBILITY;
+ pIE->Size = sizeof(Q931ie_HLComp);
+
+ return 0;
+}
+
+L3INT Q931ProcUnknownMessage(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom)
+{
+ /* TODO: Unhandled paramaters */
+ (void)pTrunk;
+ (void)b;
+ (void)iFrom;
+
+ return 0;
+}
+
+L3INT Q931ProcUnexpectedMessage(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom)
+{
+ /* TODO: Unhandled paramaters */
+ (void)pTrunk;
+ (void)b;
+ (void)iFrom;
+
+ return 0;
+}
+
+L3INT Q931Disconnect(Q931_TrunkInfo_t *pTrunk, L3INT iTo, L3INT iCRV, L3INT iCause)
+{
+ /* TODO: Unhandled paramaters */
+ (void)pTrunk;
+ (void)iTo;
+ (void)iCRV;
+ (void)iCause;
+
+ return 0;
+}
+
+L3INT Q931ReleaseComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+ Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+ ptr->MesType = Q931mes_RELEASE_COMPLETE;
+ ptr->CRVFlag = !(ptr->CRVFlag);
+ return Q931Tx32Data(pTrunk,0,buf,ptr->Size);
+}
+
+L3INT Q931AckRestart(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+ L3INT RetCode;
+
+ Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+ ptr->MesType = Q931mes_RESTART_ACKNOWLEDGE;
+ //if (ptr->CRV) {
+ ptr->CRVFlag = !(ptr->CRVFlag);
+ //}
+
+ RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+ return RetCode;
+}
+
+L3INT Q931AckSetup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+ L3INT RetCode;
+
+ Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+ ptr->MesType = Q931mes_SETUP_ACKNOWLEDGE;
+
+ RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+ return RetCode;
+}
+
+L3INT Q931AckConnect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+ L3INT RetCode;
+
+ Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+ ptr->MesType = Q931mes_CONNECT_ACKNOWLEDGE;
+
+ RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+ return RetCode;
+}
+
+L3INT Q931AckService(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+ L3INT RetCode;
+
+ Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+ ptr->MesType = Q931mes_SERVICE_ACKNOWLEDGE;
+ if (ptr->CRV) {
+ ptr->CRVFlag = !(ptr->CRVFlag);
+ }
+
+ RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+ return RetCode;
+}
+
+Q931_ENUM_NAMES(DIALECT_TYPE_NAMES, DIALECT_STRINGS)
+Q931_STR2ENUM(q931_str2Q931Dialect_type, q931_Q931Dialect_type2str, Q931Dialect_t, DIALECT_TYPE_NAMES, Q931_Dialect_Count)
Added: freeswitch/trunk/libs/openzap/src/isdn/Q931ie.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/Q931ie.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/Q931ie.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3074 @@
+/*****************************************************************************
+
+ FileName: Q931ie.c
+
+ Contents: Information Element Pack/Unpack functions.
+
+ These functions will pack out a Q931 message from the bit
+ packed original format into structs that are easier to process
+ and pack the same structs back into bit fields when sending
+ messages out.
+
+ The messages contains a short for each possible IE. The MSB
+ bit flags the precense of an IE, while the remaining bits
+ are the offset into a buffer to find the actual IE.
+
+ Each IE are supported by 3 functions:
+
+ Q931Pie_XXX Pack struct into Q.931 IE
+ Q931Uie_XXX Unpack Q.931 IE into struct
+ Q931InitIEXXX Initialize IE (see Q931api.c).
+
+ Dialect Note: This file will only contain standard DSS1 IE. Other IE as
+ used in QSIG, NI2, Q.932 etc are located in separate files.
+
+ See q931.h for description.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "Q931.h"
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+#if (_MSC_VER >= 1400) /* VC8+ */
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+#ifndef _CRT_NONSTDC_NO_DEPRECATE
+#define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+#endif
+#ifndef strcasecmp
+#define strcasecmp(s1, s2) _stricmp(s1, s2)
+#endif
+#ifndef strncasecmp
+#define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n)
+#endif
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#endif
+
+/*****************************************************************************
+
+ Macro: Q931MoreIE
+
+ Description: Local helper macro detecting if there is more IE space left
+ based on the 3 standard parameters Octet, Off and IESpace.
+ This can be used to test if the IE is completed to avoid
+ that the header of the next IE is interpreted as a part of
+ the current IE.
+
+*****************************************************************************/
+#define Q931MoreIE() (Octet + Off - 2 < IESize)
+
+#define Q931IESizeTest(x) {\
+ if (Octet + Off - 2 != IESize) {\
+ Q931SetError(pTrunk, x, Octet, Off);\
+ return x;\
+ }\
+}
+
+/*****************************************************************************
+
+ Function: Q931ReadExt
+
+ Description: Many of the octets in the standard have an MSB 'ext.1'. This
+ means that the octet usually is the latest octet, but that a
+ futhure standard may extend the octet. A stack must be able
+ to handle such extensions by skipping the extension octets.
+
+ This function will increase the offset counter with 1 for
+ each octet with an MSB of zero. This will allow the stack to
+ skip extensions wihout knowing anything about them.
+
+ Parameters: IBuf ptr to octet array.
+ Off Starting offset counter
+
+ Return Value: New offset value.
+
+*****************************************************************************/
+
+L3INT Q931ReadExt(L3UCHAR * IBuf, L3INT Off)
+{
+ L3INT c = 0;
+ while ((IBuf[c] & 0x80) == 0) {
+ c++;
+ }
+ return Off + c;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_BearerCap
+
+ Description: Unpack a bearer capability ie.
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+
+L3INT Q931Uie_BearerCap(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_BearerCap *pie = (Q931ie_BearerCap*)OBuf;
+ ie *pIE = &pMsg->BearerCap;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+ *pIE = 0;
+
+ /* Octet 1 */
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->CodStand = ieGetOctet((IBuf[Octet] & 0x60) >> 5);
+ pie->ITC = ieGetOctet(IBuf[Octet] & 0x1f);
+ Off = Q931ReadExt(&IBuf[Octet], Off);
+ Octet++;
+
+ /* Octet 4 */
+ pie->TransMode = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+ pie->ITR = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+ Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+ Octet++;
+
+ /* Octet 4.1. Rate multiplier is only present if ITR = Multirate */
+ if (pie->ITR == 0x18) {
+ pie->RateMul = ieGetOctet(IBuf[Octet + Off] & 0x7f);
+ Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+ Off ++;
+ }
+
+ /* Octet 5 */
+ if ((IBuf[Octet + Off] & 0x60) == 0x20 && Q931MoreIE()) {
+ pie->Layer1Ident = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+ pie->UIL1Prot = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+ Octet++;
+
+ /* Octet 5a. The octet may be present if ITC is unrestrictd digital info
+ * and UIL1Prot is either V.110, I.460 and X.30 or V.120. It may also
+ * be present if ITC = 3.1 kHz audio and UIL1Prot is G.711.
+ * Bit 8 of Octet 5 = 0 indicates that 5a is present.
+ */
+
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ if (((pie->ITC == 0x08) && (pie->UIL1Prot == 0x01 || pie->UIL1Prot == 0x08))
+ || ((pie->ITC == 0x10) && (pie->UIL1Prot == 0x02 || pie->UIL1Prot == 0x03))) {
+ pie->SyncAsync = ieGetOctet((IBuf[Octet + Off] & 0x40) >> 6);
+ pie->Negot = ieGetOctet((IBuf[Octet + Off] & 0x20) >> 5);
+ pie->UserRate = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+ Off ++;
+ }
+ else {
+ /* We have detected bit 8 = 0, but no setting that require the */
+ /* additional octets ??? */
+ Q931SetError(pTrunk, Q931E_BEARERCAP, 5,Off);
+ return Q931E_BEARERCAP;
+ }
+
+ /* Octet 5b. Two different structures used. */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ if (pie->UIL1Prot == 0x01) { /* ITU V.110, I.460 and X.30 */
+ pie->InterRate = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+ pie->NIConTx = ieGetOctet((IBuf[Octet + Off] & 0x10) >> 4);
+ pie->NIConRx = ieGetOctet((IBuf[Octet + Off] & 0x08) >> 3);
+ pie->FlowCtlTx = ieGetOctet((IBuf[Octet + Off] & 0x04) >> 2);
+ pie->FlowCtlRx = ieGetOctet((IBuf[Octet + Off] & 0x20) >> 1);
+ Off++;
+ }
+ else if (pie->UIL1Prot == 0x08) { /* ITU V.120 */
+ pie->HDR = ieGetOctet((IBuf[Octet + Off] & 0x40) >> 6);
+ pie->MultiFrame = ieGetOctet((IBuf[Octet + Off] & 0x20) >> 5);
+ pie->Mode = ieGetOctet((IBuf[Octet + Off] & 0x10) >> 4);
+ pie->LLInegot = ieGetOctet((IBuf[Octet + Off] & 0x08) >> 3);
+ pie->Assignor = ieGetOctet((IBuf[Octet + Off] & 0x04) >> 2);
+ pie->InBandNeg = ieGetOctet((IBuf[Octet + Off] & 0x02) >> 1);
+ Off++;
+ }
+ else {
+ Q931SetError(pTrunk,Q931E_BEARERCAP, 5,Off);
+ return Q931E_BEARERCAP;
+ }
+
+ /* Octet 5c */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ pie->NumStopBits = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+ pie->NumDataBits = ieGetOctet((IBuf[Octet + Off] & 0x18) >> 3);
+ pie->Parity = ieGetOctet(IBuf[Octet + Off] & 0x07);
+ Off++;
+
+ /* Octet 5d */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ pie->DuplexMode = ieGetOctet((IBuf[Octet + Off] & 0x40) >> 6);
+ pie->ModemType = ieGetOctet(IBuf[Octet + Off] & 0x3f);
+ Off ++;
+ }
+ }
+ }
+ }
+ }
+
+ /* Octet 6 */
+ if ((IBuf[Octet + Off] & 0x60) == 0x40 && Q931MoreIE()) {
+ pie->Layer2Ident = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+ pie->UIL2Prot = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+
+ Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+ Octet ++;
+ }
+
+ /* Octet 7 */
+ if ((IBuf[Octet + Off] & 0x60) == 0x60 && Q931MoreIE()) {
+ pie->Layer3Ident = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+ pie->UIL3Prot = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+ Octet++;
+
+ /* Octet 7a */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ if (pie->UIL3Prot == 0x0c) {
+ pie->AL3Info1 = ieGetOctet(IBuf[Octet + Off] & 0x0f);
+ Off++;
+
+ /* Octet 7b */
+ if (IsQ931Ext(IBuf[Octet + Off])) {
+ pie->AL3Info2 = ieGetOctet(IBuf[Octet + Off] & 0x0f);
+ Off++;
+ }
+ }
+ else {
+ Q931SetError(pTrunk,Q931E_BEARERCAP, 7, Off);
+ return Q931E_BEARERCAP;
+
+ }
+ }
+ }
+
+ Q931IESizeTest(Q931E_BEARERCAP);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_BearerCap);
+ pie->Size = sizeof(Q931ie_BearerCap);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_BearerCap
+
+ Description: Packing a Q.931 Bearer Capability element from a generic
+ struct into a packed octet structure in accordance with the
+ standard.
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+
+L3INT Q931Pie_BearerCap(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_BearerCap *pIE = (Q931ie_BearerCap*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet; /* remember current offset */
+ L3INT li;
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Encoding Bearer Capability IE\n");
+
+ OBuf[(*Octet)++] = Q931ie_BEARER_CAPABILITY ;
+ li = (*Octet)++; /* remember length position */
+
+ /* Octet 3 - Coding standard / Information transfer capability */
+ OBuf[(*Octet)++] = 0x80 | ((pIE->CodStand << 5) & 0x60) | (pIE->ITC & 0x1f);
+
+ /* Octet 4 - Transfer mode / Information transfer rate */
+ OBuf[(*Octet)++] = 0x80 | ((pIE->TransMode << 5) & 0x60) | (pIE->ITR & 0x1f);
+
+ if (pIE->ITR == 0x18) {
+ /* Octet 4.1 - Rate Multiplier */
+ OBuf[(*Octet)++] = 0x80 | (pIE->RateMul & 0x7f);
+ }
+
+ /* Octet 5 - Layer 1 Ident / User information layer 1 protocol */
+ if (pIE->Layer1Ident == 0x01) {
+ if (((pIE->ITC == 0x08) && (pIE->UIL1Prot == 0x01 || pIE->UIL1Prot == 0x08)) ||
+ ((pIE->ITC == 0x10) && (pIE->UIL1Prot == 0x02 || pIE->UIL1Prot == 0x03))) {
+ OBuf[(*Octet)++] = 0x00 | ((pIE->Layer1Ident << 5) & 0x60) | (pIE->UIL1Prot & 0x15);
+
+ /* Octet 5a - SyncAsync/Negot/UserRate */
+ OBuf[(*Octet)++] = 0x00 | ((pIE->SyncAsync << 6) & 0x40) | ((pIE->Negot << 5) & 0x20) | (pIE->UserRate & 0x1f);
+
+ /* Octet 5b - one of two types */
+ if (pIE->UIL1Prot == 0x01) { /* ITU V.110, I.460 and X.30 */
+ /* Octet 5b - Intermed rate/ Nic on Tx/Nix on Rx/FlowCtlTx/FlowCtlRx */
+ OBuf[(*Octet)++] = 0x00
+ | ((pIE->InterRate << 6) & 0x60)
+ | ((pIE->NIConTx << 4) & 0x10)
+ | ((pIE->NIConRx << 3) & 0x08)
+ | ((pIE->FlowCtlTx << 2) & 0x04)
+ | ((pIE->FlowCtlRx << 1) & 0x02);
+ }
+ else if (pIE->UIL1Prot == 0x08) { /* ITU V.120 */
+ /* Octet 5b - HDR/Multiframe/Mode/LLINegot/Assignor/Inbandneg*/
+ OBuf[(*Octet)++] = 0x00
+ | ((pIE->InterRate << 6) & 0x60)
+ | ((pIE->MultiFrame << 5) & 0x20)
+ | ((pIE->Mode << 4) & 0x10)
+ | ((pIE->LLInegot << 3) & 0x08)
+ | ((pIE->Assignor << 2) & 0x04)
+ | ((pIE->InBandNeg << 1) & 0x02);
+ }
+
+ /* Octet 5c - NumStopBits/NumStartBits/Parity */
+ OBuf[(*Octet)++] = 0x00
+ | ((pIE->NumStopBits << 5) & 0x60)
+ | ((pIE->NumDataBits << 3) & 0x18)
+ | (pIE->Parity & 0x07);
+
+ /* Octet 5d - Duplex Mode/Modem Type */
+ OBuf[(*Octet)++] = 0x80 | ((pIE->DuplexMode << 6) & 0x40) | (pIE->ModemType & 0x3f);
+ }
+ else {
+ OBuf[(*Octet)++] = 0x80 | ((pIE->Layer1Ident << 5) & 0x60) | (pIE->UIL1Prot & 0x1f);
+ }
+ }
+
+ /* Octet 6 - Layer2Ident/User information layer 2 prtocol */
+ if (pIE->Layer2Ident == 0x02) {
+ OBuf[(*Octet)++] = 0x80 | ((pIE->Layer2Ident << 5) & 0x60) | (pIE->UIL2Prot & 0x1f);
+ }
+
+ /* Octet 7 - Layer 3 Ident/ User information layer 3 protocol */
+ if (pIE->Layer3Ident == 0x03) {
+ if (pIE->UIL3Prot == 0x0c) {
+ OBuf[(*Octet)++] = 0x00 | ((pIE->Layer3Ident << 5) & 0x60) | (pIE->UIL3Prot & 0x1f);
+
+ /* Octet 7a - Additional information layer 3 msb */
+ OBuf[(*Octet)++] = 0x00 | (pIE->AL3Info1 & 0x0f);
+
+ /* Octet 7b - Additional information layer 3 lsb */
+ OBuf[(*Octet)++] = 0x80 | (pIE->AL3Info2 & 0x0f);
+ }
+ else {
+ OBuf[(*Octet)++] = 0x80 | ((pIE->Layer3Ident << 5) & 0x60) | (pIE->UIL3Prot & 0x1f);
+ }
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_CallID
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CallID(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_CallID *pie = (Q931ie_CallID*)OBuf;
+ ie *pIE = &pMsg->CallID;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT x = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ /* Octet 1 */
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ do {
+ pie->CallId[x] = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ x++;
+ } while (Q931MoreIE());
+
+ Q931IESizeTest(Q931E_CALLID);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_CallID) + x - 1;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_CallID) + x - 1);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_CallID
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+
+L3INT Q931Pie_CallID(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_CallID *pIE = (Q931ie_CallID*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;/* remember current offset */
+ L3INT li;
+ L3INT sCI = pIE->Size - sizeof(Q931ie_CallID) + 1;
+ L3INT x;
+
+ OBuf[(*Octet)++] = Q931ie_CALL_IDENTITY ;
+ li = (*Octet)++; /* remember length position */
+
+ for (x = 0; x < sCI; x++) {
+ OBuf[(*Octet)++] = pIE->CallId[x];
+ }
+
+ OBuf[(*Octet) - 1] |= 0x80; /* set complete flag at last octet*/
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_CallState
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CallState(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_CallState *pie = (Q931ie_CallState*)OBuf;
+ ie *pIE = &pMsg->CallState;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ /* Octet 1 */
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->CodStand = (IBuf[Octet + Off] >> 6) & 0x03;
+ pie->CallState = IBuf[Octet + Off] & 0x3f;
+ Octet++;
+
+ Q931IESizeTest(Q931E_CALLSTATE);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_CallState);
+ pie->Size = sizeof(Q931ie_CallState);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_CallState
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CallState(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_CallState *pIE = (Q931ie_CallState*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet; /* remember current offset */
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_CALL_STATE;
+ li = (*Octet)++; /* remember length position */
+
+ OBuf[(*Octet)++] = (pIE->CodStand << 6) | (pIE->CallState & 0x3f);
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_CalledSub
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CalledSub(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_CalledSub *pie = (Q931ie_CalledSub*)OBuf;
+ ie *pIE = &pMsg->CalledSub;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT x;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ /* Octet 1 */
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->TypNum = (IBuf[Octet + Off] >> 4) & 0x07;
+ pie->OddEvenInd = (IBuf[Octet + Off] >> 3) & 0x01;
+ Octet++;
+
+ /* Octet 4 */
+ x = 0;
+ do {
+ pie->Digit[x] = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ x++;
+ } while (Q931MoreIE() && x < 20);
+
+ Q931IESizeTest(Q931E_CALLEDSUB);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_CalledSub) + x - 1;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_CalledSub) + x - 1);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_CalledSub
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CalledSub(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_CalledSub *pIE = (Q931ie_CalledSub*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+ L3INT sN = pIE->Size - sizeof(Q931ie_CalledSub) + 1;
+ L3INT x;
+
+ /* Octet 1 */
+ OBuf[(*Octet)++] = Q931ie_CALLED_PARTY_SUBADDRESS;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = 0x80 | (pIE->TypNum << 4) | (pIE->OddEvenInd << 3);
+
+ /* Octet 4 */
+ for (x = 0; x<sN; x++) {
+ OBuf[(*Octet)++] = pIE->Digit[x];
+ }
+
+ OBuf[(*Octet) - 1] |= 0x80; /* Terminate bit */
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_CalledNum
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CalledNum(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_CalledNum *pie = (Q931ie_CalledNum*)OBuf;
+ ie *pIE = &pMsg->CalledNum;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT x;
+ L3INT IESize; /* # digits in this case */
+
+ *pIE = 0;
+
+ /* Octet 1 */
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->TypNum = (IBuf[Octet + Off] >> 4) & 0x07;
+ pie->NumPlanID = IBuf[Octet + Off] & 0x0f;
+ Octet++;
+
+ /* Octet 4*/
+ x = 0;
+ do {
+ pie->Digit[x] = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ x++;
+ } while ((IBuf[Octet + Off]&0x80) == 0 && Q931MoreIE());
+
+ pie->Digit[x] = '\0';
+
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_CalledNum) + x;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_CalledNum) + x);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_CalledNum
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CalledNum(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_CalledNum *pIE = (Q931ie_CalledNum*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+ L3INT sN = pIE->Size - sizeof(Q931ie_CalledNum);
+ L3INT x;
+
+ /* Octet 1 */
+ OBuf[(*Octet)++] = Q931ie_CALLED_PARTY_NUMBER;
+
+ /* Octet 2 */
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = 0x80 | (pIE->TypNum << 4) | (pIE->NumPlanID);
+
+ /* Octet 4 */
+ for (x = 0; x<sN; x++) {
+ OBuf[(*Octet)++] = pIE->Digit[x];
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_CallingNum
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CallingNum(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_CallingNum *pie = (Q931ie_CallingNum*)OBuf;
+ ie *pIE = &pMsg->CallingNum;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT x;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ /* Octet 1 */
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->TypNum = (IBuf[Octet + Off] >> 4) & 0x07;
+ pie->NumPlanID = IBuf[Octet + Off] & 0x0f;
+
+ /* Octet 3a */
+ if ((IBuf[Octet + Off] & 0x80) == 0) {
+ Off++;
+ pie->PresInd = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->ScreenInd = IBuf[Octet + Off] & 0x03;
+ }
+ Octet++;
+
+ /* Octet 4 */
+ x = 0;
+ while (Q931MoreIE()) {
+ pie->Digit[x++] = IBuf[Octet + Off] & 0x7f;
+
+ if ((IBuf[Octet + Off] & 0x80) != 0) {
+ break;
+ }
+ Off++;
+ }
+ pie->Digit[x] = '\0';
+
+ Q931IESizeTest(Q931E_CALLINGNUM);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_CallingNum) + x;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_CallingNum) + x);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_CallingNum
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CallingNum(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_CallingNum *pIE = (Q931ie_CallingNum*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+ L3INT sN = pIE->Size - sizeof(Q931ie_CallingNum);
+ L3INT x;
+
+ /* Octet 1 */
+ OBuf[(*Octet)++] = Q931ie_CALLING_PARTY_NUMBER;
+
+ /* Octet 2 */
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = 0x00 | (pIE->TypNum << 4) | (pIE->NumPlanID);
+
+ /* Octet 4 */
+ OBuf[(*Octet)++] = 0x80;
+
+ /* Octet 5 */
+ for (x = 0; x<sN; x++) {
+ OBuf[(*Octet)++] = pIE->Digit[x];
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_CallingSub
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CallingSub(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_CallingSub *pie = (Q931ie_CallingSub*)OBuf;
+ ie *pIE = &pMsg->CallingSub;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT x;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ /* Octet 1 */
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->TypNum = (IBuf[Octet + Off] >> 4) & 0x07;
+ pie->OddEvenInd = (IBuf[Octet + Off] >> 3) & 0x01;
+ Octet++;
+
+ /* Octet 4*/
+ x = 0;
+ do {
+ pie->Digit[x] = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ x++;
+ } while (Q931MoreIE() && x < 20);
+
+ Q931IESizeTest(Q931E_CALLINGSUB);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_CallingSub) + x -1;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_CallingSub) + x -1);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_CallingSub
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CallingSub(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_CallingSub *pIE = (Q931ie_CallingSub*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+ L3INT sN = pIE->Size - sizeof(Q931ie_CallingSub) + 1;
+ L3INT x;
+
+ /* Octet 1 */
+ OBuf[(*Octet)++] = Q931ie_CALLING_PARTY_SUBADDRESS;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = 0x80 | (pIE->TypNum << 4) | (pIE->OddEvenInd << 3);
+
+ /* Octet 4 */
+ for (x = 0; x<sN; x++) {
+ OBuf[(*Octet)++] = pIE->Digit[x];
+ }
+
+ OBuf[(*Octet) - 1] |= 0x80; /* Terminate bit */
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_Cause
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_Cause(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_Cause *pie = (Q931ie_Cause*)OBuf;
+ ie *pIE = &pMsg->Cause;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2*/
+ IESize = IBuf[Octet++];
+
+ /* Octet 3*/
+ pie->CodStand = (IBuf[Octet + Off]>>5) & 0x03;
+ pie->Location = IBuf[Octet + Off] & 0x0f;
+
+ /* Octet 3a */
+ if ((IBuf[Octet + Off] & 0x80) == 0) {
+ Off++;
+ pie->Recom = IBuf[Octet + Off] & 0x7f;
+ }
+ Octet++;
+
+ /* Octet 4 */
+ pie->Value = IBuf[Octet + Off] & 0x7f;
+ Octet++;
+
+ /* Consume optional Diagnostic bytes */
+ while (Q931MoreIE()) {
+ Off++;
+ };
+
+ Q931IESizeTest(Q931E_CAUSE);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_Cause);
+ pie->Size = sizeof(Q931ie_Cause);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_Cause
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_Cause(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_Cause *pIE = (Q931ie_Cause*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_CAUSE;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = 0x80 | (pIE->CodStand<<5) | pIE->Location;
+
+ /* Octet 3a - currently not supported in send */
+
+ /* Octet 4 */
+ OBuf[(*Octet)++] = 0x80 | pIE->Value;
+
+ /* Octet 5 - diagnostics not supported in send */
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_CongLevel
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CongLevel(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_CongLevel *pie = (Q931ie_CongLevel*)OBuf;
+ ie *pIE = &pMsg->CongestionLevel;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet] & 0xf0;
+ pie->CongLevel = IBuf[Octet] & 0x0f;
+ Octet ++;
+
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_CongLevel);
+ pie->Size = sizeof(Q931ie_CongLevel);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_CongLevel
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CongLevel(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_CongLevel *pIE = (Q931ie_CongLevel*)IBuf;
+ L3INT rc = 0;
+ /* L3INT Beg = *Octet; */
+
+ OBuf[(*Octet)++] = Q931ie_CONGESTION_LEVEL | pIE->CongLevel;
+
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_ChanID
+
+ Parameters: IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Uie_ChanID(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_ChanID *pie = (Q931ie_ChanID*)OBuf;
+ ie *pIE = &pMsg->ChanID;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+//18 04 e1 80 83 01
+ *pIE = 0;
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Decoding ChanID IE\n");
+
+ /* Octet 1 */
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->IntIDPresent = (IBuf[Octet] >> 6) & 0x01;
+ pie->IntType = (IBuf[Octet] >> 5) & 0x01;
+ pie->PrefExcl = (IBuf[Octet] >> 3) & 0x01;
+ pie->DChanInd = (IBuf[Octet] >> 2) & 0x01;
+ pie->InfoChanSel = IBuf[Octet] & 0x03;
+
+ Off = Q931ReadExt(&IBuf[Octet++], Off);
+
+ /* Octet 3.1 */
+ if (pie->IntIDPresent) {
+ pie->InterfaceID = IBuf[Octet + Off] & 0x7f;
+
+ /* Temp fix. Interface id can be extended using the extension bit */
+ /* this will read the octets, but do nothing with them. this is done */
+ /* because the usage of this field is a little unclear */
+ /* 30.jan.2001/JVB */
+ Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+ Off++;
+ }
+
+ if ((Octet + Off - 2) != IESize) {
+ /* Octet 3.2 */
+ if (pie->IntType == 1) { /* PRI etc */
+ pie->CodStand = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->NumMap = (IBuf[Octet + Off] >> 4) & 0x01;
+ pie->ChanMapType = IBuf[Octet + Off] & 0x0f;
+ Off++;
+
+ /* Octet 3.3 */
+ /* Temp fix. Assume B channel. H channels not supported */
+ pie->ChanSlot = IBuf[Octet + Off] & 0x7f;
+
+ /* Some dialects don't follow the extension coding properly for this, but this should be safe for all */
+ if ((Octet + Off - 1) != IESize) {
+ Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+ }
+ Off++;
+ }
+ }
+
+ Q931IESizeTest(Q931E_CHANID);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_ChanID);
+ pie->Size = sizeof(Q931ie_ChanID);
+
+ if (pTrunk->loglevel == Q931_LOG_DEBUG) {
+ const char *iface;
+ char tmp[100] = "";
+
+ if (!pie->IntType) {
+ switch (pie->InfoChanSel) {
+ case 0x0:
+ iface = "None";
+ break;
+ case 0x1:
+ iface = "B1";
+ break;
+ case 0x2:
+ iface = "B2";
+ break;
+ default:
+ iface = "Any Channel";
+ }
+
+ snprintf(tmp, sizeof(tmp)-1, "InfoChanSel: %d (%s)", pie->InfoChanSel, iface);
+ }
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG,
+ "\n-------------------------- Q.931 Channel ID ------------------------\n"
+ " Pref/Excl: %s, Interface Type: %s\n"
+ " %s\n"
+ "--------------------------------------------------------------------\n\n",
+ ((pie->PrefExcl) ? "Preferred" : "Exclusive"),
+ ((pie->IntType) ? "PRI/Other" : "BRI"),
+ tmp);
+ }
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_ChanID
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_ChanID(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_ChanID *pIE = (Q931ie_ChanID*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet; /* remember current offset */
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_CHANNEL_IDENTIFICATION;
+ li = (*Octet)++; /* remember length position */
+
+ /* Octet 3 flags & BRI chan # */
+ OBuf[(*Octet)++] = 0x80
+ | ((pIE->IntIDPresent << 6) & 0x40)
+ | ((pIE->IntType << 5) & 0x20)
+ | ((pIE->PrefExcl << 3) & 0x08)
+ | (pIE->InfoChanSel & 0x03);
+
+ /* Octet 3.1 - Interface Identifier */
+ if (pIE->IntIDPresent) {
+ OBuf[(*Octet)++] = 0x80 | (pIE->InterfaceID & 0x7f);
+ }
+
+ /* Octet 3.2 & 3.3 - PRI */
+ if (pIE->IntType) {
+ OBuf[(*Octet)++] = 0x80
+ | ((pIE->CodStand << 5) & 0x60)
+ | ((pIE->NumMap << 4) & 0x10)
+ | (pIE->ChanMapType & 0x0f); /* TODO: support all possible channel map types */
+
+ /* Octet 3.3 Channel number */
+ switch (pIE->ChanMapType) {
+ case 0x6: /* Slot map: H0 Channel Units */ /* unsupported, Octets 3.3.1 - 3.3.3 */
+ return Q931E_CHANID;
+
+ case 0x8: /* Slot map: H11 Channel Units */
+ case 0x9: /* Slot map: H12 Channel Units */
+ default: /* Channel number */
+ OBuf[(*Octet)++] = 0x80 | (pIE->ChanSlot & 0x7f);
+ break;
+ }
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+
+/*****************************************************************************
+
+ Function: Q931Uie_CRV
+
+ Description: Reading CRV.
+
+ The CRV is currently returned in the return value that
+ Q921Rx23 will assign to the CRV field in the unpacked
+ message. CRV is basically 2 bytes etc, but the spec allows
+ the use of longer CRV values.
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: CRV
+
+*****************************************************************************/
+L3USHORT Q931Uie_CRV(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff)
+{
+ L3USHORT CRV = 0;
+ L3INT Octet = *IOff;
+ L3INT l = IBuf[Octet++];
+
+ if (l == 1) { /* One octet CRV */
+ CRV = IBuf[Octet++] & 0x7F;
+ }
+ else if (l == 2) { /* two octet CRV */
+ CRV = (IBuf[Octet++] & 0x7f) << 8;
+ CRV |= IBuf[Octet++];
+ }
+ else {
+ /* Long CRV is not used, so we skip this */
+ /* TODO: is it right to set to 0 here? */
+ CRV = 0;
+ Octet += l;
+ }
+
+ *IOff = Octet;
+ return CRV;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_DateTime
+
+ Parameters: pTrunk [IN] Ptr to trunk information.
+ pIE [OUT] ptr to Information Element id.
+ IBuf [IN] ptr to a packed ie.
+ OBuf [OUT] ptr to buffer for Unpacked ie.
+ IOff [IN\OUT] Input buffer offset
+ OOff [IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_DateTime(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_DateTime * pie = (Q931ie_DateTime*)OBuf;
+ ie *pIE = &pMsg->DateTime;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize = 0;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 - Year */
+ pie->Year = IBuf[Octet++];
+
+ /* Octet 4 - Month */
+ pie->Month = IBuf[Octet++];
+
+ /* Octet 5 - Day */
+ pie->Day = IBuf[Octet++];
+
+ /*******************************************************************
+ The remaining part of the IE are optioinal, but only the length
+ can now tell us wherever these fields are present or not
+ (always remember: IESize does not include ID and Size octet)
+ ********************************************************************/
+ pie->Format = 0;
+
+ /* Octet 6 - Hour (optional)*/
+ if (IESize >= 4) {
+ pie->Format = 1;
+ pie->Hour = IBuf[Octet++];
+
+ /* Octet 7 - Minute (optional)*/
+ if (IESize >= 5) {
+ pie->Format = 2;
+ pie->Minute = IBuf[Octet++];
+
+ /* Octet 8 - Second (optional)*/
+ if (IESize >= 6) {
+ pie->Format = 3;
+ pie->Second = IBuf[Octet++];
+ }
+ }
+ }
+
+ Q931IESizeTest(Q931E_DATETIME);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_DateTime);
+ pie->Size = sizeof(Q931ie_DateTime);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_DateTime
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_DateTime(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_DateTime *pIE = (Q931ie_DateTime*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_DATETIME;
+ li = (*Octet)++;
+
+ OBuf[(*Octet)++] = pIE->Year;
+ OBuf[(*Octet)++] = pIE->Month;
+ OBuf[(*Octet)++] = pIE->Day;
+ if (pIE->Format >= 1) {
+ OBuf[(*Octet)++] = pIE->Hour;
+
+ if (pIE->Format >= 2) {
+ OBuf[(*Octet)++] = pIE->Minute;
+
+ if (pIE->Format >= 3) {
+ OBuf[(*Octet)++] = pIE->Second;
+ }
+ }
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet)-Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_Display
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_Display(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_Display *pie = (Q931ie_Display*)OBuf;
+ ie *pIE = &pMsg->Display;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+ L3INT x;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+ IESize = IBuf[Octet++];
+
+ for (x = 0; x<IESize; x++) {
+ pie->Display[x] = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+
+ Q931IESizeTest(Q931E_DISPLAY);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_Display) + x - 1;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_Display) + x - 1);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_Display
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_Display(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_Display *pIE = (Q931ie_Display*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+ L3INT DSize;
+ L3INT x;
+
+ OBuf[(*Octet)++] = Q931ie_DISPLAY;
+ li = (*Octet)++;
+
+ DSize = pIE->Size - sizeof(Q931ie_Display);
+
+ for (x = 0; x< DSize; x++) {
+
+ OBuf[(*Octet)++] = pIE->Display[x];
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_HLComp
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_HLComp(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_HLComp * pie = (Q931ie_HLComp*)OBuf;
+ ie *pIE = &pMsg->HLComp;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3*/
+ pie->CodStand = (IBuf[Octet + Off] >>5) & 0x03;
+ pie->Interpret = (IBuf[Octet + Off] >>2) & 0x07;
+ pie->PresMeth = IBuf[Octet + Off] & 0x03;
+ Octet++;
+
+ /* Octet 4 */
+ pie->HLCharID = IBuf[Octet + Off] & 0x7f;
+ Octet++;
+
+ /* Octet 4a*/
+ if ((IBuf[Octet + Off - 1] & 0x80) == 0 && Q931MoreIE()) {
+ if (pie->HLCharID == 0x5e || pie->HLCharID == 0x5f) {
+ pie->EHLCharID = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+ else if ( pie->HLCharID >= 0xc3 && pie->HLCharID <= 0xcf) {
+ pie->EVideoTlfCharID = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+ else {
+ /* error Octet 4a indicated, but invalid value in Octet 4. */
+ Q931SetError(pTrunk,Q931E_HLCOMP, 4, Off);
+ return Q931E_HLCOMP;
+ }
+ Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+ }
+
+ Q931IESizeTest(Q931E_HLCOMP);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_HLComp);
+ pie->Size = sizeof(Q931ie_HLComp);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_HLComp
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_HLComp(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_HLComp *pIE = (Q931ie_HLComp*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_HIGH_LAYER_COMPATIBILITY;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = 0x80 | ((pIE->CodStand << 5) & 0x60) | ((pIE->Interpret << 2) & 0x1c) | (pIE->PresMeth & 0x03);
+
+ /* Octet 4 */
+ OBuf[(*Octet)++] = pIE->HLCharID;
+
+ /* Octet 4a */
+ if (pIE->HLCharID == 0x5e || pIE->HLCharID == 0x5f) {
+ OBuf[(*Octet)++] = 0x80 | (pIE->EHLCharID & 0x7f);
+ }
+ else if ( pIE->HLCharID >= 0xc3 && pIE->HLCharID <= 0xcf) {
+ OBuf[(*Octet)++] = 0x80 | (pIE->EVideoTlfCharID & 0x7f);
+ }
+ else {
+ OBuf[(*Octet) - 1] |= 0x80;
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_KeypadFac
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_KeypadFac(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_KeypadFac *pie = (Q931ie_KeypadFac*)OBuf;
+ ie *pIE = &pMsg->KeypadFac;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+ L3INT x;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+ IESize = IBuf[Octet++];
+
+ for (x = 0; x<IESize; x++) {
+ pie->KeypadFac[x] = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+
+ Q931IESizeTest(Q931E_KEYPADFAC);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_KeypadFac) + x - 1;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_KeypadFac) + x - 1);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_KeypadFac
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_KeypadFac(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_KeypadFac *pIE = (Q931ie_KeypadFac*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+ L3INT DSize;
+ L3INT x;
+
+ OBuf[(*Octet)++] = Q931ie_KEYPAD_FACILITY;
+ li = (*Octet)++;
+
+ DSize = pIE->Size - sizeof(Q931ie_KeypadFac) + 1;
+
+ for (x = 0; x< DSize; x++) {
+ OBuf[(*Octet)++] = pIE->KeypadFac[x];
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_LLComp
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_LLComp(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_LLComp *pie = (Q931ie_LLComp*)OBuf;
+ ie *pIE = &pMsg->LLComp;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->CodStand = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->ITransCap = IBuf[Octet + Off] & 0x1f;
+ Octet++;
+
+ /* Octet 3a*/
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ pie->NegotInd = (IBuf[Octet + Off] >> 6) & 0x01;
+ Off++;
+ }
+
+ /* Octet 4 */
+ pie->TransMode = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->InfoRate = IBuf[Octet + Off] & 0x1f;
+
+ Octet++;
+
+ /* Octet 4.1 */
+ if (pie->InfoRate == 0x14) { /* Mutirate */
+ pie->RateMul = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+
+ /* Octet 5 - Layer 1 Ident */
+ if ((IBuf[Octet + Off] & 0x60) == 0x20) { /* Layer 1 Ident ? */
+ pie->Layer1Ident = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->UIL1Prot = IBuf[Octet + Off] & 0x1f;
+ Octet++;
+
+ /* Octet 5a */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ pie->SyncAsync = (IBuf[Octet + Off] >> 6) & 0x01;
+ pie->Negot = (IBuf[Octet + Off] >> 5) & 0x01;
+ pie->UserRate = IBuf[Octet + Off] & 0x1f;
+ Off++;
+
+ /* Octet 5b - 2 options */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ if (pie->UIL1Prot == 0x01) { /* V.110, I.460 and X.30*/
+ pie->InterRate = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->NIConTx = (IBuf[Octet + Off] >> 4) & 0x01;
+ pie->NIConRx = (IBuf[Octet + Off] >> 3) & 0x01;
+ pie->FlowCtlTx = (IBuf[Octet + Off] >> 2) & 0x01;
+ pie->FlowCtlRx = (IBuf[Octet + Off] >> 1) & 0x01;
+ Off++;
+ }
+ else if (pie->UIL1Prot == 0x80) { /* V.120 */
+ pie->HDR = (IBuf[Octet + Off] >> 6) & 0x01;
+ pie->MultiFrame = (IBuf[Octet + Off] >> 5) & 0x01;
+ pie->ModeL1 = (IBuf[Octet + Off] >> 4) & 0x01;
+ pie->NegotLLI = (IBuf[Octet + Off] >> 3) & 0x01;
+ pie->Assignor = (IBuf[Octet + Off] >> 2) & 0x01;
+ pie->InBandNeg = (IBuf[Octet + Off] >> 1) & 0x01;
+ Off++;
+ }
+ else if (pie->UIL1Prot == 0x07) { /* non standard */
+ Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+ Off++;
+ }
+ else {
+ Q931SetError(pTrunk,Q931E_LLCOMP, 5,2);
+ return Q931E_LLCOMP;
+ }
+
+ /* Octet 5c */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ pie->NumStopBits = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->NumDataBits = (IBuf[Octet + Off] >> 3) & 0x03;
+ pie->Parity = IBuf[Octet + Off] & 0x07;
+ Off++;
+
+ /* Octet 5d */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ pie->DuplexMode = (IBuf[Octet + Off] >> 6) & 0x01;
+ pie->ModemType = IBuf[Octet + Off] & 0x3f;
+ Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+ Off++;
+ }
+ }
+ }
+ }
+ }
+
+ /* Octet 6 - Layer 2 Ident */
+ if ((IBuf[Octet + Off] & 0x60) == 0x40) { /* Layer 1 Ident ? */
+ pie->Layer2Ident = (IBuf[Octet + Off] >>5) & 0x03;
+ pie->UIL2Prot = IBuf[Octet + Off] & 0x1f;
+ Octet++;
+
+ /* Octet 6a */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ if (pie->UIL2Prot == 0x10) { /* 2nd 6a */
+ pie->UsrSpcL2Prot = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+ else { /* assume 1st 6a */
+ pie->ModeL2 = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->Q933use = IBuf[Octet + Off] & 0x03;
+ Off++;
+ }
+ /* Octet 6b */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ pie->WindowSize = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+ }
+ }
+
+ /* Octet 7 - layer 3 Ident */
+ if ((IBuf[Octet + Off] & 0x60) == 0x60) { /* Layer 3 Ident ? */
+ pie->Layer3Ident = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->UIL3Prot = IBuf[Octet + Off] & 0x1f;
+ Octet++;
+
+ /* Octet 7a */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ if (pie->UIL3Prot == 0x0b) {
+ /* Octet 7a + 7b AddL3Info */
+ pie->AddL3Info = ((IBuf[Octet + Off] << 4) & 0xf0)
+ | (IBuf[Octet + Off + 1] & 0x0f);
+ Off += 2;
+ }
+ else {
+ if (pie->UIL3Prot == 0x1f) {
+ pie->ModeL3 = (IBuf[Octet + Off] >> 5) & 0x03;
+ Off++;
+ }
+ else {
+ pie->OptL3Info = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+
+ /* Octet 7b*/
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ pie->DefPackSize = IBuf[Octet + Off] & 0x0f;
+ Off++;
+
+ /* Octet 7c */
+ if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+ pie->PackWinSize= IBuf[Octet + Off] & 0x7f;
+ }
+ }
+ }
+ }
+ }
+
+ Q931IESizeTest(Q931E_LLCOMP);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_LLComp);
+ pie->Size = sizeof(Q931ie_LLComp);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_LLComp
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_LLComp(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_LLComp *pIE = (Q931ie_LLComp*)IBuf;
+ L3INT rc = 0;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_LOW_LAYER_COMPATIBILITY;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = (pIE->CodStand << 6) | pIE->ITransCap;
+
+ /* Octet 3a */
+ OBuf[(*Octet)++] = 0x80 | (pIE->NegotInd << 6);
+
+ /* Octet 4 */
+ OBuf[(*Octet)++] = 0x80 | (pIE->TransMode << 5) | pIE->InfoRate;
+
+ /* Octet 4.1 */
+ if (pIE->InfoRate == 0x18) {
+ OBuf[(*Octet)++] = 0x80 | pIE->RateMul;
+ }
+
+ /* Octet 5 */
+ if (pIE->Layer1Ident == 0x01) {
+ OBuf[(*Octet)++] = (pIE->Layer1Ident << 5) | pIE->UIL1Prot;
+
+ /* Octet 5a */
+ if ((pIE->ITransCap == 0x08 && (pIE->UIL1Prot == 0x01 || pIE->UIL1Prot == 0x08))
+ || (pIE->ITransCap == 0x10 && (pIE->UIL1Prot == 0x02 || pIE->UIL1Prot == 0x03))) {
+ OBuf[(*Octet)++] = (pIE->SyncAsync<<6) | (pIE->Negot<<5) | pIE->UserRate;
+
+ /* Octet 5b*/
+ if (pIE->UIL1Prot == 0x01) {
+ OBuf[(*Octet)++] = (pIE->InterRate << 5)
+ | (pIE->NIConTx << 4)
+ | (pIE->NIConTx << 3)
+ | (pIE->FlowCtlTx << 2)
+ | (pIE->FlowCtlRx << 1);
+ }
+ else if (pIE->UIL1Prot == 0x08) {
+ OBuf[(*Octet)++] = (pIE->HDR << 6)
+ | (pIE->MultiFrame << 5)
+ | (pIE->ModeL1 << 4)
+ | (pIE->NegotLLI << 3)
+ | (pIE->Assignor << 2)
+ | (pIE->InBandNeg << 1);
+ }
+ else {
+ OBuf[(*Octet) - 1] |= 0x80;
+ }
+
+ /* How to detect wherever 5c and 5d is to present is not clear
+ * but they have been inculded as 'standard'
+ * Octet 5c
+ */
+ if (pIE->UIL1Prot == 0x01 || pIE->UIL1Prot == 0x08) {
+ OBuf[(*Octet)++] = (pIE->NumStopBits << 5) | (pIE->NumDataBits << 3) | pIE->Parity ;
+
+ /* Octet 5d */
+ OBuf[(*Octet)++] = 0x80 | (pIE->DuplexMode << 6) | pIE->ModemType;
+ }
+ }
+ else {
+ OBuf[(*Octet) - 1] |= 0x80;
+ }
+ }
+
+ /* Octet 6 */
+ if (pIE->Layer2Ident == 0x02) {
+ OBuf[(*Octet)++] = (pIE->Layer2Ident << 5) | pIE->UIL2Prot;
+
+ /* Octet 6a*/
+ if (pIE->UIL2Prot == 0x02 /* Q.921/I.441 */
+ || pIE->UIL2Prot == 0x06 /* X.25 link layer */
+ || pIE->UIL2Prot == 0x07 /* X.25 multilink */
+ || pIE->UIL2Prot == 0x09 /* HDLC ARM */
+ || pIE->UIL2Prot == 0x0a /* HDLC NRM */
+ || pIE->UIL2Prot == 0x0b /* HDLC ABM */
+ || pIE->UIL2Prot == 0x0d /* X.75 SLP */
+ || pIE->UIL2Prot == 0x0e /* Q.922 */
+ || pIE->UIL2Prot == 0x11) { /* ISO/ECE 7776 DTE-DCE */
+ OBuf[(*Octet)++] = (pIE->ModeL2 << 5) | pIE->Q933use;
+
+ /* Octet 6b */
+ OBuf[(*Octet)++] = 0x80 | pIE->WindowSize;
+ }
+ else if (pIE->UIL2Prot == 0x10) { /* User Specific */
+ OBuf[(*Octet)++] = 0x80 | pIE->UsrSpcL2Prot;
+ }
+ else {
+ OBuf[(*Octet) - 1] |= 0x80;
+ }
+ }
+
+ /* Octet 7 */
+ if (pIE->Layer3Ident == 0x03) {
+ OBuf[(*Octet)++] = (pIE->Layer3Ident << 5) | pIE->UIL3Prot;
+
+ /* Octet 7a - 3 different ones */
+ if (pIE->UIL3Prot == 0x10) {
+ OBuf[(*Octet++)] = 0x80 | pIE->OptL3Info;
+ }
+ else if (pIE->UIL3Prot == 0x06
+ || pIE->UIL3Prot == 0x07
+ || pIE->UIL3Prot == 0x08) {
+ OBuf[(*Octet)++] = pIE->ModeL3 << 5;
+
+ /* Octet 7b note 7 */
+ OBuf[(*Octet)++] = pIE->DefPackSize;
+
+ /* Octet 7c note 7 */
+ OBuf[(*Octet)++] = 0x80 | pIE->PackWinSize;
+ }
+ else if (pIE->UIL3Prot == 0x0b) {
+ OBuf[(*Octet)++] = (pIE->AddL3Info >> 4) & 0x0f;
+ OBuf[(*Octet)++] = 0x80 | (pIE->AddL3Info & 0x0f);
+ }
+ else {
+ OBuf[(*Octet) - 1] |= 0x80;
+ }
+ }
+ else {
+ Q931SetError(pTrunk,Q931E_LLCOMP, 7,0);
+ rc = Q931E_LLCOMP;
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_NetFac
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_NetFac(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_NetFac *pie = (Q931ie_NetFac*)OBuf;
+ ie *pIE = &pMsg->NetFac;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT x = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ pie->LenNetID = IBuf[Octet + Off]; /* full octet is used */
+ Octet++;
+
+ if (pie->LenNetID > 0) {
+ /* Octet 3.1 */
+ pie->TypeNetID = (IBuf[Octet + Off] >> 4) & 0x0f;
+ pie->NetIDPlan = IBuf[Octet + Off] & 0x0f;
+ Off = Q931ReadExt(&IBuf[Octet], Off);
+ Off++;
+
+ /* Octet 3.2*/
+ for (x = 0; x < pie->LenNetID; x++) {
+ pie->NetID[x] = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+ }
+
+ /* Octet 4*/
+ pie->NetFac = IBuf[Octet + Off]; /* Full Octet is used */
+ Octet++;
+
+ Q931IESizeTest(Q931E_NETFAC);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_NetFac) + x - 1;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_NetFac) + x - 1);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_NetFac
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_NetFac(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_NetFac *pIE = (Q931ie_NetFac*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet;
+ L3INT li;
+ L3INT x;
+
+ OBuf[(*Octet)++] = Q931ie_NETWORK_SPECIFIC_FACILITIES;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = pIE->LenNetID;
+
+ if (pIE->LenNetID > 0) {
+ /* Octet 3.1 */
+ OBuf[(*Octet)++] = 0x80 | (pIE->TypeNetID << 4) | pIE->NetIDPlan;
+
+ /* Octet 3.2 */
+ for (x = 0; x <pIE->LenNetID; x++) {
+ OBuf[(*Octet)++] = pIE->NetID[x];
+ }
+ }
+
+ /* Octet 4 */
+ OBuf[(*Octet)++] = pIE->NetFac;
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_NotifInd
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_NotifInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_NotifInd *pie = (Q931ie_NotifInd*)OBuf;
+ ie *pIE = &pMsg->NotifInd;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2*/
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->Notification = IBuf[Octet + Off] & 0x7f;
+
+ Off = Q931ReadExt(&IBuf[Octet], Off);
+ Octet++;
+
+ Q931IESizeTest(Q931E_NOTIFIND);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_NotifInd);
+ pie->Size = sizeof(Q931ie_NotifInd);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_NotifInd
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_NotifInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_NotifInd *pIE = (Q931ie_NotifInd*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_NOTIFICATION_INDICATOR;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = pIE->Notification;
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_ProgInd
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_ProgInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_ProgInd *pie = (Q931ie_ProgInd*)OBuf;
+ ie *pIE = &pMsg->ProgInd;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->CodStand = (IBuf[Octet + Off] >> 5) & 0x03;
+ pie->Location = IBuf[Octet + Off] & 0x0f;
+
+ Off = Q931ReadExt(&IBuf[Octet], Off);
+ Octet++;
+
+ /* Octet 4 */
+ pie->ProgDesc = IBuf[Octet + Off] & 0x7f;
+ Off = Q931ReadExt(&IBuf[Octet], Off);
+ Octet++;
+
+ Q931IESizeTest(Q931E_PROGIND);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_ProgInd);
+ pie->Size = sizeof(Q931ie_ProgInd);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_ProgInd
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset L3INTo OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_ProgInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_ProgInd *pIE = (Q931ie_ProgInd*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_PROGRESS_INDICATOR;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = 0x80 | (pIE->CodStand << 5) | pIE->Location;
+
+ /* Octet 4 */
+ OBuf[(*Octet)++] = 0x80 | pIE->ProgDesc;
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_RepeatInd
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_RepeatInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_RepeatInd *pie = (Q931ie_RepeatInd*)OBuf;
+ ie *pIE = &pMsg->RepeatInd;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet] & 0xf0;
+ pie->RepeatInd = IBuf[Octet] & 0x0f;
+ Octet ++;
+
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_RepeatInd);
+ pie->Size = sizeof(Q931ie_RepeatInd);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_RepeatInd
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_RepeatInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_RepeatInd *pIE = (Q931ie_RepeatInd*)IBuf;
+ L3INT rc = 0;
+ /* L3INT Beg = *Octet; */
+
+ OBuf[(*Octet)++] = Q931ie_REPEAT_INDICATOR | pIE->RepeatInd;
+
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_RevChargeInd
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_RevChargeInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ ie iE;
+ /* ie *pIE = &pMsg->RevChargeInd; */
+ Q931SetIE(iE, *OOff);
+
+ return iE;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_RevChargeInd
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_RevChargeInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_RestartInd
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_RestartInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_RestartInd *pie = (Q931ie_RestartInd*)OBuf;
+ ie *pIE = &pMsg->RestartInd;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->Class = IBuf[Octet + Off] & 0x07;
+ pie->Spare = IBuf[Octet + Off] & 0x78;
+
+ Off = Q931ReadExt(&IBuf[Octet], Off);
+ Octet++;
+
+ Q931IESizeTest(Q931E_RESTARTIND);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_RestartInd);
+ pie->Size = sizeof(Q931ie_RestartInd);
+
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_RestartInd
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_RestartInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_RestartInd *pIE = (Q931ie_RestartInd*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_RESTART_INDICATOR;
+ li = (*Octet)++;
+
+ /* Octet 3*/
+ OBuf[(*Octet)++] = 0x80 | pIE->Class ;
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_Segment
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_Segment(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_Segment *pie = (Q931ie_Segment*)OBuf;
+ ie *pIE = &pMsg->Segment;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+ Octet++;
+
+ /* Octet 2*/
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->FSI = (IBuf[Octet + Off] & 0x80) >> 7;
+ pie->NumSegRem = IBuf[Octet + Off] & 0x7f;
+ Octet++;
+
+ /* Octet 4 */
+ pie->SegType = IBuf[Octet + Off] & 0x7f;
+ Octet++;
+
+ Q931IESizeTest(Q931E_SEGMENT);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_Segment);
+ pie->Size = sizeof(Q931ie_Segment);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_Segment
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_Segment(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_Segment *pIE = (Q931ie_Segment*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_SEGMENTED_MESSAGE;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = (pIE->FSI << 7) | pIE->NumSegRem;
+
+ /* Octet 4 */
+ OBuf[(*Octet)++] = pIE->SegType;
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_SendComplete
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_SendComplete(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_SendComplete *pie = (Q931ie_SendComplete*)OBuf;
+ ie *pIE = &pMsg->SendComplete;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+
+ *pIE = 0;
+ Octet++;
+
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_SendComplete);
+ pie->Size = sizeof(Q931ie_SendComplete);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_ProgInd
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_SendComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ /* Q931ie_SendComplete * pIE = (Q931ie_SendComplete*)IBuf; */
+ L3INT rc = Q931E_NO_ERROR;
+ /* L3INT Beg = *Octet; */
+
+ OBuf[(*Octet)++] = 0x80 | (L3UCHAR)Q931ie_SENDING_COMPLETE;
+
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_Signal
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_Signal(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_Signal *pie = (Q931ie_Signal*)OBuf;
+ ie *pIE = &pMsg->Signal;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->Signal = IBuf[Octet + Off];
+ Octet++;
+
+ Q931IESizeTest(Q931E_SIGNAL);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_Signal);
+ pie->Size = sizeof(Q931ie_Signal);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_Signal
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_Signal(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_Signal *pIE = (Q931ie_Signal*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_SIGNAL;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = pIE->Signal;
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_TransNetSel
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_TransNetSel(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_TransNetSel *pie = (Q931ie_TransNetSel*)OBuf;
+ ie *pIE = &pMsg->TransNetSel;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT x = 0;
+ L3INT l;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ l = IBuf[Octet++] - 3;
+
+ /* Octet 3 */
+ pie->Type = (IBuf[Octet + Off] >> 4) & 0x07;
+
+ Off = Q931ReadExt(&IBuf[Octet], Off);
+ Octet++;
+
+ for (x = 0; x < l; x++) {
+ pie->NetID[x] = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ }
+
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_TransNetSel) + x - 1;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_TransNetSel) + x - 1);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_TransNetSel
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_TransNetSel(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_TransNetSel *pIE = (Q931ie_TransNetSel*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet;
+ L3INT li;
+ L3INT x;
+ L3INT l;
+
+ OBuf[(*Octet)++] = Q931ie_TRANSIT_NETWORK_SELECTION;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = 0x80 | (pIE->Type << 4) | pIE->NetIDPlan;
+
+ /* Octet 4 */
+ l = pIE->Size - sizeof(Q931ie_TransNetSel) + 1;
+ for (x = 0; x < l; x++) {
+ OBuf[(*Octet)++] = pIE->NetID[x];
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_UserUser
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_UserUser(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_UserUser *pie = (Q931ie_UserUser*)OBuf;
+ ie *pIE = &pMsg->UserUser;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT l;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ l = IBuf[Octet++] - 1;
+
+ /* Octet 3 */
+ pie->ProtDisc = IBuf[Octet++];
+
+ for (Off = 0; Off < l; Off++) {
+ pie->User[Off] = IBuf[Octet + Off];
+ }
+
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_UserUser) + Off - 1;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_UserUser) + Off - 1);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_UserUser
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_UserUser(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_UserUser *pIE = (Q931ie_UserUser*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet;
+ L3INT li;
+ L3INT x;
+ L3INT l;
+
+ OBuf[(*Octet)++] = Q931ie_USER_USER;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = pIE->ProtDisc;
+
+ /* Octet 4 */
+ l = pIE->Size - sizeof(Q931ie_UserUser) + 1;
+ for (x = 0; x < l; x++) {
+ OBuf[(*Octet)++] = pIE->User[x];
+ }
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_GenericDigits
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_GenericDigits(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_GenericDigits *pie = (Q931ie_GenericDigits*)OBuf;
+ ie *pIE = &pMsg->GenericDigits;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT x;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ /* Octet 1 */
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->Type = (IBuf[Octet]) & 0x1F;
+ pie->Encoding = (IBuf[Octet] >> 5) & 0x07;
+ Octet++;
+
+ /* Octet 4*/
+ if (pie->Encoding == 0) { /* BCD Even */
+ x = 0;
+ do {
+ pie->Digit[x++] = IBuf[Octet + Off] & 0x0f;
+ pie->Digit[x++] = (IBuf[Octet + Off] >> 4) & 0x0f;
+ Off++;
+ } while (Q931MoreIE());
+ } else if (pie->Encoding == 1) { /* BCD Odd */
+ x = 0;
+ do {
+ pie->Digit[x++] = IBuf[Octet + Off] & 0x0f;
+ if (Q931MoreIE()) {
+ pie->Digit[x] = (IBuf[Octet + Off] >> 4) & 0x0f;
+ }
+ x++;
+ Off++;
+ } while (Q931MoreIE());
+ } else if (pie->Encoding == 2) { /* IA5 */
+ x = 0;
+ do {
+ pie->Digit[x++] = IBuf[Octet + Off] & 0x7f;
+ Off++;
+ } while (Q931MoreIE());
+ } else {
+ /* Binary encoding type unkown */
+ Q931SetError(pTrunk, Q931E_GENERIC_DIGITS, Octet, Off);
+ return Q931E_GENERIC_DIGITS;
+ }
+
+ Q931IESizeTest(Q931E_GENERIC_DIGITS);
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_CallingSub) + x - 1;
+ pie->Size = (L3UCHAR)(sizeof(Q931ie_CallingSub) + x - 1);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_GenericDigits
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+
+L3INT Q931Pie_GenericDigits(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ OBuf[(*Octet)++] = (Q931ie_GENERIC_DIGITS & 0xFF);
+ OBuf[(*Octet)++] = 0;
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Uie_ChangeStatus
+
+ Parameters: pIE[OUT] ptr to Information Element id.
+ IBuf[IN] ptr to a packed ie.
+ OBuf[OUT] ptr to buffer for Unpacked ie.
+ IOff[IN\OUT] Input buffer offset
+ OOff[IN\OUT] Output buffer offset
+
+ Ibuf and OBuf points directly to buffers. The IOff and OOff
+ must be updated, but are otherwise not used in the ie unpack.
+
+ Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_ChangeStatus(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+ Q931ie_ChangeStatus *pie = (Q931ie_ChangeStatus*)OBuf;
+ ie *pIE = &pMsg->ChangeStatus;
+ L3INT Off = 0;
+ L3INT Octet = 0;
+ L3INT IESize;
+
+ *pIE = 0;
+
+ pie->IEId = IBuf[Octet++];
+
+ /* Octet 2 */
+ IESize = IBuf[Octet++];
+
+ /* Octet 3 */
+ pie->Preference = (IBuf[Octet + Off] >> 6) & 0x01;
+ pie->Spare = IBuf[Octet + Off] & 0x38;
+ pie->NewStatus = IBuf[Octet + Off] & 0x07;
+ Octet++;
+
+ Q931SetIE(*pIE, *OOff);
+
+ *IOff = (*IOff) + Octet + Off;
+ *OOff = (*OOff) + sizeof(Q931ie_ChangeStatus);
+ pie->Size = sizeof(Q931ie_ChangeStatus);
+
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pie_ChangeStatus
+
+ Parameters: IBuf[IN] Ptr to struct.
+ OBuf[OUT] Ptr tp packed output buffer.
+ Octet[IN/OUT] Offset into OBuf.
+
+ Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_ChangeStatus(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ Q931ie_ChangeStatus *pIE = (Q931ie_ChangeStatus*)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Beg = *Octet;
+ L3INT li;
+
+ OBuf[(*Octet)++] = Q931ie_CHANGE_STATUS;
+ li = (*Octet)++;
+
+ /* Octet 3 */
+ OBuf[(*Octet)++] = 0x80 | pIE->NewStatus | ((pIE->Preference & 0x01) << 6);
+
+ OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+ return rc;
+}
+
+
+
+L3INT Q931Uie_Generic(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff)
+{
+ L3INT Octet = 0;
+ L3UCHAR id = 0;
+
+ /* id */
+ id = IBuf[Octet++];
+
+ /* Length */
+ Octet += IBuf[Octet];
+ Octet++;
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Discarding IE %#hhx with length %d\n", id, Octet - 2);
+
+ *IOff += Octet;
+ return Q931E_NO_ERROR;
+}
+
+L3INT Q931Pie_Generic(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+ /* do nothing */
+ return Q931E_NO_ERROR;
+}
Added: freeswitch/trunk/libs/openzap/src/isdn/Q931mes.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/Q931mes.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/Q931mes.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1870 @@
+/*****************************************************************************
+
+ FileName: Q931mes.c
+
+ Contents: Pack/Unpack functions. These functions will unpack a Q931
+ message from the bit packed original format into structs
+ that contains variables sized by the user. It will also pack
+ the struct back into a Q.931 message as required.
+
+ See q931.h for description.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+
+*****************************************************************************/
+
+#include "Q931.h"
+
+/**
+ * Q931MesgHeader
+ * \brief Create Q.931 Message header
+ */
+L3INT Q931MesgHeader(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *mes, L3UCHAR *OBuf, L3INT Size, L3INT *IOff)
+{
+ L3INT Octet = *IOff;
+
+ Q931Log(pTrunk, Q931_LOG_DEBUG, "Creating Q.931 Message Header:\n ProtDisc %d (%#x), CRV %d (%#x), CRVflag: %d (%#x), MesType: %d (%#x)\n",
+ mes->ProtDisc, mes->ProtDisc, mes->CRV, mes->CRV, mes->CRVFlag, mes->CRVFlag, mes->MesType, mes->MesType);
+
+ OBuf[Octet++] = mes->ProtDisc; /* Protocol discriminator */
+ if (!Q931_IS_BRI(pTrunk)) {
+ OBuf[Octet++] = 2; /* length is 2 octets */
+ OBuf[Octet++] = (L3UCHAR)((mes->CRV >> 8) & 0x7f) | ((mes->CRVFlag << 7) & 0x80); /* msb */
+ OBuf[Octet++] = (L3UCHAR) (mes->CRV & 0xff); /* lsb */
+ } else {
+ OBuf[Octet++] = 1; /* length is 1 octet */
+ OBuf[Octet++] = (L3UCHAR) (mes->CRV & 0x7f) | ((mes->CRVFlag << 7) & 0x80); /* CRV & flag */
+ }
+ OBuf[Octet++] = mes->MesType; /* message header */
+
+ *IOff = Octet;
+ return 0;
+}
+
+
+/*****************************************************************************
+
+ Function: Q931Umes_Alerting
+
+*****************************************************************************/
+
+L3INT Q931Umes_Alerting(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_BEARER_CAPABILITY:
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_DISPLAY:
+ case Q931ie_SIGNAL:
+ case Q931ie_HIGH_LAYER_COMPATIBILITY:
+ case Q931ie_USER_USER:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Alerting
+
+*****************************************************************************/
+L3INT Q931Pmes_Alerting(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Bearer capability */
+ if (Q931IsIEPresent(pMes->BearerCap)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Channel Identification */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* High Layer Compatibility */
+ if (Q931IsIEPresent(pMes->HLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_CallProceeding
+
+*****************************************************************************/
+L3INT Q931Umes_CallProceeding(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_BEARER_CAPABILITY:
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_DISPLAY:
+ case Q931ie_HIGH_LAYER_COMPATIBILITY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_CallProceeding
+
+*****************************************************************************/
+L3INT Q931Pmes_CallProceeding(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Bearer capability */
+ if (Q931IsIEPresent(pMes->BearerCap)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Channel Identification */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* High Layer Compatibility */
+ if (Q931IsIEPresent(pMes->HLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_CongestionControl
+
+*****************************************************************************/
+L3INT Q931Umes_CongestionControl(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(mes);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+
+/*****************************************************************************
+
+ Function: Q931Pmes_CongestionControl
+
+*****************************************************************************/
+L3INT Q931Pmes_CongestionControl(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ *OSize = 0;
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Connect
+
+*****************************************************************************/
+L3INT Q931Umes_Connect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_BEARER_CAPABILITY:
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_DISPLAY:
+ case Q931ie_DATETIME:
+ case Q931ie_SIGNAL:
+ case Q931ie_LOW_LAYER_COMPATIBILITY:
+ case Q931ie_HIGH_LAYER_COMPATIBILITY:
+ case Q931ie_CONNECTED_NUMBER: /* not actually used, seen while testing BRI PTMP TE */
+ case Q931ie_USER_USER:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+
+ default:
+ Q931Log(pTrunk, Q931_LOG_ERROR, "Illegal IE %#hhx in Connect Message\n", IBuf[IOff]);
+
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Connect
+
+*****************************************************************************/
+L3INT Q931Pmes_Connect(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Bearer capability */
+ if (Q931IsIEPresent(pMes->BearerCap)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Channel Identification */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Date/Time */
+ if (Q931IsIEPresent(pMes->DateTime)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Low Layer Compatibility */
+ if (Q931IsIEPresent(pMes->LLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* High Layer Compatibility */
+ if (Q931IsIEPresent(pMes->HLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_ConnectAck
+
+*****************************************************************************/
+L3INT Q931Umes_ConnectAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_DISPLAY:
+ case Q931ie_SIGNAL:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+
+/*****************************************************************************
+
+ Function: Q931Pmes_ConnectAck
+
+*****************************************************************************/
+L3INT Q931Pmes_ConnectAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Disconnect
+
+*****************************************************************************/
+L3INT Q931Umes_Disconnect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CAUSE:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_DISPLAY:
+ case Q931ie_SIGNAL:
+ case Q931ie_FACILITY:
+ case Q931ie_USER_USER:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Disconnect
+
+*****************************************************************************/
+L3INT Q931Pmes_Disconnect(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Cause */
+ if (Q931IsIEPresent(pMes->Cause)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Information
+
+*****************************************************************************/
+L3INT Q931Umes_Information(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_SENDING_COMPLETE:
+ case Q931ie_DISPLAY:
+ case Q931ie_KEYPAD_FACILITY:
+ case Q931ie_CALLED_PARTY_NUMBER:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Information
+
+*****************************************************************************/
+L3INT Q931Pmes_Information(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Sending Complete */
+ if (Q931IsIEPresent(pMes->SendComplete)) {
+ OBuf[Octet++] = (L3UCHAR)(pMes->SendComplete & 0x00ff);
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Keypad Facility */
+ if (Q931IsIEPresent(pMes->KeypadFac)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Called Party number */
+ if (Q931IsIEPresent(pMes->CalledNum)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Notify
+
+*****************************************************************************/
+L3INT Q931Umes_Notify(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_BEARER_CAPABILITY:
+ case Q931ie_NOTIFICATION_INDICATOR:
+ case Q931ie_DISPLAY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Notify
+
+*****************************************************************************/
+L3INT Q931Pmes_Notify(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Bearer capability */
+ if (Q931IsIEPresent(pMes->BearerCap)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Progress
+
+*****************************************************************************/
+L3INT Q931Umes_Progress(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_BEARER_CAPABILITY:
+ case Q931ie_CAUSE:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_DISPLAY:
+ case Q931ie_HIGH_LAYER_COMPATIBILITY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Progress
+
+*****************************************************************************/
+L3INT Q931Pmes_Progress(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Bearer capability */
+ if (Q931IsIEPresent(pMes->BearerCap)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Cause */
+ if (Q931IsIEPresent(pMes->Cause)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* High Layer Compatibility */
+ if (Q931IsIEPresent(pMes->HLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Release
+
+*****************************************************************************/
+L3INT Q931Umes_Release(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CAUSE:
+ case Q931ie_DISPLAY:
+ case Q931ie_SIGNAL:
+ case Q931ie_USER_USER:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Release
+
+*****************************************************************************/
+L3INT Q931Pmes_Release(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Cause */
+ if (Q931IsIEPresent(pMes->Cause)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_ReleaseComplete
+
+*****************************************************************************/
+L3INT Q931Umes_ReleaseComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CAUSE:
+ case Q931ie_DISPLAY:
+ case Q931ie_SIGNAL:
+ case Q931ie_USER_USER:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_ReleaseComplete
+
+*****************************************************************************/
+L3INT Q931Pmes_ReleaseComplete(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Cause */
+ if (Q931IsIEPresent(pMes->Cause)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Restart
+
+*****************************************************************************/
+L3INT Q931Umes_Restart(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_DISPLAY:
+ case Q931ie_RESTART_INDICATOR:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Restart
+
+*****************************************************************************/
+L3INT Q931Pmes_Restart(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* ChanID */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* RestartInd */
+ if (Q931IsIEPresent(pMes->RestartInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_RESTART_INDICATOR](pTrunk, Q931GetIEPtr(pMes->RestartInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_RestartAck
+
+*****************************************************************************/
+L3INT Q931Umes_RestartAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size)
+{
+ Q931mes_Generic *mes = (Q931mes_Generic*)OBuf;
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_DISPLAY:
+ case Q931ie_RESTART_INDICATOR:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_RestartAck
+
+*****************************************************************************/
+L3INT Q931Pmes_RestartAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* ChanID */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* RestartInd */
+ if (Q931IsIEPresent(pMes->RestartInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_RESTART_INDICATOR](pTrunk, Q931GetIEPtr(pMes->RestartInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Resume
+
+*****************************************************************************/
+L3INT Q931Umes_Resume(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CALL_IDENTITY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Resume
+
+*****************************************************************************/
+L3INT Q931Pmes_Resume(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Call Identity */
+ if (Q931IsIEPresent(pMes->CallID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALL_IDENTITY](pTrunk, Q931GetIEPtr(pMes->CallID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_ResumeAck
+
+*****************************************************************************/
+L3INT Q931Umes_ResumeAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_DISPLAY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+
+/*****************************************************************************
+
+ Function: Q931Pmes_ResumeAck
+
+*****************************************************************************/
+L3INT Q931Pmes_ResumeAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Channel Identification */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_ResumeReject
+
+*****************************************************************************/
+L3INT Q931Umes_ResumeReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CAUSE:
+ case Q931ie_DISPLAY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+
+/*****************************************************************************
+
+ Function: Q931Pmes_ResumeReject
+
+*****************************************************************************/
+L3INT Q931Pmes_ResumeReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Cause */
+ if (Q931IsIEPresent(pMes->Cause)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+L3INT Q931Umes_Segment(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT OOff)
+{
+ L3INT i = IOff;
+
+ return IOff - i;
+}
+
+L3INT Q931Pmes_Segment(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ *OSize = 0;
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Setup
+
+*****************************************************************************/
+L3INT Q931Umes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT ir = 0;
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_SENDING_COMPLETE:
+ IOff++;
+ break;
+
+ case Q931ie_BEARER_CAPABILITY:
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_NETWORK_SPECIFIC_FACILITIES:
+ case Q931ie_DISPLAY:
+ case Q931ie_DATETIME:
+ case Q931ie_KEYPAD_FACILITY:
+ case Q931ie_SIGNAL:
+ case Q931ie_CALLING_PARTY_NUMBER:
+ case Q931ie_CALLING_PARTY_SUBADDRESS:
+ case Q931ie_CALLED_PARTY_NUMBER:
+ case Q931ie_CALLED_PARTY_SUBADDRESS:
+ case Q931ie_TRANSIT_NETWORK_SELECTION:
+ case Q931ie_LOW_LAYER_COMPATIBILITY:
+ case Q931ie_HIGH_LAYER_COMPATIBILITY:
+ case Q931ie_FACILITY:
+ case Q931ie_USER_USER:
+ case Q931ie_REDIRECTING_NUMBER:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+
+ case Q931ie_REPEAT_INDICATOR:
+ if (ir < 2) {
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ ir++;
+ } else {
+ return Q931E_ILLEGAL_IE;
+ }
+ break;
+
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Setup
+
+ Decription: Pack a Q931mes_Generic into a real Q.931 message. The user will
+ set up a SETUP message and issue this to the stack where it
+ is processed by Q931ProcSetup that processes and validates
+ it before it actually sends it out. This function is called
+ to compute the real Q.931 message.
+
+ Parameters: IBuf[IN] Ptr to un-packed struct
+ ISize[IN] Size of input buffer (unpacked message).
+ OBuf[OUT] Ptr to packed 'octet' wise message.
+ OSize[OUT] Size of packed message.
+
+ Called By: Q931ProcSetup
+
+*****************************************************************************/
+L3INT Q931Pmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Sending Complete */
+ if (Q931IsIEPresent(pMes->SendComplete)) {
+ OBuf[Octet++] = (L3UCHAR)Q931ie_SENDING_COMPLETE & 0xff;
+ }
+
+ /* Repeat Indicator */
+ if (Q931IsIEPresent(pMes->RepeatInd)) {
+ OBuf[Octet++] = (L3UCHAR)Q931ie_REPEAT_INDICATOR & 0xff;
+ }
+
+ /* Bearer capability */
+ if (Q931IsIEPresent(pMes->BearerCap)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ } else {
+ rc = Q931E_BEARERCAP;
+ }
+
+ /* Channel Identification */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Network spesific facilities */
+ if (Q931IsIEPresent(pMes->NetFac)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_NETWORK_SPECIFIC_FACILITIES](pTrunk, Q931GetIEPtr(pMes->NetFac,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Date/Time */
+ if (Q931IsIEPresent(pMes->DateTime)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Keypad Facility */
+ if (Q931IsIEPresent(pMes->KeypadFac)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Calling Party Number */
+ if (Q931IsIEPresent(pMes->CallingNum)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CallingNum,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Calling Party Subaddress */
+ if (Q931IsIEPresent(pMes->CallingSub)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CallingSub,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Called Party number */
+ if (Q931IsIEPresent(pMes->CalledNum)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Called party subaddress */
+ if (Q931IsIEPresent(pMes->CalledSub)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CalledSub,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Transit network selection */
+ if (Q931IsIEPresent(pMes->TransNetSel)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_TRANSIT_NETWORK_SELECTION](pTrunk, Q931GetIEPtr(pMes->TransNetSel,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Repeat Indicator */
+ if (Q931IsIEPresent(pMes->LLRepeatInd)) {
+ rc = Q931E_UNKNOWN_IE;/* TODO */
+ }
+
+ /* Low Layer Compatibility */
+ if (Q931IsIEPresent(pMes->LLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* High Layer Compatibility */
+ if (Q931IsIEPresent(pMes->HLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_SetupAck
+
+*****************************************************************************/
+L3INT Q931Umes_SetupAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_DISPLAY:
+ case Q931ie_SIGNAL:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_SetupAck
+
+*****************************************************************************/
+L3INT Q931Pmes_SetupAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Channel Identification */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Status
+
+*****************************************************************************/
+L3INT Q931Umes_Status(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CAUSE:
+ case Q931ie_CALL_STATE:
+ case Q931ie_DISPLAY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Status
+
+*****************************************************************************/
+L3INT Q931Pmes_Status(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Cause */
+ if (Q931IsIEPresent(pMes->Cause)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Call State */
+ if (Q931IsIEPresent(pMes->CallState)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALL_STATE](pTrunk, Q931GetIEPtr(pMes->CallState,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_StatusEnquiry
+
+*****************************************************************************/
+L3INT Q931Umes_StatusEnquiry(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_DISPLAY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_StatusEnquiry
+
+*****************************************************************************/
+L3INT Q931Pmes_StatusEnquiry(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Suspend
+
+*****************************************************************************/
+L3INT Q931Umes_Suspend(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CALL_IDENTITY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Suspend
+
+*****************************************************************************/
+L3INT Q931Pmes_Suspend(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Call Identity */
+ if (Q931IsIEPresent(pMes->CallID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALL_IDENTITY](pTrunk, Q931GetIEPtr(pMes->CallID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_SuspendAck
+
+*****************************************************************************/
+L3INT Q931Umes_SuspendAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_DISPLAY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_SuspendAck
+
+*****************************************************************************/
+L3INT Q931Pmes_SuspendAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_SuspendReject
+
+*****************************************************************************/
+L3INT Q931Umes_SuspendReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CAUSE:
+ case Q931ie_DISPLAY:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_SuspendReject
+
+*****************************************************************************/
+L3INT Q931Pmes_SuspendReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Cause */
+ if (Q931IsIEPresent(pMes->Cause)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_UserInformation
+
+*****************************************************************************/
+L3INT Q931Umes_UserInformation(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT I, L3INT O)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(mes);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_UserInformation
+
+*****************************************************************************/
+L3INT Q931Pmes_UserInformation(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ *OSize = 0;
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_Service
+
+*****************************************************************************/
+L3INT Q931Umes_Service(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ case Q931ie_CHANGE_STATUS:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Service
+
+*****************************************************************************/
+L3INT Q931Pmes_Service(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ if (Q931IsIEPresent(pMes->ChangeStatus)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANGE_STATUS](pTrunk, Q931GetIEPtr(pMes->ChangeStatus,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
+
+/*****************************************************************************
+
+ Function: Q931Umes_ServiceAck
+
+*****************************************************************************/
+L3INT Q931Umes_ServiceAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+
+ while (IOff < Size) {
+ switch (IBuf[IOff]) {
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ case Q931ie_CHANGE_STATUS:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ }
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_ServiceAck
+
+*****************************************************************************/
+L3INT Q931Pmes_ServiceAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT rc = Q931E_NO_ERROR;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ if (Q931IsIEPresent(pMes->ChangeStatus)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANGE_STATUS](pTrunk, Q931GetIEPtr(pMes->ChangeStatus,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
Added: freeswitch/trunk/libs/openzap/src/isdn/Q932mes.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/Q932mes.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/Q932mes.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,286 @@
+/*****************************************************************************
+
+ FileName: Q932mes.c
+
+ Contents: Q.932 Message Encoders/Decoders
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "Q931.h"
+
+/*****************************************************************************
+
+ Function: Q932Umes_Facility
+
+*****************************************************************************/
+
+L3INT Q932Umes_Facility(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+
+ /* TODO */
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Facility
+
+*****************************************************************************/
+L3INT Q932Pmes_Facility(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q932Umes_Hold
+
+*****************************************************************************/
+
+L3INT Q932Umes_Hold(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+
+ /* TODO */
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Hold
+
+*****************************************************************************/
+L3INT Q932Pmes_Hold(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q932Umes_HoldAck
+
+*****************************************************************************/
+
+L3INT Q932Umes_HoldAck(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+
+ /* TODO */
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_HoldAck
+
+*****************************************************************************/
+L3INT Q932Pmes_HoldAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q932Umes_HoldReject
+
+*****************************************************************************/
+
+L3INT Q932Umes_HoldReject(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+
+ /* TODO */
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_HoldReject
+
+*****************************************************************************/
+L3INT Q932Pmes_HoldReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q932Umes_Register
+
+*****************************************************************************/
+
+L3INT Q932Umes_Register(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+
+ /* TODO */
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Register
+
+*****************************************************************************/
+L3INT Q932Pmes_Register(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q932Umes_Retrieve
+
+*****************************************************************************/
+
+L3INT Q932Umes_Retrieve(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+
+ /* TODO */
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_Retrieve
+
+*****************************************************************************/
+L3INT Q932Pmes_Retrieve(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q932Umes_RetrieveAck
+
+*****************************************************************************/
+
+L3INT Q932Umes_RetrieveAck(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+
+ /* TODO */
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_RetrieveAck
+
+*****************************************************************************/
+L3INT Q932Pmes_RetrieveAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
+
+/*****************************************************************************
+
+ Function: Q932Umes_RetrieveReject
+
+*****************************************************************************/
+
+L3INT Q932Umes_RetrieveReject(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT OOff = 0;
+
+ /* TODO */
+
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: Q931Pmes_RetrieveReject
+
+*****************************************************************************/
+L3INT Q932Pmes_RetrieveReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3BOOL RetCode = L3FALSE;
+
+ NoWarning(OBuf);
+ NoWarning(IBuf);
+
+ return RetCode;
+}
Added: freeswitch/trunk/libs/openzap/src/isdn/include/5ESS.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/include/5ESS.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/include/5ESS.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,103 @@
+/******************************************************************************
+
+ FileName: 5ESS.h
+
+ Contents: Header and definition for the AT&T 5ESS ISDN dialect. The
+ header contains the following parts:
+
+ - Definition of codes
+ - Definition of information elements (5ESSie_).
+ - Definition of messages (5ESSmes_).
+ - Function prototypes.
+
+ Description: The AT&T 5ESS ISDN dialect here covers ????
+
+ Related Files: 5ESS.h AT&T 5ESS ISDN Definitions
+ 5ESSie.c AT&T 5ESS ISDN IE encoders/coders (not extant yet)
+ See Q931ie.c for IE encoders/coders
+ 5ESSStateTE.c AT&T 5ESS ISDN TE State Engine
+ 5ESSStateNT.c AT&T 5ESS ISDN NT State Engine
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ Copyright (c) 2007, Michael S. Collins, All rights reserved.
+ email:mcollins@fcnetwork.com
+
+ 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 Case Labs, Ltd 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.
+******************************************************************************/
+
+#ifndef _5ESS_NL
+#define _5ESS_NL
+
+#include "Q931.h"
+
+/*****************************************************************************
+
+ Q.931 Message codes
+ Only 5ESS specific message and ie types
+ here the rest are inherited from Q931.h
+
+*****************************************************************************/
+
+
+/*****************************************************************************
+
+ Q.931 Message Pack/Unpack functions. Implemented in 5ESSmes.c
+ Note: Because C variables may not begin with numeric digit, all identifiers
+ are prefixed with "ATT5ESS" instead of a bare "5ESS"
+
+*****************************************************************************/
+L3INT ATT5ESSUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT ATT5ESSPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT ATT5ESSUmes_SetupAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT ATT5ESSPmes_SetupAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+L3INT ATT5ESSUmes_0x07(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT ATT5ESSPmes_0x07(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT ATT5ESSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT ATT5ESSPmes_0x0f(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+
+
+/*****************************************************************************
+
+ Q.931 Process Function Prototyping. Implemented in 5ESSStateTE.c
+
+*****************************************************************************/
+L3INT ATT5ESSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom);
+L3INT ATT5ESSProc0x07TE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom);
+
+
+void ATT5ESSCreateTE(L3UCHAR i);
+void ATT5ESSCreateNT(L3UCHAR i);
+
+#endif /* _5ESS_NL */
Added: freeswitch/trunk/libs/openzap/src/isdn/include/DMS.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/include/DMS.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/include/DMS.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,91 @@
+/******************************************************************************
+
+ FileName: national.h
+
+ Contents: Header and definition for the National ISDN dialect. The
+ header contents the following parts:
+ - Definition of codes
+ - Definition of information elements (nationalie_).
+ - Definition of messages (nationalmes_).
+ - Function prototypes.
+
+ Description: The National ISDN dialect here covers ????
+
+ Related Files: national.h National ISDN Definitions
+ nationalie.c National ISDN IE encoders/coders
+ nationalStateTE.c National ISDN TE State Engine
+ nationalStateNT.c National ISDN NT State Engine
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ 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 Case Labs, Ltd 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.
+******************************************************************************/
+
+#ifndef _DMS_NL
+#define _DMS_NL
+
+#include "Q931.h"
+
+/*****************************************************************************
+
+ Q.931 Message codes
+ Only National specific message and ie types
+ here the rest are inherited from national.h
+
+*****************************************************************************/
+
+
+/*****************************************************************************
+
+ Q.931 Message Pack/Unpack functions. Implemented in nationalmes.c
+
+*****************************************************************************/
+L3INT DMSUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT DMSPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT DMSUmes_0x07(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT DMSPmes_0x07(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT DMSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT DMSPmes_0x0f(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+/*****************************************************************************
+
+ Q.931 Process Function Prototyping. Implemented in nationalStateTE.c
+
+*****************************************************************************/
+
+L3INT DMSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom);
+L3INT DMSProc0x07TE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom);
+
+void DMSCreateTE(L3UCHAR i);
+void DMSCreateNT(L3UCHAR i);
+
+#endif /* _DMS_NL */
Added: freeswitch/trunk/libs/openzap/src/isdn/include/Q921.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/include/Q921.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/include/Q921.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,227 @@
+/*****************************************************************************
+
+ FileName: q921.h
+
+ Description: Contains headers of a Q.921 protocol.
+
+ Note: This header file is the only include file that should be
+ acessed by users of the Q.921 stack.
+
+ Interface: The Q.921 stack contains 2 layers.
+
+ - One interface layer.
+ - One driver layer.
+
+ The interface layer contains the interface functions required
+ for a layer 2 stack to be able to send and receive messages.
+
+ The driver layer will simply feed bytes into the ship as
+ required and queue messages received out from the ship.
+
+ Q921TimeTick The Q.921 like any other blackbox
+ modules contains no thread by it's own
+ and must therefore be called regularly
+ by an external 'thread' to do maintenance
+ etc.
+
+ Q921Rx32 Receive message from layer 3. Called by
+ the layer 3 stack to send a message.
+
+
+ NOTE: The following are not yet implemented
+
+ OnQ921Error Function called every if an error is
+ detected.
+
+ OnQ921Log Function called if logging is active.
+
+
+ <TODO> Maintenance/Configuration interface
+ <TODO> Logging
+ <TODO> DL_ message passing to layer 3
+ <TODO> Timers
+ <TODO> Api commands to tell 921 to stop and start for a trunk
+
+ Created: 27.dec.2000/JVB
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+
+*****************************************************************************/
+
+/****************************************************************************
+ * Changes:
+ *
+ * - June,July 2008: Stefan Knoblich <s.knoblich@axsentis.de>:
+ * Add PTMP TEI management
+ * Add timers
+ * Add retransmit counters
+ * Add logging
+ * Various cleanups
+ *
+ ****************************************************************************/
+
+#ifndef _Q921
+#define _Q921
+
+#define Q921MAXHDLCSPACE 3000
+#define L2UCHAR unsigned char /* Min 8 bit */
+#define L2USHORT unsigned short /* 16 bit */
+#define L2INT int /* Min 16 bit signed */
+#define L2ULONG unsigned long /* Min 32 bit */
+#define L2TRUNK Q921Data_t *
+
+#define Q921_TEI_BCAST 127
+#define Q921_TEI_MAX Q921_TEI_BCAST
+
+#define Q921_TEI_DYN_MIN 64
+#define Q921_TEI_DYN_MAX 126
+
+
+typedef enum /* Network/User Mode */
+{
+ Q921_TE=0, /* 0 : User Mode */
+ Q921_NT=1 /* 1 : Network Mode */
+} Q921NetUser_t;
+
+typedef enum /* Type of connection */
+{
+ Q921_PTP=0, /* 0 : Point-To-Point */
+ Q921_PTMP=1 /* 1 : Point-To-Multipoint */
+} Q921NetType_t;
+
+typedef enum
+{
+ Q921_LOG_NONE = -1,
+ Q921_LOG_EMERG = 0,
+ Q921_LOG_ALERT,
+ Q921_LOG_CRIT,
+ Q921_LOG_ERROR,
+ Q921_LOG_WARNING,
+ Q921_LOG_NOTICE,
+ Q921_LOG_INFO,
+ Q921_LOG_DEBUG
+} Q921LogLevel_t;
+
+
+/*
+ * Messages for L2 <-> L3 communication
+ */
+typedef enum {
+ Q921_DL_ESTABLISH = 0,
+ Q921_DL_ESTABLISH_CONFIRM,
+ Q921_DL_RELEASE,
+ Q921_DL_RELEASE_CONFIRM,
+ Q921_DL_DATA,
+ Q921_DL_UNIT_DATA
+} Q921DLMsg_t;
+
+typedef int (*Q921Tx21CB_t) (void *, L2UCHAR *, L2INT);
+typedef int (*Q921Tx23CB_t) (void *, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *, L2INT);
+typedef int (*Q921LogCB_t) (void *, Q921LogLevel_t, char *, L2INT);
+
+struct Q921_Link;
+
+typedef struct Q921Data
+{
+ L2INT initialized;
+
+ L2UCHAR sapi; /*!< User assigned SAPI */
+ L2UCHAR tei; /*!< User assigned TEI value */
+
+ L2INT Q921HeaderSpace;
+ Q921NetUser_t NetUser;
+ Q921NetType_t NetType;
+
+ struct Q921_Link *context; /*!< per-TEI / link context space */
+
+ /* timers */
+ L2ULONG T202; /*!< PTMP TE mode TEI retransmit timer */
+ L2ULONG T200Timeout;
+ L2ULONG T201Timeout;
+ L2ULONG T202Timeout;
+ L2ULONG T203Timeout;
+
+ L2ULONG TM01Timeout;
+
+ /* counters */
+ L2ULONG N200Limit; /*!< max retransmit */
+
+ L2ULONG N202; /*!< PTMP TE mode retransmit counter */
+ L2ULONG N202Limit; /*!< PTMP TE mode max retransmit */
+
+ L2ULONG N201Limit; /*!< max number of octets */
+ L2ULONG k; /*!< max number of unacknowledged I frames */
+
+ /* callbacks and callback data pointers */
+ Q921Tx21CB_t Q921Tx21Proc;
+ Q921Tx23CB_t Q921Tx23Proc;
+ void *PrivateData21;
+ void *PrivateData23;
+
+ /* logging */
+ Q921LogLevel_t loglevel; /*!< trunk loglevel */
+ Q921LogCB_t Q921LogProc; /*!< log callback procedure */
+ void *PrivateDataLog; /*!< private data pointer for log proc */
+
+ /* tei mgmt */
+ L2UCHAR tei_map[Q921_TEI_MAX]; /*!< */
+
+ L2UCHAR HDLCInQueue[Q921MAXHDLCSPACE]; /*!< HDLC input queue */
+} Q921Data_t;
+
+/*
+ * Public functions
+ */
+int Q921_InitTrunk(L2TRUNK trunk,
+ L2UCHAR sapi,
+ L2UCHAR tei,
+ Q921NetUser_t NetUser,
+ Q921NetType_t NetType,
+ L2INT hsize,
+ Q921Tx21CB_t cb21,
+ Q921Tx23CB_t cb23,
+ void *priv21,
+ void *priv23);
+int Q921Start(L2TRUNK trunk);
+int Q921Stop(L2TRUNK trunk);
+
+void Q921SetLogCB(L2TRUNK trunk, Q921LogCB_t func, void *priv);
+void Q921SetLogLevel(L2TRUNK trunk, Q921LogLevel_t level);
+
+int Q921Rx12(L2TRUNK trunk);
+int Q921Rx32(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR * Mes, L2INT Size);
+
+int Q921QueueHDLCFrame(L2TRUNK trunk, L2UCHAR *b, L2INT size);
+
+void Q921SetGetTimeCB(L2ULONG (*callback)(void));
+void Q921TimerTick(L2TRUNK trunk);
+
+#endif
Added: freeswitch/trunk/libs/openzap/src/isdn/include/Q921priv.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/include/Q921priv.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/include/Q921priv.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,321 @@
+/*****************************************************************************
+
+ FileName: Q921priv.h
+
+ Description: Private declarations
+
+ Created: 08.Aug.2008/STKN
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2008, Stefan Knoblich, axsentis GmbH. All rights reserved.
+ email:s.knoblich@axsentis.de
+
+ 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 Case Labs, Ltd 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.
+
+*****************************************************************************/
+#ifndef _Q921_PRIV_H_
+#define _Q921_PRIV_H_
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+#if (_MSC_VER >= 1400) /* VC8+ */
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+#ifndef _CRT_NONSTDC_NO_DEPRECATE
+#define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+#endif
+#ifndef strcasecmp
+#define strcasecmp(s1, s2) _stricmp(s1, s2)
+#endif
+#ifndef strncasecmp
+#define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n)
+#endif
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#endif
+
+typedef enum /* Q.921 States */
+{
+ Q921_STATE_STOPPED = 0, /* Trunk stopped */
+ Q921_STATE_TEI_UNASSIGNED = 1, /* TEI unassigned */
+ Q921_STATE_TEI_AWAITING, /* Assign awaiting TEI */
+ Q921_STATE_TEI_ESTABLISH, /* Establish awaiting TEI */
+ Q921_STATE_TEI_ASSIGNED, /* TEI assigned */
+ Q921_STATE_AWAITING_ESTABLISHMENT, /* Awaiting establishment */
+ Q921_STATE_AWAITING_RELEASE, /* Awaiting release */
+ Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, /* Multiple frame established */
+ Q921_STATE_TIMER_RECOVERY /* Timer recovery */
+} Q921State_t;
+
+/*
+ * Flags
+ */
+enum Q921_Flags {
+ Q921_FLAG_L3_INITIATED = (1 << 0),
+
+ Q921_FLAG_UI_FRAME_QUEUED = (1 << 1),
+ Q921_FLAG_I_FRAME_QUEUED = (1 << 2),
+
+ Q921_FLAG_ACK_PENDING = (1 << 3),
+ Q921_FLAG_REJECT = (1 << 4),
+
+ Q921_FLAG_RECV_BUSY = (1 << 5),
+ Q921_FLAG_PEER_RECV_BUSY = (1 << 6)
+};
+
+#define Q921_SET_FLAG(x, f) ((x)->flags |= f)
+#define Q921_CHECK_FLAG(x, f) ((x)->flags & f)
+#define Q921_CLEAR_FLAG(x, f) ((x)->flags &= ~f)
+
+
+/*
+ * dynamic TEI handling
+ */
+#define Q921_SAPI_TEI 63 /* SAPI for all TEI Messages */
+#define Q921_LAYER_ENT_ID_TEI 0x0f /* UN Layer Management Entity ID for TEI Mgmt */
+#define Q921_LAYER_ENT_ID_Q931 0x08 /* Q.931 Layer Management Entity ID */
+
+
+typedef enum {
+ Q921_TEI_ID_REQUEST = 1,
+ Q921_TEI_ID_ASSIGNED,
+ Q921_TEI_ID_DENIED,
+ Q921_TEI_ID_CHECKREQ,
+ Q921_TEI_ID_CHECKRESP,
+ Q921_TEI_ID_REMOVE,
+ Q921_TEI_ID_VERIFY
+} Q921TeiMessageType_t;
+
+
+/**
+ * Per-Datalink context
+ */
+struct Q921_Link {
+ L2UCHAR tei; /*!< This endpoint's TEI */
+
+ L2UCHAR va;
+ L2UCHAR vs;
+ L2UCHAR vr;
+
+ L2INT flags;
+ Q921State_t state;
+
+ L2ULONG N202; /*!< PTMP TE mode retransmit counter */
+ L2ULONG N200; /*!< retransmit counter (per-TEI in PTMP NT mode) */
+
+ L2ULONG TM01; /*!< Datalink inactivity disconnect timer */
+
+ L2ULONG T200;
+ L2ULONG T201; /*!< PTMP NT mode timer */
+ L2ULONG T203;
+
+ L2USHORT ri; /*!< random id for TEI request mgmt */
+
+ /* I + UI Frame queue */
+ L2UCHAR UIFrameQueue[Q921MAXHDLCSPACE];
+ L2UCHAR IFrameQueue[Q921MAXHDLCSPACE];
+ L2UCHAR IFrameResendQueue[Q921MAXHDLCSPACE];
+};
+
+
+#define Q921_LINK_CONTEXT(tr, tei) \
+ (Q921_IS_PTMP_NT(tr) && tei != Q921_TEI_BCAST) ? ((struct Q921_Link *)&(tr)->context[tei]) : (tr)->context
+
+#define Q921_TRUNK_CONTEXT(tr) \
+ (tr)->context
+
+#define Q921_LOGBUFSIZE 2000
+#define INITIALIZED_MAGIC 42
+
+/*
+ * Helper macros
+ */
+#define Q921_INC_COUNTER(x) (x = (x + 1) % 128)
+#define Q921_DEC_COUNTER(x) (x = (x) ? (x - 1) : 127)
+
+#define Q921_UFRAME_HEADER_SIZE 3
+#define Q921_UFRAME_DATA_OFFSET(tr) ((tr)->Q921HeaderSpace + Q921_UFRAME_HEADER_SIZE)
+
+#define Q921_SFRAME_HEADER_SIZE 4
+#define Q921_SFRAME_DATA_OFFSET(tr) ((tr)->Q921HeaderSpace + Q921_SFRAME_HEADER_SIZE)
+
+#define Q921_IFRAME_HEADER_SIZE 4
+#define Q921_IFRAME_DATA_OFFSET(tr) ((tr)->Q921HeaderSpace + Q921_IFRAME_HEADER_SIZE)
+
+#define Q921_IS_TE(x) ((x)->NetUser == Q921_TE)
+#define Q921_IS_NT(x) ((x)->NetUser == Q921_NT)
+
+#define Q921_IS_STOPPED(tr) ((tr)->state == Q921_STATE_STOPPED)
+
+/* TODO: rework this one */
+#define Q921_IS_READY(tr) ((tr)->state >= Q921_STATE_TEI_ASSIGNED)
+
+#define Q921_IS_PTMP(x) ((x)->NetType == Q921_PTMP)
+#define Q921_IS_PTMP_TE(x) ((x)->NetType == Q921_PTMP && (x)->NetUser == Q921_TE)
+#define Q921_IS_PTMP_NT(x) ((x)->NetType == Q921_PTMP && (x)->NetUser == Q921_NT)
+
+#define Q921_IS_PTP(x) ((x)->NetType == Q921_PTP)
+#define Q921_IS_PTP_TE(x) ((x)->NetType == Q921_PTP && (x)->NetUser == Q921_TE)
+#define Q921_IS_PTP_NT(x) ((x)->NetType == Q921_PTP && (x)->NetUser == Q921_NT)
+
+/* Make life a little easier */
+#define Q921_COMMAND(x) ((x)->NetUser == Q921_TE ? 0 : 1)
+#define Q921_RESPONSE(x) ((x)->NetUser == Q921_TE ? 1 : 0)
+
+#define Q921_IS_COMMAND(tr, x) ((x) == (Q921_IS_TE(tr) ? 1 : 0))
+#define Q921_IS_RESPONSE(tr, x) ((x) == (Q921_IS_TE(tr) ? 0 : 1))
+
+
+/*******************************************************************************
+ * Private functions
+ *******************************************************************************/
+
+/*
+ * L1 / L2 Interface
+ */
+static int Q921Tx21Proc(L2TRUNK trunk, L2UCHAR *Msg, L2INT size);
+static int Q921Tx23Proc(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *Msg, L2INT size);
+
+
+/*
+ * Timers
+ */
+static L2ULONG Q921GetTime(void);
+
+static void Q921T200TimerStart(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T200TimerStop(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T200TimerReset(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T200TimerExpire(L2TRUNK trunk, L2UCHAR tei);
+
+static void Q921T201TimerStart(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T201TimerStop(L2TRUNK trunk, L2UCHAR tei);
+/* static void Q921T201TimerReset(L2TRUNK trunk, L2UCHAR tei); - Unused for now */
+static void Q921T201TimerExpire(L2TRUNK trunk, L2UCHAR tei);
+
+static void Q921T202TimerStart(L2TRUNK trunk);
+static void Q921T202TimerStop(L2TRUNK trunk);
+static void Q921T202TimerReset(L2TRUNK trunk);
+static void Q921T202TimerExpire(L2TRUNK trunk);
+
+static void Q921T203TimerStart(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T203TimerStop(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T203TimerReset(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T203TimerExpire(L2TRUNK trunk, L2UCHAR tei);
+
+static void Q921TM01TimerStart(L2TRUNK trunk, L2UCHAR tei);
+/* static void Q921TM01TimerStop(L2TRUNK trunk, L2UCHAR tei); - Unused for now */
+static void Q921TM01TimerReset(L2TRUNK trunk, L2UCHAR tei);
+/* static void Q921TM01TimerExpire(L2TRUNK trunk, L2UCHAR tei); - Unused for now */
+
+/*
+ * Frame encoding
+ */
+static int Q921SendS(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR sv, L2UCHAR *mes, L2INT size);
+static int Q921SendU(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR m, L2UCHAR *mes, L2INT size);
+
+static int Q921SendRNR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendREJ(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendSABME(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendDM(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendDISC(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendUA(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendUN(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf, L2UCHAR *mes, L2INT size);
+static int Q921SendRR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+
+/*
+ * Frame decoding
+ */
+static int Q921ProcIFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcSFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcUFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+
+static int Q921ProcSABME(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcDM(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcUA(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcDISC(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcRR(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcRNR(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcREJ(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+
+
+/*
+ * (Common) procedures defined in the Q.921 SDL
+ */
+static int Q921SendEnquiry(L2TRUNK trunk, L2UCHAR tei);
+static int Q921SendEnquiryResponse(L2TRUNK trunk, L2UCHAR tei);
+static void Q921ResetExceptionConditions(L2TRUNK trunk, L2UCHAR tei);
+static int Q921EstablishDataLink(L2TRUNK trunk, L2UCHAR tei);
+static int Q921NrErrorRecovery(L2TRUNK trunk, L2UCHAR tei);
+static int Q921InvokeRetransmission(L2TRUNK trunk, L2UCHAR tei, L2UCHAR nr);
+static int Q921AcknowledgePending(L2TRUNK trunk, L2UCHAR tei);
+/*
+static int Q921SetReceiverBusy(L2TRUNK trunk);
+static int Q921ClearReceiverBusy(L2TRUNK trunk);
+*/
+
+/*
+ * Queueing
+ */
+static int Q921SendQueuedIFrame(L2TRUNK trunk, L2UCHAR tei);
+static int Q921EnqueueI(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR *mes, L2INT size);
+
+/*
+ * TEI management
+ */
+static int Q921TeiSendAssignRequest(L2TRUNK trunk);
+static int Q921TeiProcAssignResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiSendVerifyRequest(L2TRUNK trunk);
+static int Q921TeiProcCheckRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiProcRemoveRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiProcAssignRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiProcCheckResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiProcVerifyRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiSendRemoveRequest(L2TRUNK trunk, L2UCHAR tei);
+static int Q921TeiSendDenyResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri);
+static int Q921TeiSendAssignedResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri);
+static int Q921TeiSendCheckRequest(L2TRUNK trunk, L2UCHAR tei);
+
+/*
+ * Logging
+ */
+static int Q921Log(L2TRUNK trunk, Q921LogLevel_t level, const char *fmt, ...);
+static int Q921LogMesg(L2TRUNK trunk, Q921LogLevel_t level, L2UCHAR received, L2UCHAR *mes, L2INT size, const char *fmt, ...);
+
+/*
+ * State handling
+ */
+static int Q921ChangeState(L2TRUNK trunk, Q921State_t state, L2UCHAR tei);
+
+#endif
Added: freeswitch/trunk/libs/openzap/src/isdn/include/Q931.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/include/Q931.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/include/Q931.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1175 @@
+/******************************************************************************
+
+ FileName: Q931.h
+
+ Contents: Header and definition for the ITU-T Q.931 stack. The
+ header contents the following parts:
+
+ - Definition of codes
+ - Definition of information elements (Q931ie_).
+ - Definition of messages (Q931mes_).
+ - Definitian of variables (var_).
+ - Function prototypes.
+
+ Description: The Q.931 stack provided here covers ITU-T Q.931 w/Q.932
+ supplementary services for both PRI, BRI and variants.
+ The stack is generic and designed to deal with variants as
+ needed.
+
+ The stack uses the following interface functions:
+
+ - Q931Initialize Initialize the Q.931 stack.
+ - Q931Rx23 Receive a message from layer 2
+ - Q931Tx32 Send a message to layer 2
+ - Q931Rx43 Receive a message from layer 4 or above.
+ - Q931Tx34 Send a message to layer 4 or above.
+ - Q931TimeTick Periodical timer processing.
+ - Q931ErrorProc Callback for stack error message.
+
+ The protocol is a module with no external dependencies and
+ can easely be ported to any operating system like Windows,
+ Linux, rtos and others.
+
+ Related Files: Q931.h Q.931 Definitions
+ Q931.c Q.931 Interface Functions.
+ Q931api.c Low level L4 API functions.
+
+ Q932.h Q.932 Suplementary Services
+ Q932mes.c Q.932 encoders/coders
+
+ Q931mes.c Q.931 Message encoders/coders
+ Q931ie.c Q.931 IE encoders/coders
+ Q931StateTE.c Generic Q.931 TE State Engine
+ Q931StateNT.c Generic Q.931 NT State Engine
+
+ Design Note 1: For each variant please add separate files starting with
+ the variant short-name as follows:
+
+ <variant>.h Spesific headers needed.
+ <variant>mes.c Message encoders/decores.
+ <variant>ie.c IE encoders/decoders.
+ <variant>StateTE.c TE side state engine.
+ <variant>StateNT.c NT side state engine.
+
+ Design Note 2: The stack is deliberatly made non-threading. Use 1
+ thread per Trunk, but lock access from the timertick
+ and rx, tx functions. And make sure the callbacks only
+ dump messages to a queue, no time-consuming processing
+ inside stack processing.
+
+ All stack processing is async 'fire and forget', meaning
+ that there are not, and should not be any time-consuming
+ processing within the stack-time. The best way to thread
+ a stack is to use one single thread that signal 5 queues.
+
+ - Incoming L2 queue.
+ - Incoming L4 queue.
+ - Outgoing L2 queue.
+ - Outgoing L4 queue.
+ - Error/Trace queue.
+
+ Design Note 3: DSP optimization. The L3 (Rx23) can be called directly
+ from a HDLC receiver without usage of queues for optimized
+ processing. But keep in mind that Q.931 calls Tx34 or Tx32
+ as part of receiving a message from Layer 2.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+******************************************************************************/
+
+#ifndef _Q931_NL
+#define _Q931_NL
+
+/* uncomment the #define below to add x.25 support to the Q.931 */
+/* #define Q931_X25_SUPPORT */
+
+#include "stdio.h"
+
+#ifdef _MSC_VER
+#pragma warning(disable:4100)
+#ifndef strcasecmp
+#define strcasecmp(s1, s2) _stricmp(s1, s2)
+#endif
+#endif
+#include <string.h>
+
+
+/*****************************************************************************
+
+ Enum helper macros <Need description of these macros>
+
+*****************************************************************************/
+#define Q931_ENUM_NAMES(_NAME, _STRINGS) static const char * _NAME [] = { _STRINGS , NULL };
+#define Q931_STR2ENUM_P(_FUNC1, _FUNC2, _TYPE) _TYPE _FUNC1 (const char *name); const char * _FUNC2 (_TYPE type);
+#define Q931_STR2ENUM(_FUNC1, _FUNC2, _TYPE, _STRINGS, _MAX) \
+ _TYPE _FUNC1 (const char *name) \
+ { \
+ int i; \
+ _TYPE t = _MAX ; \
+ \
+ for (i = 0; i < _MAX ; i++) { \
+ if (!strcasecmp(name, _STRINGS[i])) { \
+ t = (_TYPE) i; \
+ break; \
+ } \
+ } \
+ \
+ return t; \
+ } \
+ const char * _FUNC2 (_TYPE type) \
+ { \
+ if (type > _MAX) { \
+ type = _MAX; \
+ } \
+ return _STRINGS[(int)type]; \
+ } \
+
+/*****************************************************************************
+
+ Error Codes
+
+*****************************************************************************/
+typedef enum {
+ Q931E_NO_ERROR = 0,
+
+ Q931E_UNKNOWN_MESSAGE = -3001,
+ Q931E_ILLEGAL_IE = -3002,
+ Q931E_UNKNOWN_IE = -3003,
+ Q931E_BEARERCAP = -3004,
+ Q931E_HLCOMP = -3005,
+ Q931E_LLCOMP = -3006,
+ Q931E_INTERNAL = -3007,
+ Q931E_MISSING_CB = -3008,
+ Q931E_UNEXPECTED_MESSAGE = -3009,
+ Q931E_ILLEGAL_MESSAGE = -3010,
+ Q931E_TOMANYCALLS = -3011,
+ Q931E_INVALID_CRV = -3012,
+ Q931E_CALLID = -3013,
+ Q931E_CALLSTATE = -3014,
+ Q931E_CALLEDSUB = -3015,
+ Q931E_CALLEDNUM = -3016,
+ Q931E_CALLINGNUM = -3017,
+ Q931E_CALLINGSUB = -3018,
+ Q931E_CAUSE = -3019,
+ Q931E_CHANID = -3020,
+ Q931E_DATETIME = -3021,
+ Q931E_DISPLAY = -3022,
+ Q931E_KEYPADFAC = -3023,
+ Q931E_NETFAC = -3024,
+ Q931E_NOTIFIND = -3025,
+ Q931E_PROGIND = -3026,
+ Q931E_RESTARTIND = -3027,
+ Q931E_SEGMENT = -3028,
+ Q931E_SIGNAL = -3029,
+ Q931E_GENERIC_DIGITS = -3030
+} q931_error_t;
+
+/* The q931_error_t enum should be kept in sync with the q931_error_names array in Q931.c */
+
+const char *q931_error_to_name(q931_error_t error);
+
+/*****************************************************************************
+
+ Some speed optimization can be achieved by changing all variables to the
+ word size of your processor. A 32 bit processor has to do a lot of extra
+ work to read a packed 8 bit integer. Changing all fields to 32 bit integer
+ will result in usage of some extra space, but will speed up the stack.
+
+ The stack has been designed to allow L3UCHAR etc. to be any size of 8 bit
+ or larger.
+
+*****************************************************************************/
+
+#define L3UCHAR unsigned char /* Min 8 bit */
+#define L3USHORT unsigned short /* Min 16 bit unsigned */
+#define L3UINT unsigned int /* Min 16 bit unsigned */
+#define L3INT int /* Min 16 bit signed */
+#define L3ULONG unsigned long /* Min 32 bit */
+#define L3BOOL char /* Min 1 bit, valuse 0 & 1 only */
+
+#define L3TRUE 1
+#define L3FALSE 0
+
+/*****************************************************************************
+
+ Global defines.
+
+*****************************************************************************/
+
+typedef L3USHORT ie; /* Special data type to hold a dynamic */
+ /* or optional information element as */
+ /* part of a message struct. MSB = 1 */
+ /* indicate that the ie is present, the */
+ /* last 15 bits is an offset ( or the */
+ /* value for single octet ) to the */
+ /* struct holding the ie. Offset = 0 */
+ /* is buf[1] etc. */
+ /* ie == 0xffff indicates error */
+
+/*****************************************************************************
+
+ MAXTRUNKS sets how many physical trunks this system might have. This
+ number should be keept at a minimum since it will use global space.
+
+ It is recommended that you leave MAXCHPERTRUNK as is
+
+*****************************************************************************/
+
+#define Q931_LOGBUFSIZE 1024 /* size of logging buffer */
+
+#define Q931L4BUF 1000 /* size of message buffer */
+
+#define Q931L2BUF 300 /* size of message buffer */
+
+#define Q931MAXTRUNKS 4 /* Total number of trunks that will be */
+ /* processed by this instance of the */
+ /* stack */
+
+#define Q931MAXCHPERTRUNK 32 /* Number of channels per trunk. The */
+ /* stack uses a static set of 32 */
+ /* channels regardless if it is E1, T1 */
+ /* or BRI that actually is used. */
+
+#define Q931MAXCALLPERTRUNK (Q931MAXCHPERTRUNK * 2)
+ /* Number of max active CRV per trunk. */
+ /* Q.931 can have more calls than there */
+ /* are channels. */
+
+
+#define Q931_IS_BRI(x) ((x)->TrunkType == Q931_TrType_BRI || (x)->TrunkType == Q931_TrType_BRI_PTMP)
+#define Q931_IS_PRI(x) (!Q931_IS_BRI(x))
+
+#define Q931_IS_PTP(x) ((x)->TrunkType != Q931_TrType_BRI_PTMP)
+#define Q931_IS_PTMP(X) ((x)->TrunkType == Q931_TrType_BRI_PTMP)
+
+#define Q931_BRI_MAX_CRV 127
+#define Q931_PRI_MAX_CRV 32767
+
+/*****************************************************************************
+
+ The following defines control the dialect switch tables and should only be
+ changed when a new dialect needs to be inserted into the stack.
+
+ This stack uses an array of functions to know which function to call as
+ it receives a SETUP message etc. A new dialect can when choose to use
+ the proc etc. for standard Q.931 or insert a modified proc.
+
+ This technique has also been used to distinguish between user and network
+ mode to make the code as easy to read and maintainable as possible.
+
+ A message and IE index have been used to save space. These indexes allowes
+ the message or IE code to be used directly and will give back a new index
+ into the table.
+
+*****************************************************************************/
+
+/* WARNING! Initialize Q931CreateDialectCB[] will NULL when increasing the */
+/* Q931MAXDLCT value to avoid Q931Initialize from crashing if one entry is */
+/* not used. */
+#define Q931MAXDLCT 8 /* Max dialects included in this */
+ /* compile. User and Network count as */
+ /* one dialect each. */
+
+#define Q931MAXMES 128 /* Number of messages */
+#define Q931MAXIE 255 /* Number of IE */
+#define Q931MAXUSEDIE 50 /* Maximum number of ie types per Dialect */
+#define Q931MAXCODESETS 7 /* Maximum number of codests (by spec, 0-7) */
+#define Q931MAXSTATE 100 /* Size of state tables */
+#define Q931MAXTIMER 25 /* Maximum number of timers */
+
+/*****************************************************************************
+
+ Call States for ITU-T Q.931 TE (User Mode)
+
+*****************************************************************************/
+
+#define Q931_U0 0
+#define Q931_U1 1
+#define Q931_U2 2
+#define Q931_U3 3
+#define Q931_U4 4
+#define Q931_U6 6
+#define Q931_U7 7
+#define Q931_U8 8
+#define Q931_U9 9
+#define Q931_U10 10
+#define Q931_U11 11
+#define Q931_U12 12
+#define Q931_U15 15
+#define Q931_U17 17
+#define Q931_U19 19
+#define Q931_U25 25
+
+/*****************************************************************************
+
+ Call States for ITU-T Q.931 NT (Network Mode)
+
+*****************************************************************************/
+#define Q931_N0 (0x0100 | 0)
+#define Q931_N1 (0x0100 | 1)
+#define Q931_N2 (0x0100 | 2)
+#define Q931_N3 (0x0100 | 3)
+#define Q931_N4 (0x0100 | 4)
+#define Q931_N6 (0x0100 | 6)
+#define Q931_N7 (0x0100 | 7)
+#define Q931_N8 (0x0100 | 8)
+#define Q931_N9 (0x0100 | 9)
+#define Q931_N10 (0x0100 | 11)
+#define Q931_N11 (0x0100 | 11)
+#define Q931_N12 (0x0100 | 12)
+#define Q931_N15 (0x0100 | 15)
+#define Q931_N17 (0x0100 | 17)
+#define Q931_N19 (0x0100 | 19)
+#define Q931_N22 (0x0100 | 22)
+#define Q931_N25 (0x0100 | 25)
+
+/*****************************************************************************
+
+ Q.931 Message codes
+
+*****************************************************************************/
+
+#define Q931mes_ALERTING 0x01 /* 0000 0001 */
+#define Q931mes_CALL_PROCEEDING 0x02 /* 0000 0010 */
+#define Q931mes_CONNECT 0x07 /* 0000 0111 */
+#define Q931mes_CONNECT_ACKNOWLEDGE 0x0f /* 0000 1111 */
+#define Q931mes_PROGRESS 0x03 /* 0000 0011 */
+#define Q931mes_SETUP 0x05 /* 0000 0101 */
+#define Q931mes_SETUP_ACKNOWLEDGE 0x0d /* 0000 1101 */
+#define Q931mes_RESUME 0x26 /* 0010 0110 */
+#define Q931mes_RESUME_ACKNOWLEDGE 0x2e /* 0010 1110 */
+#define Q931mes_RESUME_REJECT 0x22 /* 0010 0010 */
+#define Q931mes_SUSPEND 0x25 /* 0010 0101 */
+#define Q931mes_SUSPEND_ACKNOWLEDGE 0x2d /* 0010 1101 */
+#define Q931mes_SUSPEND_REJECT 0x21 /* 0010 0001 */
+#define Q931mes_USER_INFORMATION 0x20 /* 0010 0000 */
+#define Q931mes_DISCONNECT 0x45 /* 0100 0101 */
+#define Q931mes_RELEASE 0x4d /* 0100 1101 */
+#define Q931mes_RELEASE_COMPLETE 0x5a /* 0101 1010 */
+#define Q931mes_RESTART 0x46 /* 0100 0110 */
+#define Q931mes_RESTART_ACKNOWLEDGE 0x4e /* 0100 1110 */
+#define Q931mes_CONGESTION_CONTROL 0x79 /* 0111 1001 */
+#define Q931mes_INFORMATION 0x7b /* 0111 1011 */
+#define Q931mes_NOTIFY 0x6e /* 0110 1110 */
+#define Q931mes_STATUS 0x7d /* 0111 1101 */
+#define Q931mes_STATUS_ENQUIRY 0x75 /* 0111 0101 */
+#define Q931mes_SEGMENT 0x60 /* 0110 0000 */
+
+#define Q931mes_SERVICE 0x0f /* 0000 1111 */
+#define Q931mes_SERVICE_ACKNOWLEDGE 0x07 /* 0000 0111 */
+
+
+/**
+ * Generic Q.931 Timers
+ */
+enum {
+ Q931_TIMER_T300 = 1, /* */
+ Q931_TIMER_T301,
+ Q931_TIMER_T302,
+ Q931_TIMER_T303,
+ Q931_TIMER_T304,
+ Q931_TIMER_T305,
+ Q931_TIMER_T306,
+ Q931_TIMER_T307,
+ Q931_TIMER_T308,
+ Q931_TIMER_T309,
+ Q931_TIMER_T310,
+ Q931_TIMER_T311,
+ Q931_TIMER_T312,
+ Q931_TIMER_T313,
+ Q931_TIMER_T314,
+ Q931_TIMER_T315,
+ Q931_TIMER_T316,
+ Q931_TIMER_T317,
+ Q931_TIMER_T318,
+ Q931_TIMER_T319,
+ Q931_TIMER_T320,
+ Q931_TIMER_T321,
+ Q931_TIMER_T322,
+};
+
+/**
+ * Q.931 ToN
+ */
+enum {
+ Q931_TON_UNKNOWN = 0x00,
+ Q931_TON_INTERNATIONAL = 0x01,
+ Q931_TON_NATIONAL = 0x02,
+ Q931_TON_NETWORK_SPECIFIC = 0x03,
+ Q931_TON_SUBSCRIBER_NUMBER = 0x04,
+ Q931_TON_ABBREVIATED_NUMBER = 0x06,
+ Q931_TON_RESERVED = 0x07
+};
+
+/**
+ * Q.931 Numbering Plan
+ */
+enum {
+ Q931_NUMPLAN_UNKNOWN = 0x00,
+ Q931_NUMPLAN_E164 = 0x01,
+ Q931_NUMPLAN_X121 = 0x03,
+ Q931_NUMPLAN_F69 = 0x04,
+ Q931_NUMPLAN_NATIONAL = 0x08,
+ Q931_NUMPLAN_PRIVATE = 0x09,
+ Q931_NUMPLAN_RESERVED = 0x0e
+};
+
+/**
+ * Q.931 Presentation Indicator
+ */
+enum {
+ Q931_PRES_ALLOWED = 0x00,
+ Q931_PRES_RESTRICTED = 0x01,
+ Q931_PRES_NOT_AVAILABLE = 0x02,
+ Q931_PRES_RESERVED = 0x03
+};
+
+/**
+ * Q.931 Screening Indicator
+ */
+enum {
+ Q931_SCREEN_USER_NOT_SCREENED = 0x00,
+ Q931_SCREEN_USER_VERIFIED_PASSED = 0x01,
+ Q931_SCREEN_USER_VERIFIED_FAILED = 0x02,
+ Q931_SCREEN_NETWORK = 0x03
+};
+
+/**
+ * Q.931 Coding Standard
+ */
+enum {
+ Q931_CODING_ITU = 0x00,
+ Q931_CODING_ISO = 0x01,
+ Q931_CODING_NATIONAL = 0x02,
+ Q931_CODING_NETWORK = 0x03
+};
+
+/**
+ * Q.931 High layer characteristik id
+ */
+enum {
+ Q931_HLCHAR_TELEPHONY = 0x01,
+ Q931_HLCHAR_FAX_G23 = 0x04,
+ Q931_HLCHAR_FAX_G4 = 0x21,
+ Q931_HLCHAR_FAX_G4II = 0x24,
+ Q931_HLCHAR_T102 = 0x32,
+ Q931_HLCHAR_T101 = 0x33,
+ Q931_HLCHAR_F60 = 0x35,
+ Q931_HLCHAR_X400 = 0x38,
+ Q931_HLCHAR_X200 = 0x41
+};
+
+/**
+ * Q.931 User information layer 1 protocol
+ */
+enum {
+ Q931_UIL1P_V110 = 0x01,
+ Q931_UIL1P_I460 = 0x01,
+ Q931_UIL1P_X30 = 0x01,
+
+ Q931_UIL1P_G711U = 0x02,
+ Q931_UIL1P_G711A = 0x03,
+ Q931_UIL1P_G721 = 0x04,
+
+ Q931_UIL1P_H221 = 0x05,
+ Q931_UIL1P_H242 = 0x05,
+
+ Q931_UIL1P_H223 = 0x06,
+ Q931_UIL1P_H245 = 0x06,
+
+ Q931_UIL1P_RATE_ADAP = 0x07,
+
+ Q931_UIL1P_V120 = 0x08,
+ Q931_UIL1P_X31 = 0x09
+};
+
+/**
+ * Q.931 Information Transfer Capability
+ */
+enum {
+ Q931_ITC_SPEECH = 0x00,
+ Q931_ITC_UNRESTRICTED = 0x08,
+ Q931_ITC_RESTRICTED = 0x09,
+ Q931_ITC_3K1_AUDIO = 0x10,
+ Q931_ITC_UNRESTRICTED_TONES = 0x11,
+ Q931_ITC_VIDEO = 0x18
+};
+
+/**
+ * Q.931 Information transfer rate
+ */
+enum {
+ Q931_ITR_PACKET = 0x00,
+ Q931_ITR_64K = 0x10,
+ Q931_ITR_128K = 0x11,
+ Q931_ITR_384K = 0x13,
+ Q931_ITR_1536K = 0x15,
+ Q931_ITR_1920K = 0x17,
+ Q931_ITR_MULTI = 0x18
+};
+
+/*****************************************************************************
+
+ Struct: Q931mes_Header
+
+ Description: Used to read the header & message code.
+
+*****************************************************************************/
+typedef struct {
+ L3UINT Size; /* Size of message in bytes */
+ L3UCHAR ProtDisc; /* Protocol Discriminator */
+ L3UCHAR MesType; /* Message type */
+ L3UCHAR CRVFlag; /* Call reference value flag */
+ L3INT CRV; /* Call reference value */
+
+} Q931mes_Header;
+
+/*****************************************************************************
+
+ Struct: Q931mes_Generic
+
+ Description: Generic header containing all IE's. This is not used, but is
+ provided in case a proprietary variant needs it.
+
+*****************************************************************************/
+typedef struct {
+ L3UINT Size; /* Size of message in bytes */
+ L3UCHAR ProtDisc; /* Protocol Discriminator */
+ L3UCHAR MesType; /* Message type */
+ L3UCHAR CRVFlag; /* Call reference value flag */
+ L3INT CRV; /* Call reference value */
+
+ /* WARNING: don't touch anything above this line (TODO: use Q931mes_Header directly to make sure it's the same) */
+
+ L3UCHAR Tei; /* TEI */
+
+ ie Shift;
+ ie MoreData;
+ ie SendComplete;
+ ie CongestionLevel;
+ ie RepeatInd;
+
+ ie Segment; /* Segmented message */
+ ie BearerCap; /* Bearer Capability */
+ ie Cause; /* Cause */
+ ie CallState; /* Call State */
+ ie CallID; /* Call Identity */
+ ie ChanID; /* Channel Identification */
+ ie ChangeStatus; /* Change Staus */
+ ie ProgInd; /* Progress Indicator */
+ ie NetFac; /* Network Spesific Facilities */
+ ie NotifInd; /* Notification Indicator */
+ ie Display; /* Display */
+ ie DateTime; /* Date/Time */
+ ie KeypadFac; /* Keypad Facility */
+ ie Signal; /* Signal */
+ ie InfoRate; /* Information rate */
+ ie EndEndTxDelay; /* End to End Transmit Delay */
+ ie TransDelSelInd; /* Transmit Delay Sel. and Ind. */
+ ie PackParam; /* Packed Layer Binary parameters */
+ ie PackWinSize; /* Packet Layer Window Size */
+ ie PackSize; /* Packed Size */
+ ie ClosedUserGrp; /* Closed User Group */
+ ie RevChargeInd; /* Reverse Charging Indicator */
+ ie CalledNum; /* Called Party Number */
+ ie CalledSub; /* Called Party subaddress */
+ ie CallingNum; /* Calling Party Number */
+ ie CallingSub; /* Calling Party Subaddress */
+ ie RedirNum; /* Redirection Number */
+ ie TransNetSel; /* Transmit Network Selection */
+ ie LLRepeatInd; /* Repeat Indicator 2 LLComp */
+ ie RestartWin; /* Restart Window */
+ ie RestartInd; /* Restart Indicator */
+ ie LLComp; /* Low Layer Compatibility */
+ ie HLComp; /* High Layer Compatibility */
+ ie UserUser; /* User-user */
+ ie Escape; /* Escape for extension */
+ ie Switchhook;
+ ie FeatAct;
+ ie FeatInd;
+ ie GenericDigits;
+
+ L3UCHAR buf[1]; /* Buffer for IE's */
+
+} Q931mes_Generic;
+
+
+/*****************************************************************************
+
+ Struct: Q931_TrunkInfo
+
+ Description: TrunkInfo is the struct entry used to store Q.931 related
+ information and state for E1/T1/J1 trunks and associated
+ channels in the system.
+
+ The user should store this information outside this stack
+ and needs to feed the interface functions with a pointer to
+ the TrunkInfo entry.
+
+*****************************************************************************/
+typedef struct Q931_TrunkInfo Q931_TrunkInfo_t;
+
+typedef enum {
+ Q931_LOG_NONE = -1,
+ Q931_LOG_EMERG,
+ Q931_LOG_ALERT,
+ Q931_LOG_CRIT,
+ Q931_LOG_ERROR,
+ Q931_LOG_WARNING,
+ Q931_LOG_NOTICE,
+ Q931_LOG_INFO,
+ Q931_LOG_DEBUG
+} Q931LogLevel_t;
+
+typedef L3INT (*Q931Tx34CB_t) (void *,L3UCHAR *, L3INT);
+typedef L3INT (*Q931Tx32CB_t) (void *, L3INT, L3UCHAR, L3UCHAR *, L3INT);
+typedef L3INT (*Q931ErrorCB_t) (void *,L3INT,L3INT,L3INT);
+typedef L3INT (*Q931LogCB_t) (void *, Q931LogLevel_t, char *, L3INT);
+
+typedef enum { /* Network/User Mode. */
+ Q931_TE=0, /* 0 : User Mode */
+ Q931_NT=1 /* 1 : Network Mode */
+} Q931NetUser_t;
+
+typedef enum { /* Dialect enum */
+ Q931_Dialect_Q931 = 0,
+ Q931_Dialect_National = 2,
+ Q931_Dialect_DMS = 4,
+ Q931_Dialect_5ESS = 6, /* Coming soon to a PRI stack near you! */
+
+ Q931_Dialect_Count
+} Q931Dialect_t;
+#define DIALECT_STRINGS "q931", "", "national", "", "dms", "", "5ess", ""
+Q931_STR2ENUM_P(q931_str2Q931Dialect_type, q931_Q931Dialect_type2str, Q931Dialect_t)
+
+typedef enum { /* Trunk Line Type. */
+ Q931_TrType_E1 = 0, /* 0 : E1 Trunk */
+ Q931_TrType_T1 = 1, /* 1 : T1 Trunk */
+ Q931_TrType_J1 = 2, /* 2 : J1 Trunk */
+ Q931_TrType_BRI = 3, /* 3 : BRI Trunk */
+ Q931_TrType_BRI_PTMP = 4 /* 4 : BRI PTMP Trunk */
+} Q931_TrunkType_t;
+
+typedef enum { /* Trunk State */
+ Q931_TrState_NoAlignment=0, /* Trunk not aligned */
+ Q931_TrState_Aligning=1, /* Aligning in progress */
+ Q931_TrState_Aligned=2 /* Trunk Aligned */
+} Q931_TrunkState_t;
+
+typedef enum {
+ Q931_ChType_NotUsed=0, /* Unused Channel */
+ Q931_ChType_B=1, /* B Channel (Voice) */
+ Q931_ChType_D=2, /* D Channel (Signalling) */
+ Q931_ChType_Sync=3 /* Sync Channel */
+} Q931_ChanType_t;
+
+struct Q931_Call
+{
+ L3UCHAR InUse; /* Indicate if entry is in use. */
+ /* 0 = Not in Use */
+ /* 1 = Active Call. */
+
+ L3UCHAR Tei; /* Associated TEI */
+
+ L3UCHAR BChan; /* Associated B Channel. */
+ /* 0 - 31 valid B chan */
+ /* 255 = Not allocated */
+
+ L3INT CRV; /* Associated CRV. */
+
+ L3UINT State; /* Call State. */
+ /* 0 is Idle, but other values are */
+ /* defined per dialect. */
+ /* Default usage is 1-99 for TE and */
+ /* 101 - 199 for NT. */
+
+ L3ULONG Timer; /* Timer in ms. The TimeTick will check */
+ /* if this has exceeded the timeout, and */
+ /* if so call the timers timeout proc. */
+
+ L3USHORT TimerID; /* Timer Identification/State */
+ /* actual values defined by dialect */
+ /* 0 : No timer running */
+ /* ITU-T Q.931:301 - 322 Timer running */
+};
+
+struct Q931_TrunkInfo
+{
+ Q931NetUser_t NetUser; /* Network/User Mode. */
+ Q931_TrunkType_t TrunkType; /* Trunk Line Type. */
+ Q931Dialect_t Dialect; /* Q.931 Based dialect index. */
+
+ Q931Tx34CB_t Q931Tx34CBProc;
+ Q931Tx32CB_t Q931Tx32CBProc;
+ Q931ErrorCB_t Q931ErrorCBProc;
+ Q931LogCB_t Q931LogCBProc;
+ void *PrivateData32;
+ void *PrivateData34;
+ void *PrivateDataLog;
+
+ Q931LogLevel_t loglevel;
+
+ L3UCHAR Enabled; /* Enabled/Disabled */
+ /* 0 = Disabled */
+ /* 1 = Enabled */
+
+ Q931_TrunkState_t TrunkState;
+
+ L3INT LastCRV; /* Last used crv for the trunk. */
+
+ L3UCHAR L3Buf[Q931L4BUF]; /* message buffer for messages to be */
+ /* send from Q.931 L4. */
+
+ L3UCHAR L2Buf[Q931L2BUF]; /* buffer for messages send to L2. */
+
+ /* The auto flags below switch on/off automatic Ack messages. SETUP ACK */
+ /* as an example can be sent by the stack in response to SETUP to buy */
+ /* time in processing on L4. Setting this to true will cause the stack */
+ /* to automatically send this. */
+
+ L3BOOL autoSetupAck; /* Indicate if the stack should send */
+ /* SETUP ACK or not. 0=No, 1 = Yes. */
+
+ L3BOOL autoConnectAck; /* Indicate if the stack should send */
+ /* CONNECT ACT or not. 0=No, 1=Yes. */
+
+ L3BOOL autoRestartAck; /* Indicate if the stack should send */
+ /* RESTART ACK or not. 0=No, 1=Yes. */
+
+ L3BOOL autoServiceAck; /* Indicate if the stack should send */
+ /* SERVICE ACK or not. 0=No, 1=Yes. */
+
+ /* channel array holding info per channel. Usually defined to 32 */
+ /* channels to fit an E1 since T1/J1 and BRI will fit inside a E1. */
+ struct _charray
+ {
+ Q931_ChanType_t ChanType; /* Unused, B, D, Sync */
+
+ L3UCHAR Available; /* Channel Available Flag */
+ /* 0 : Avaiabled */
+ /* 1 : Used */
+
+ L3INT CRV; /* Associated CRV */
+
+ } ch[Q931MAXCHPERTRUNK];
+
+ /* Active Call information indentified by CRV. See Q931AllocateCRV for */
+ /* initialization of call table. */
+ struct Q931_Call call[Q931MAXCALLPERTRUNK];
+};
+
+/*****************************************************************************
+
+ Struct: Q931State
+
+ Description: Define a Q931 State, legal events and next state for each
+ event. Used to simplify the state engine logic. Each state
+ engine defines its own state table and the logic need only
+ call a helper function to check if the message is legal
+ at this stage.
+
+*****************************************************************************/
+typedef struct
+{
+ L3INT State;
+ L3INT Message;
+ L3UCHAR Direction;
+} Q931State;
+
+/*****************************************************************************
+
+ Proc table external references.
+
+ The proc tables are defined in Q931.c and initialized in Q931Initialize.
+
+*****************************************************************************/
+typedef L3INT (q931proc_func_t) (Q931_TrunkInfo_t *pTrunk, L3UCHAR *, L3INT);
+
+typedef L3INT (q931umes_func_t) (Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+typedef L3INT (q931pmes_func_t) (Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+typedef L3INT (q931uie_func_t) (Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff);
+typedef L3INT (q931pie_func_t) (Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+
+typedef L3INT (q931timeout_func_t) (Q931_TrunkInfo_t *pTrunk, L3INT callIndex);
+typedef L3ULONG q931timer_t;
+
+extern q931proc_func_t *Q931Proc[Q931MAXDLCT][Q931MAXMES];
+
+extern q931umes_func_t *Q931Umes[Q931MAXDLCT][Q931MAXMES];
+extern q931pmes_func_t *Q931Pmes[Q931MAXDLCT][Q931MAXMES];
+
+extern q931uie_func_t *Q931Uie[Q931MAXDLCT][Q931MAXIE];
+extern q931pie_func_t *Q931Pie[Q931MAXDLCT][Q931MAXIE];
+
+extern q931timeout_func_t *Q931Timeout[Q931MAXDLCT][Q931MAXTIMER];
+extern q931timer_t Q931Timer[Q931MAXDLCT][Q931MAXTIMER];
+
+
+/*****************************************************************************
+
+ Macro: GetIETotoSize
+
+ Syntax: L3INT GetIETotSize(InfoElem ie);
+
+ Description: Compute the total size in bytes of an info element including
+ size of 'header'.
+
+*****************************************************************************/
+#define Q931GetIETotSize(ie) (((ie.InfoID & 0x80) != 0) ? 1 : ie.LenIE) + 2)
+
+/*****************************************************************************
+
+ Macro: IsIEPresent
+
+ Syntax: BOOL IsIEPresent(ie InfoElement);
+
+ Description: Return TRUE if the Information Element is included.
+
+*****************************************************************************/
+#define Q931IsIEPresent(x) ((x & 0x8000) != 0)
+
+/*****************************************************************************
+
+ Macro: GetIEOffset and GetIEValue
+
+ Syntax: L3INT GetIEOffset(ie InfoElement)
+ L3INT GetIEValue(ie InfoElement)
+
+ Description: Returns the offset (or the value )to the Information Element.
+
+ Note: GetIEValue assumes that the 15 lsb bit is the value of a
+ single octet information element. This macro can not be used
+ on a variable information element.
+
+*****************************************************************************/
+#define Q931GetIEOffset(x) (x & 0x7fff)
+#define Q931GetIEValue(x) (x & 0x7fff)
+
+/*****************************************************************************
+
+ Macro: Q931GetIEPtr
+
+ Syntax: void * Q931GetIEPtr(ie InfoElement, L3UCHAR * Buf);
+
+ Description: Compute a Ptr to the information element.
+
+*****************************************************************************/
+#define Q931GetIEPtr(ie,buf) ((void *)&buf[Q931GetIEOffset(ie)])
+
+/*****************************************************************************
+
+ Macro: SetIE
+
+ Syntax: void SetIE(ie InfoElement, L3INT Offset);
+
+ Description: Set an information element.
+
+*****************************************************************************/
+#define Q931SetIE(x,o) { x = (ie)(o) | 0x8000; }
+
+/*****************************************************************************
+
+ Macro: IsQ931Ext
+
+ Syntax BOOL IsQ931Ext(L3UCHAR c)
+
+ Description: Return true Check if the msb (bit 8) is 0. This indicate
+ that the octet is extended.
+
+*****************************************************************************/
+#define IsQ931Ext(x) ((x & 0x80) == 0)
+
+/*****************************************************************************
+
+ Macro: ieGetOctet
+
+ Syntax: unsigned L3UCHAR ieGetOctet(L3INT e)
+
+ Description: Macro to fetch one byte from an integer. Mostly used to
+ avoid warnings.
+
+*****************************************************************************/
+#define ieGetOctet(x) ((L3UCHAR)(x))
+
+/*****************************************************************************
+
+ Macro: NoWarning
+
+ Syntax: void NoWarning(x)
+
+ Description: Macro to suppress unreferenced formal parameter warnings
+
+ Used during creation of the stack since the stack is
+ developed for Warning Level 4 and this creates a lot of
+ warning for the initial empty functions.
+
+*****************************************************************************/
+#define NoWarning(x) (x = x)
+
+/*****************************************************************************
+
+ External references. See Q931.c for details.
+
+*****************************************************************************/
+
+#include "Q931ie.h"
+
+#include "Q932.h"
+
+/*****************************************************************************
+
+ Q.931 Message Pack/Unpack functions. Implemented in Q931mes.c
+
+*****************************************************************************/
+L3INT Q931Pmes_Alerting(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_CallProceeding(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Connect(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ConnectAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Progress(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_SetupAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Resume(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ResumeAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ResumeReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Suspend(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_SuspendAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_SuspendReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_UserInformation(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Disconnect(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Release(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ReleaseComplete(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Restart(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_RestartAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_CongestionControl(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Information(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Notify(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Segment(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Status(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_StatusEnquiry(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Service(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ServiceAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+
+L3INT Q931Umes_Alerting(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_CallProceeding(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Connect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_ConnectAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Progress(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_SetupAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Resume(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_ResumeAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_ResumeReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Suspend(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_SuspendAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_SuspendReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_UserInformation(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Disconnect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Release(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_ReleaseComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Restart(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_RestartAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_CongestionControl(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Information(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Notify(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Segment(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Status(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_StatusEnquiry(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Service(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT Q931Umes_ServiceAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+
+
+/*****************************************************************************
+
+ Q.931 Process Function Prototyping. Implemented in Q931StateTE.c
+
+*****************************************************************************/
+L3INT Q931ProcAlertingTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcCallProceedingTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcConnectTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcConnectAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcProgressTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSetupTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSetupAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeRejectTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendRejectTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcUserInformationTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcDisconnectTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcReleaseTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcReleaseCompleteTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcRestartTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcRestartAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcCongestionControlTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcInformationTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcNotifyTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcStatusTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcStatusEnquiryTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSegmentTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+
+L3INT Q931ProcAlertingNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcCallProceedingNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcConnectNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcConnectAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcProgressNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSetupNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSetupAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeRejectNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendRejectNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcUserInformationNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcDisconnectNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcReleaseNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcReleaseCompleteNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcRestartNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcRestartAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcCongestionControlNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcInformationNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcNotifyNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcStatusNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcStatusEnquiryNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSegmentNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+
+L3INT Q931ProcUnknownMessage(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcUnexpectedMessage(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+
+/*****************************************************************************
+
+ Interface Function Prototypes. Implemented in Q931.c
+
+*****************************************************************************/
+void Q931TimerTick(Q931_TrunkInfo_t *pTrunk);
+L3INT Q931Rx23(Q931_TrunkInfo_t *pTrunk, L3INT ind, L3UCHAR tei, L3UCHAR * Mes, L3INT Size);
+L3INT Q931Tx32Data(Q931_TrunkInfo_t *pTrunk, L3UCHAR bcast, L3UCHAR * Mes, L3INT Size);
+L3INT Q931Rx43(Q931_TrunkInfo_t *pTrunk, L3UCHAR * Mes, L3INT Size);
+L3INT Q931Tx34(Q931_TrunkInfo_t *pTrunk, L3UCHAR * Mes, L3INT Size);
+void Q931SetError(Q931_TrunkInfo_t *pTrunk,L3INT ErrID, L3INT ErrPar1, L3INT ErrPar2);
+
+void Q931SetDefaultErrorCB(Q931ErrorCB_t Q931ErrorPar);
+
+void Q931CreateTE(L3UCHAR i);
+void Q931CreateNT(L3UCHAR i);
+void Q931SetMesCreateCB(L3INT (*callback)(void));
+void Q931SetDialectCreateCB(L3INT (*callback)(L3INT));
+void Q931SetHeaderSpace(L3INT space);
+
+void Q931SetMesProc(L3UCHAR mes, L3UCHAR dialect, q931proc_func_t *Q931ProcFunc, q931umes_func_t *Q931UmesFunc, q931pmes_func_t *Q931PmesFunc);
+void Q931SetIEProc(L3UCHAR iec, L3UCHAR dialect, q931pie_func_t *Q931PieProc, q931uie_func_t *Q931UieProc);
+void Q931SetTimeoutProc(L3UCHAR dialect, L3UCHAR timer, q931timeout_func_t *Q931TimeoutProc);
+void Q931SetTimerDefault(L3UCHAR dialect, L3UCHAR timer, q931timer_t timeout);
+
+void Q931Initialize(void);
+void Q931AddDialect(L3UCHAR iDialect, void (*Q931CreateDialectCB)(L3UCHAR iDialect));
+L3INT Q931InitMesSetup(Q931mes_Generic *p);
+L3INT Q931InitMesRestartAck(Q931mes_Generic * pMes);
+L3INT Q931InitMesGeneric(Q931mes_Generic *pMes);
+
+L3INT Q931CreateCRV(Q931_TrunkInfo_t *pTrunk, L3INT * callIndex);
+L3INT Q931ReleaseCRV(Q931_TrunkInfo_t *pTrunk, L3INT CRV);
+L3INT Q931AllocateCRV(Q931_TrunkInfo_t *pTrunk, L3INT iCRV, L3INT * callIndex);
+L3INT Q931FindCRV(Q931_TrunkInfo_t *pTrunk, L3INT crv, L3INT *callindex);
+L3INT Q931GetCallState(Q931_TrunkInfo_t *pTrunk, L3INT iCRV);
+L3INT Q931StartTimer(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3USHORT iTimer);
+L3INT Q931StopTimer(Q931_TrunkInfo_t *pTrunk, L3INT callindex, L3USHORT iTimer);
+L3INT Q931SetState(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3INT iState);
+L3ULONG Q931GetTime(void);
+void Q931SetGetTimeCB(L3ULONG (*callback)(void));
+void Q931AddStateEntry(L3UCHAR iD, L3INT iState, L3INT iMes, L3UCHAR cDir);
+L3BOOL Q931IsEventLegal(L3UCHAR iD, L3INT iState, L3INT iMes, L3UCHAR cDir);
+
+/*****************************************************************************
+
+ Q.931 Low Level API Function Prototyping. Implemented in Q931API.c
+
+*****************************************************************************/
+ie Q931AppendIE(L3UCHAR *pm, L3UCHAR *pi);
+L3INT Q931GetUniqueCRV(Q931_TrunkInfo_t *pTrunk);
+
+L3INT Q931InitIEBearerCap(Q931ie_BearerCap *p);
+L3INT Q931InitIEChanID(Q931ie_ChanID *p);
+L3INT Q931InitIEProgInd(Q931ie_ProgInd *p);
+L3INT Q931InitIENetFac(Q931ie_NetFac * pIE);
+L3INT Q931InitIEDisplay(Q931ie_Display * pIE);
+L3INT Q931InitIEDateTime(Q931ie_DateTime * pIE);
+L3INT Q931InitIEKeypadFac(Q931ie_KeypadFac * pIE);
+L3INT Q931InitIESignal(Q931ie_Signal * pIE);
+L3INT Q931InitIECallingNum(Q931ie_CallingNum * pIE);
+L3INT Q931InitIECallingSub(Q931ie_CallingSub * pIE);
+L3INT Q931InitIECalledNum(Q931ie_CalledNum * pIE);
+L3INT Q931InitIECalledSub(Q931ie_CalledSub * pIE);
+L3INT Q931InitIETransNetSel(Q931ie_TransNetSel * pIE);
+L3INT Q931InitIELLComp(Q931ie_LLComp * pIE);
+L3INT Q931InitIEHLComp(Q931ie_HLComp * pIE);
+
+L3INT Q931Disconnect(Q931_TrunkInfo_t *pTrunk, L3INT iTo, L3INT iCRV, L3INT iCause);
+L3INT Q931ReleaseComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+L3INT Q931AckRestart(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+L3INT Q931AckConnect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+L3INT Q931AckSetup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+L3INT Q931AckService(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+
+L3INT Q931Api_InitTrunk(Q931_TrunkInfo_t *pTrunk,
+ Q931Dialect_t Dialect,
+ Q931NetUser_t NetUser,
+ Q931_TrunkType_t TrunkType,
+ Q931Tx34CB_t Q931Tx34CBProc,
+ Q931Tx32CB_t Q931Tx32CBProc,
+ Q931ErrorCB_t Q931ErrorCBProc,
+ void *PrivateData32,
+ void *PrivateData34);
+
+L3INT Q931GetMesSize(Q931mes_Generic *pMes);
+L3INT Q931InitMesResume(Q931mes_Generic * pMes);
+
+L3INT Q931Log(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level, const char *fmt, ...);
+void Q931SetLogCB(Q931_TrunkInfo_t *trunk, Q931LogCB_t func, void *priv);
+void Q931SetLogLevel(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level);
+
+void Q931SetL4HeaderSpace(L3INT space);
+void Q931SetL2HeaderSpace(L3INT space);
+L3INT Q931ProcDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b,L3INT c);
+L3INT Q931UmesDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT Q931UieDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff);
+L3INT Q931PmesDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931PieDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+L3INT Q931TxDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT n);
+L3INT Q931ErrorDummy(void *priv, L3INT a, L3INT b, L3INT c);
+L3INT Q931TimeoutDummy(Q931_TrunkInfo_t *pTrunk, L3INT callIndex);
+
+L3INT Q931MesgHeader(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *mes, L3UCHAR *OBuf, L3INT Size, L3INT *IOff);
+
+#endif /* _Q931_NL */
Added: freeswitch/trunk/libs/openzap/src/isdn/include/Q931ie.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/include/Q931ie.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/include/Q931ie.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1205 @@
+/******************************************************************************
+
+ FileName: Q931ie.h
+
+ Contents: Header and definition for the ITU-T Q.931 ie
+ structures and functions
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+******************************************************************************/
+
+#ifndef _Q931IE_NL
+#define _Q931IE_NL
+
+/* Codesets */
+
+typedef enum {
+
+ Q931_CODESET_0 = ( 0 ),
+ Q931_CODESET_1 = ( 1 << 8 ),
+ Q931_CODESET_2 = ( 2 << 8 ),
+ Q931_CODESET_3 = ( 3 << 8 ),
+ Q931_CODESET_4 = ( 4 << 8 ),
+ Q931_CODESET_5 = ( 5 << 8 ),
+ Q931_CODESET_6 = ( 6 << 8 ),
+ Q931_CODESET_7 = ( 7 << 8 )
+
+} q931_codeset_t;
+
+/* Single octet information elements */
+#define Q931ie_SHIFT 0x90 /* 1001 ---- */
+#define Q931ie_MORE_DATA 0xa0 /* 1010 ---- */
+#define Q931ie_SENDING_COMPLETE 0xa1 /* 1010 0001 */
+#define Q931ie_CONGESTION_LEVEL 0xb0 /* 1011 ---- */
+#define Q931ie_REPEAT_INDICATOR 0xd0 /* 1101 ---- */
+
+/* Variable Length Information Elements */
+#define Q931ie_SEGMENTED_MESSAGE 0x00 /* 0000 0000 */
+#define Q931ie_CHANGE_STATUS 0x01 /* 0000 0001 */
+#define Q931ie_BEARER_CAPABILITY 0x04 /* 0000 0100 */
+#define Q931ie_CAUSE 0x08 /* 0000 1000 */
+#define Q931ie_CALL_IDENTITY 0x10 /* 0001 0000 */
+#define Q931ie_CALL_STATE 0x14 /* 0001 0100 */
+#define Q931ie_CHANNEL_IDENTIFICATION 0x18 /* 0001 1000 */
+#define Q931ie_PROGRESS_INDICATOR 0x1e /* 0001 1110 */
+#define Q931ie_NETWORK_SPECIFIC_FACILITIES 0x20 /* 0010 0000 */
+#define Q931ie_NOTIFICATION_INDICATOR 0x27 /* 0010 0111 */
+#define Q931ie_DISPLAY 0x28 /* 0010 1000 */
+#define Q931ie_DATETIME 0x29 /* 0010 1001 */
+#define Q931ie_KEYPAD_FACILITY 0x2c /* 0010 1100 */
+#define Q931ie_SIGNAL 0x34 /* 0011 0100 */
+#define Q931ie_SWITCHOOK 0x36 /* 0011 0110 */
+#define Q931ie_FEATURE_ACTIVATION 0x38 /* 0011 1000 */
+#define Q931ie_FEATURE_INDICATION 0x39 /* 0011 1001 */
+#define Q931ie_INFORMATION_RATE 0x40 /* 0100 0000 */
+#define Q931ie_END_TO_END_TRANSIT_DELAY 0x42 /* 0100 0010 */
+#define Q931ie_TRANSIT_DELAY_SELECTION_AND_IND 0x43 /* 0100 0011 */
+#define Q931ie_PACKED_LAYER_BIMARY_PARAMETERS 0x44 /* 0100 0100 */
+#define Q931ie_PACKED_LAYER_WINDOW_SIZE 0x45 /* 0100 0101 */
+#define Q931ie_PACKED_SIZE 0x46 /* 0100 0110 */
+#define Q931ie_CALLING_PARTY_NUMBER 0x6c /* 0110 1100 */
+#define Q931ie_CALLING_PARTY_SUBADDRESS 0x6d /* 0110 1101 */
+#define Q931ie_CALLED_PARTY_NUMBER 0x70 /* 0111 0000 */
+#define Q931ie_CALLED_PARTY_SUBADDRESS 0x71 /* 0111 0001 */
+#define Q931ie_REDIRECTING_NUMBER 0x74 /* 0111 0100 */
+#define Q931ie_TRANSIT_NETWORK_SELECTION 0x78 /* 0111 1000 */
+#define Q931ie_RESTART_INDICATOR 0x79 /* 0111 1001 */
+#define Q931ie_LOW_LAYER_COMPATIBILITY 0x7c /* 0111 1100 */
+#define Q931ie_HIGH_LAYER_COMPATIBILITY 0x7d /* 0111 1101 */
+#define Q931ie_USER_USER 0x7e /* 0111 1110 */
+#define Q931ie_ESCAPE_FOR_EX 0x7f /* 0111 1111 */
+
+/* Variable Length Codeset 6 Information Elements */
+#define Q931ie_GENERIC_DIGITS 0x37 /* 0011 0111 */
+
+/* Variable Length Information Element to shut up BRI testing */
+#define Q931ie_CONNECTED_NUMBER 0x4c /* 0100 1101 */
+#define Q931ie_FACILITY 0x1c /* 0001 1101 */
+
+
+/*****************************************************************************
+
+ Struct: Q931ie_BearerCap
+
+ Description: Bearer Capability Information Element.
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00000100 for Bearer Capability */
+ L3UCHAR Size; /* Length of Information Element */
+
+ L3UCHAR CodStand; /* Coding Standard. */
+ /* 00 - ITU-T */
+ /* 01 - ISO/IEC */
+ /* 10 - National standard */
+ /* 11 - Network side spesific */
+
+ L3UCHAR ITC; /* Information Transfer Capability */
+ /* 00000 - Speech */
+ /* 01000 - Unrestricted digital info */
+ /* 01001 - Restricted digital info */
+ /* 10000 - 3.1 kHz audio */
+ /* 10001 - Unrestricted with tones */
+ /* 11000 - Video */
+
+ L3UCHAR TransMode; /* Transfer Mode. */
+ /* 00 - Circuit mode */
+ /* 10 - Packet mode */
+
+ L3UCHAR ITR; /* Information Transfer Rate. */
+ /* 00000 - Packed mode */
+ /* 10000 - 64 kbit/s */
+ /* 10001 - 2 x 64 kbit/s */
+ /* 10011 - 384 kbit/s */
+ /* 10101 - 1536 kbit/s */
+ /* 10111 - 1920 kbit/s */
+ /* 11000 - Multirat (64 kbit/s base) */
+
+ L3UCHAR RateMul; /* Rate Multiplier */
+
+ L3UCHAR Layer1Ident; /* Layer 1 Ident. */
+
+ L3UCHAR UIL1Prot; /* User Information Layer 1 Protocol */
+ /* 00001 : ITU-T V.110, I.460 and X.30 */
+ /* 00010 : G.711 my-law */
+ /* 00011 : G.711 A-law */
+ /* 00100 : G.721 */
+ /* 00101 : H.221 and H.242 */
+ /* 00110 : H.223 and H.245 */
+ /* 00111 : Non ITU-T Standard */
+ /* 01000 : ITU-T V.120 */
+ /* 01001 : ITU-T X.31 HDLC flag stuff. */
+
+ L3UCHAR SyncAsync; /* Sync/Async */
+ /* 0 : Syncronous data */
+ /* 1 : Asyncronous data */
+
+ L3UCHAR Negot; /* Negotiation */
+ /* 0 : In-band negotiation not possib. */
+ /* 1 : In-band negotiation possible */
+
+ L3UCHAR UserRate; /* User rate */
+ /* 00000 : I.460, V.110, X,30 */
+ /* 00001 : 0.6 kbit/s x.1 */
+ /* 00010 : 1.2 kbit/s */
+ /* 00011 : 2.4 kbit/s */
+ /* 00100 : 3.6 kbit/s */
+ /* 00101 : 4.8 kbit/s */
+ /* 00110 : 7.2 kbit/s */
+ /* 00111 : 8 kbit/s I.460 */
+ /* 01000 : 9.6 kbit/s */
+ /* 01001 : 14.4 kbit/s */
+ /* 01010 : 16 kbit/s */
+ /* 01011 : 19.2 kbit/s */
+ /* 01100 : 32 kbit/s */
+ /* 01101 : 38.4 kbit/s */
+ /* 01110 : 48 kbit/s */
+ /* 01111 : 56 kbit/s */
+ /* 10000 : 57.6 kbit/s */
+ /* 10010 : 28.8 kbit/s */
+ /* 10100 : 24 kbit/s */
+ /* 10101 : 0.1345 kbit/s */
+ /* 10110 : 0.100 kbit/s */
+ /* 10111 : 0.075/1.2 kbit/s */
+ /* 11000 : 1.2/0.075/kbit/s */
+ /* 11001 : 0.050 kbit/s */
+ /* 11010 : 0.075 kbit/s */
+ /* 11011 : 0.110 kbit/s */
+ /* 11100 : 0.150 kbit/s */
+ /* 11101 : 0.200 kbit/s */
+ /* 11110 : 0.300 kbit/s */
+ /* 11111 : 12 kbit/s */
+
+ L3UCHAR InterRate; /* Intermediate Rate */
+ /* 00 : Not used */
+ /* 01 : 8 kbit/s */
+ /* 10 : 16 kbit/s */
+ /* 11 : 32 kbit/s */
+
+ L3UCHAR NIConTx; /* Network Indepentend Clock on transmit*/
+ /* 0 : Not required to send data clc */
+ /* 1 : Send data w/NIC clc */
+
+ L3UCHAR NIConRx; /* NIC on Rx */
+ /* 0 : Cannot accept indep. clc */
+ /* 1 : data with indep. clc accepted */
+
+ L3UCHAR FlowCtlTx; /* Flow control on Tx */
+ /* 0 : Send Flow ctrl not required */
+ /* 1 : Send flow ctrl required */
+
+ L3UCHAR FlowCtlRx; /* Flow control on Rx */
+ /* 0 : cannot use receive flow ctrl */
+ /* 1 : Receive flow ctrl accepted */
+ L3UCHAR HDR; /* HDR/No HDR */
+ L3UCHAR MultiFrame; /* Multi frame support */
+ /* 0 : multiframe not supported */
+ /* 1 : multiframe supported */
+
+ L3UCHAR Mode; /* Mode of operation */
+ /* 0 : bit transparent mode of operat. */
+ /* 1 : protocol sesitive mode of op. */
+
+ L3UCHAR LLInegot; /* Logical link id negotiation (oct. 5b)*/
+ /* 0 : default LLI=256 only */
+ /* 1 : Full protocol negotiation */
+
+ L3UCHAR Assignor; /* Assignor/assignee */
+ /* 0 : Default Asignee */
+ /* 1 : Assignor only */
+
+ L3UCHAR InBandNeg; /* In-band/out-band negot. */
+ /* 0 : negot done w/ USER INFO mes */
+ /* 1 : negot done in-band w/link zero */
+
+ L3UCHAR NumStopBits; /* Number of stop bits */
+ /* 00 : Not used */
+ /* 01 : 1 bit */
+ /* 10 : 1.5 bits */
+ /* 11 : 2 bits */
+
+ L3UCHAR NumDataBits; /* Number of data bits. */
+ /* 00 : not used */
+ /* 01 : 5 bits */
+ /* 10 : 7 bits */
+ /* 11 : 8 bits */
+
+ L3UCHAR Parity; /* Parity Information */
+ /* 000 : Odd */
+ /* 010 : Even */
+ /* 011 : None */
+ /* 100 : Forced to 0 */
+ /* 101 : Forced to 1 */
+
+ L3UCHAR DuplexMode; /* Mode duplex */
+ /* 0 : Half duplex */
+ /* 1 : Full duplex */
+
+ L3UCHAR ModemType; /* Modem type, see Q.931 p 64 */
+
+ L3UCHAR Layer2Ident; /* Layer 2 Ident */
+
+ L3UCHAR UIL2Prot; /* User Information Layer 2 Protocol */
+ /* 00010 : Q.921/I.441 */
+ /* 00110 : X.25 */
+ /* 01100 : LAN logical link */
+
+ L3UCHAR Layer3Ident; /* Layer 3 ident. */
+
+ L3UCHAR UIL3Prot; /* User Information Layer 3 Protocol */
+ /* 00010 : Q.931 */
+ /* 00110 : X.25 */
+ /* 01011 : ISO/IEC TR 9577 */
+
+ L3UCHAR AL3Info1; /* additional layer 3 info 1 */
+
+ L3UCHAR AL3Info2; /* additional layer 3 info 2 */
+
+} Q931ie_BearerCap;
+
+/*****************************************************************************
+
+ Struct: Q931ie_CallID
+
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00010000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR CallId[1]; /* Call identity */
+
+} Q931ie_CallID;
+
+/*****************************************************************************
+
+ Struct: Q931ie_CallState
+
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00010100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR CodStand; /* Coding Standard */
+ L3UCHAR CallState; /* Call State Value */
+
+} Q931ie_CallState;
+
+/*****************************************************************************
+
+ Struct: Q931ie_Cause
+
+ Description: Cause IE as described in Q.850
+
+*****************************************************************************/
+typedef struct {
+
+ L3UCHAR IEId; /* 00010100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR CodStand; /* Coding Standard */
+ L3UCHAR Location; /* Location */
+ L3UCHAR Recom; /* Recommendation */
+ L3UCHAR Value; /* Cause Value */
+ L3UCHAR Diag[1]; /* Optional Diagnostics Field */
+
+} Q931ie_Cause;
+
+/*****************************************************************************
+
+ Struct: Q931ie_CalledNum
+
+*****************************************************************************/
+typedef struct {
+
+ L3UCHAR IEId; /* 01110000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR TypNum; /* Type of Number */
+ L3UCHAR NumPlanID; /* Numbering plan identification */
+ L3UCHAR Digit[1]; /* Digit (IA5) */
+
+} Q931ie_CalledNum;
+
+/*****************************************************************************
+
+ Struct: Q931ie_CalledSub
+
+ Description: Called party subaddress
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01110001 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR TypNum; /* Type of subaddress */
+ L3UCHAR OddEvenInd; /* Odd/Even indicator */
+ L3UCHAR Digit[1]; /* digits */
+
+} Q931ie_CalledSub;
+
+/*****************************************************************************
+
+ Struct: Q931ie_CallingNum
+
+ Description: Calling party number
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01101100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR TypNum; /* Type of number */
+ L3UCHAR NumPlanID; /* Numbering plan identification */
+ L3UCHAR PresInd; /* Presentation indicator */
+ L3UCHAR ScreenInd; /* Screening indicator */
+ L3UCHAR Digit[1]; /* Number digits (IA5) */
+
+} Q931ie_CallingNum;
+
+/*****************************************************************************
+
+ Struct: Q931ie_CallingSub
+
+ Description: Calling party subaddress
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01101101 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR TypNum; /* Type of subaddress */
+ L3UCHAR OddEvenInd; /* Odd/Even indicator */
+ L3UCHAR Digit[1]; /* digits */
+
+} Q931ie_CallingSub;
+
+/*****************************************************************************
+
+ Struct: Q931ie_ChanID
+
+ Description: Channel identification
+
+ Channel Identificationis one of the IE elements that differ
+ between BRI and PRI. IntType = 1 = BRI and ChanSlot is used
+ for channel number, while InfoChanSel is used for BRI.
+
+ ChanID is one of the most important IE as it is passed
+ either though SETUP or CALL PROCEEDING to select the channel
+ to be used.
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00011000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR IntIDPresent; /* Int. id. present */
+ L3UCHAR IntType; /* Interface Type */
+ /* 0 : Basic Interface (BRI) */
+ /* 1 : Other interfaces, PRI etc. */
+
+ L3UCHAR PrefExcl; /* Pref./Excl. */
+ /* 0 : Indicated channel is preffered */
+ /* 1 : Exclusive, no other accepted */
+
+ L3UCHAR DChanInd; /* D-channel ind. */
+ /* 0 : chan is NOT D chan. */
+ /* 1 : chan is D chan */
+
+ L3UCHAR InfoChanSel; /* Info. channel selection */
+ /* 00 : No channel */
+ /* 01 : B1 channel */
+ /* 10 : B2 channel */
+ /* 11 : Any channel */
+
+ L3UCHAR InterfaceID; /* Interface identifier */
+
+ L3UCHAR CodStand; /* Code standard */
+ /* 00 : ITU-T standardization coding */
+ /* 01 : ISO/IEC Standard */
+ /* 10 : National Standard */
+ /* 11 : Standard def. by network. */
+
+ L3UCHAR NumMap; /* Number/Map */
+ /* 0 : chan is in following octet */
+ /* 1 : chan is indicated by slot map */
+
+ L3UCHAR ChanMapType; /* Channel type/Map element type */
+ /* 0011 : B Channel units */
+ /* 0110 : H0 channel units */
+ /* 1000 : H11 channel units */
+ /* 1001 : H12 channel units */
+
+ L3UCHAR ChanSlot; /* Channel number */
+
+} Q931ie_ChanID;
+
+/*****************************************************************************
+
+ Struct: Q931ie_DateTime
+
+ Description: Date/time
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00101001 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR Year; /* Year */
+ L3UCHAR Month; /* Month */
+ L3UCHAR Day; /* Day */
+ L3UCHAR Hour; /* Hour */
+ L3UCHAR Minute; /* Minute */
+ L3UCHAR Second; /* Second */
+ L3UCHAR Format; /* Indicate presense of Hour, Min & sec */
+ /* 0 : Only Date */
+ /* 1 : Hour present */
+ /* 2 : Hour and Minute present */
+ /* 3 : Hour, Minute and Second present */
+} Q931ie_DateTime;
+
+/*****************************************************************************
+
+ Struct: Q931ie_Display
+
+ Description: Display
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00101000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR Display[1]; /* Display information (IA5) */
+
+} Q931ie_Display;
+
+/*****************************************************************************
+
+ Struct: Q931ie_HLComp
+
+ Description: High layer compatibility
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01111101 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR CodStand; /* Coding standard */
+ L3UCHAR Interpret; /* Interpretation */
+ L3UCHAR PresMeth; /* Presentation methor of prot. profile */
+ L3UCHAR HLCharID; /* High layer characteristics id. */
+ L3UCHAR EHLCharID; /* Extended high layer character. id. */
+ L3UCHAR EVideoTlfCharID; /* Ext. videotelephony char. id. */
+
+} Q931ie_HLComp;
+
+/*****************************************************************************
+
+ Struct: Q931ie_KeypadFac
+
+ Description: Keypad facility
+
+*****************************************************************************/
+
+typedef struct {
+ L3UCHAR IEId; /* 00101100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR KeypadFac[1]; /* dynamic buffer */
+
+} Q931ie_KeypadFac;
+
+/*****************************************************************************
+
+ Struct: Q931ie_LLComp
+
+ Description: Low layer compatibility
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01111100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR CodStand; /* Coding standard */
+ /* 00 - ITU-T */
+ /* 01 - ISO/IEC */
+ /* 10 - National standard */
+ /* 11 - Network side spesific */
+
+ L3UCHAR ITransCap; /* Information transfer capability */
+ /* 00000 - Speech */
+ /* 01000 - Unrestricted digital info */
+ /* 01001 - Restricted digital info */
+ /* 10000 - 3.1 kHz audio */
+ /* 10001 - Unrestricted with tones */
+ /* 11000 - Video */
+
+ L3UCHAR NegotInd; /* Negot indic. */
+ /* 0 : Out-band neg. not possib. */
+ /* 1 : Out-band neg. possible */
+
+ L3UCHAR TransMode; /* Transfer Mode */
+ /* 00 : Circuit Mode */
+ /* 10 : Packed Mode */
+
+ L3UCHAR InfoRate; /* Information transfer rate */
+ /* 00000 - Packed mode */
+ /* 10000 - 64 kbit/s */
+ /* 10001 - 2 x 64 kbit/s */
+ /* 10011 - 384 kbit/s */
+ /* 10101 - 1536 kbit/s */
+ /* 10111 - 1920 kbit/s */
+ /* 11000 - Multirat (64 kbit/s base) */
+
+ L3UCHAR RateMul; /* Rate multiplier */
+ L3UCHAR Layer1Ident; /* Layer 1 ident. */
+ L3UCHAR UIL1Prot; /* User information layer 1 protocol */
+ /* 00001 : ITU-T V.110, I.460 and X.30 */
+ /* 00010 : G.711 my-law */
+ /* 00011 : G.711 A-law */
+ /* 00100 : G.721 */
+ /* 00101 : H.221 and H.242 */
+ /* 00110 : H.223 and H.245 */
+ /* 00111 : Non ITU-T Standard */
+ /* 01000 : ITU-T V.120 */
+ /* 01001 : ITU-T X.31 HDLC flag stuff. */
+
+ L3UCHAR SyncAsync; /* Synch/asynch */
+ /* 0 : Syncronous data */
+ /* 1 : Asyncronous data */
+
+ L3UCHAR Negot; /* Negot */
+ /* 0 : In-band negotiation not possib. */
+ /* 1 : In-band negotiation possible */
+
+ L3UCHAR UserRate; /* User rate */
+ /* 00000 : I.460, V.110, X,30 */
+ /* 00001 : 0.6 kbit/s x.1 */
+ /* 00010 : 1.2 kbit/s */
+ /* 00011 : 2.4 kbit/s */
+ /* 00100 : 3.6 kbit/s */
+ /* 00101 : 4.8 kbit/s */
+ /* 00110 : 7.2 kbit/s */
+ /* 00111 : 8 kbit/s I.460 */
+ /* 01000 : 9.6 kbit/s */
+ /* 01001 : 14.4 kbit/s */
+ /* 01010 : 16 kbit/s */
+ /* 01011 : 19.2 kbit/s */
+ /* 01100 : 32 kbit/s */
+ /* 01101 : 38.4 kbit/s */
+ /* 01110 : 48 kbit/s */
+ /* 01111 : 56 kbit/s */
+ /* 10000 : 57.6 kbit/s */
+ /* 10010 : 28.8 kbit/s */
+ /* 10100 : 24 kbit/s */
+ /* 10101 : 0.1345 kbit/s */
+ /* 10110 : 0.100 kbit/s */
+ /* 10111 : 0.075/1.2 kbit/s */
+ /* 11000 : 1.2/0.075/kbit/s */
+ /* 11001 : 0.050 kbit/s */
+ /* 11010 : 0.075 kbit/s */
+ /* 11011 : 0.110 kbit/s */
+ /* 11100 : 0.150 kbit/s */
+ /* 11101 : 0.200 kbit/s */
+ /* 11110 : 0.300 kbit/s */
+ /* 11111 : 12 kbit/s */
+
+ L3UCHAR InterRate; /* Intermediate rate */
+ /* 00 : Not used */
+ /* 01 : 8 kbit/s */
+ /* 10 : 16 kbit/s */
+ /* 11 : 32 kbit/s */
+
+ L3UCHAR NIConTx; /* Network Indepentend Clock on transmit*/
+ /* 0 : Not required to send data clc */
+ /* 1 : Send data w/NIC clc */
+
+ L3UCHAR NIConRx; /* NIC on Rx */
+ /* 0 : Cannot accept indep. clc */
+ /* 1 : data with indep. clc accepted */
+
+ L3UCHAR FlowCtlTx; /* Flow control on Tx */
+ /* 0 : Send Flow ctrl not required */
+ /* 1 : Send flow ctrl required */
+
+ L3UCHAR FlowCtlRx; /* Flow control on Rx */
+ /* 0 : cannot use receive flow ctrl */
+ /* 1 : Receive flow ctrl accepted */
+ L3UCHAR HDR; /* HDR/No HDR */
+ L3UCHAR MultiFrame; /* Multi frame support */
+ /* 0 : multiframe not supported */
+ /* 1 : multiframe supported */
+
+ L3UCHAR ModeL1; /* Mode L1 */
+ /* 0 : bit transparent mode of operat. */
+ /* 1 : protocol sesitive mode of op. */
+
+ L3UCHAR NegotLLI; /* Negot. LLI */
+ /* 0 : default LLI=256 only */
+ /* 1 : Full protocol negotiation */
+
+ L3UCHAR Assignor; /* Assignor/Assignor ee */
+ /* 0 : Default Asignee */
+ /* 1 : Assignor only */
+
+ L3UCHAR InBandNeg; /* In-band negot. */
+ /* 0 : negot done w/ USER INFO mes */
+ /* 1 : negot done in-band w/link zero */
+
+ L3UCHAR NumStopBits; /* Number of stop bits */
+ /* 00 : Not used */
+ /* 01 : 1 bit */
+ /* 10 : 1.5 bits */
+ /* 11 : 2 bits */
+
+ L3UCHAR NumDataBits; /* Number of data bits. */
+ /* 00 : not used */
+ /* 01 : 5 bits */
+ /* 10 : 7 bits */
+ /* 11 : 8 bits */
+
+ L3UCHAR Parity; /* Parity Information */
+ /* 000 : Odd */
+ /* 010 : Even */
+ /* 011 : None */
+ /* 100 : Forced to 0 */
+ /* 101 : Forced to 1 */
+
+ L3UCHAR DuplexMode; /* Mode duplex */
+ /* 0 : Half duplex */
+ /* 1 : Full duplex */
+
+ L3UCHAR ModemType; /* Modem type, see Q.931 p 89 */
+
+ L3UCHAR Layer2Ident; /* Layer 2 ident. */
+
+ L3UCHAR UIL2Prot; /* User information layer 2 protocol */
+ /* 00001 : Basic mode ISO 1745 */
+ /* 00010 : Q.921/I.441 */
+ /* 00110 : X.25 single link */
+ /* 00111 : X.25 multilink */
+ /* 01000 : Extended LAPB T.71 */
+ /* 01001 : HDLC ARM */
+ /* 01010 : HDLC NRM */
+ /* 01011 : HDLC ABM */
+ /* 01100 : LAN logical link */
+ /* 01101 : X.75 SLP */
+ /* 01110 : Q.922 */
+ /* 01111 : Q.922 core aspect */
+ /* 10000 : User specified */
+ /* 10001 : ISO/IEC 7776 DTE-DCE */
+
+ L3UCHAR ModeL2; /* Mode */
+ /* 01 : Normal Mode of operation */
+ /* 10 : Extended mode of operation */
+
+ L3UCHAR Q933use; /* Q.9333 use */
+
+ L3UCHAR UsrSpcL2Prot; /* User specified layer 2 protocol info */
+
+ L3UCHAR WindowSize; /* Window size (k) */
+
+ L3UCHAR Layer3Ident; /* Layer 3 ident */
+
+ L3UCHAR UIL3Prot; /* User Information Layer 3 protocol */
+ /* 00010 : Q.931 */
+ /* 00110 : X.25 */
+ /* 00111 : 8208 */
+ /* 01000 : X.233 ... */
+ /* 01001 : 6473 */
+ /* 01010 : T.70 */
+ /* 01011 : ISO/IEC TR 9577 */
+ /* 10000 : User specified */
+ L3UCHAR OptL3Info; /* Optional Leyer 3 info */
+
+ L3UCHAR ModeL3; /* Mode of operation */
+ /* 01 : Normal packed seq. numbering */
+ /* 10 : Extended packed seq. numbering */
+
+ L3UCHAR DefPackSize; /* Default packet size */
+
+ L3UCHAR PackWinSize; /* Packet window size */
+
+ L3UCHAR AddL3Info; /* Additional Layer 3 protocol info */
+
+} Q931ie_LLComp;
+
+/*****************************************************************************
+
+ Struct: Q931ie_NetFac;
+
+ Description: Network-specific facilities
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00100000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR LenNetID; /* Length of network facilities id. */
+ L3UCHAR TypeNetID; /* Type of network identification */
+ L3UCHAR NetIDPlan; /* Network identification plan. */
+ L3UCHAR NetFac; /* Network specific facility spec. */
+ L3UCHAR NetID[1]; /* Network id. (IA5) */
+
+} Q931ie_NetFac;
+
+/*****************************************************************************
+
+ Struct: Q931ie_NotifInd;
+
+ Description: Notification Indicator
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00100000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR Notification; /* Notification descriptor */
+
+} Q931ie_NotifInd;
+
+/*****************************************************************************
+
+ Struct: Q931ie_ProgInd
+
+ Description: Progress indicator
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00011110 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR CodStand; /* Coding standard */
+ L3UCHAR Location; /* Location */
+ L3UCHAR ProgDesc; /* Progress description */
+
+} Q931ie_ProgInd;
+
+/*****************************************************************************
+
+ Struct; Q931ie_Segment
+
+ Description: Segmented message
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00000000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR FSI; /* First segment indicator */
+ L3UCHAR NumSegRem; /* Number of segments remaining */
+ L3UCHAR SegType; /* Segment message type */
+
+} Q931ie_Segment;
+
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00000000 */
+ L3UCHAR Size; /* Length of Information Element */
+
+} Q931ie_SendComplete;
+
+/*****************************************************************************
+
+ Struct: Q931ie_Signal
+
+ Description: Signal
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00000000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR Signal; /* Signal value */
+ /* 00000000 Dial tone on */
+ /* 00000001 Ring back tone on */
+ /* 00000010 Intercept tone on */
+ /* 00000011 Network congestion on */
+ /* 00000100 Busy tone on */
+ /* 00000101 Confirm tone on */
+ /* 00000110 Answer tone on */
+ /* 00000111 Call waiting tone */
+ /* 00001000 Off-hook warning tone */
+ /* 00001001 Pre-emption tone on */
+ /* 00111111 Tones off */
+ /* 01000000 Alerting on - pattern 0 */
+ /* 01000001 Alerting on - pattern 1 */
+ /* 01000010 Alerting on - pattern 2 */
+ /* 01000011 Alerting on - pattern 3 */
+ /* 01000100 Alerting on - pattern 4 */
+ /* 01000101 Alerting on - pattern 5 */
+ /* 01000110 Alerting on - pattern 6 */
+ /* 01000111 Alerting on - pattern 7 */
+ /* 01001111 Alerting off */
+} Q931ie_Signal;
+
+/*****************************************************************************
+
+ Struct: Q931ie_TransDelSelInd
+
+ description: Transit delay selection and indication
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+ L3UCHAR IEId; /* 00000000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3ULONG TxDSIValue; /* Trans. delay sel. & ind. value */
+
+} Q931ie_TransDelSelInd;
+#endif
+
+/*****************************************************************************
+
+ Struct: Q931ie_TransNetSel
+
+ Description: Transit network selection
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01111000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR Type; /* Type of network identifier */
+ L3UCHAR NetIDPlan; /* Network idetification plan */
+ L3UCHAR NetID[1]; /* Network identification(IA5) */
+
+} Q931ie_TransNetSel;
+
+/*****************************************************************************
+
+ Struct: Q931ie_UserUser
+
+ Description: User-user
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01111110 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR ProtDisc; /* Protocol discriminator */
+ L3UCHAR User[1]; /* User information */
+
+} Q931ie_UserUser;
+
+/*****************************************************************************
+
+ Struct: Q931ie_ClosedUserGrp
+
+ Description: Closed user group
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+ L3UCHAR IEId; /* 01000111 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR CUGInd; /* CUG indication */
+ L3UCHAR CUG[1]; /* CUG index code (IA5) */
+
+} Q931ie_ClosedUserGrp;
+#endif
+
+/*****************************************************************************
+
+ Struct: Q931ie_CongLevel
+
+ Description: Congestion Level
+
+*****************************************************************************/
+typedef struct {
+
+ L3UCHAR IEId; /* 01000111 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR CongLevel; /* Conguestion Level */
+
+} Q931ie_CongLevel;
+
+/*****************************************************************************
+
+ Struct: Q931ie_EndEndTxDelay
+
+ Description: End to end transit delay
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+ L3UCHAR IEId; /* 01000010 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3ULONG CumTxDelay; /* Cumulative transit delay value */
+ L3ULONG ReqTxDelay; /* Requested end to end transit delay */
+ L3ULONG MaxTxDelay; /* Maximum transit delay */
+
+} Q931ie_EndEndTxDelay;
+#endif
+
+/*****************************************************************************
+
+ Struct: Q931ie_InfoRate
+
+ Description: Information Rate
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+ L3UCHAR IEId; /* 01100000 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR InInfoRate; /* Incoming information rate */
+ L3UCHAR OutInfoRate; /* Outgoing information rate */
+ L3UCHAR MinInInfoRate; /* Minimum incoming information rate */
+ L3UCHAR MinOutInfoRate; /* Minimum outgoing information rate */
+
+} Q931ie_InfoRate;
+#endif
+
+/*****************************************************************************
+
+ Struct: Q931ie_PackParam
+
+ Description: Packed layer binary parameters
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+ L3UCHAR IEId; /* 01000100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR FastSel; /* Fast selected */
+ L3UCHAR ExpData; /* Exp. data */
+ L3UCHAR DelConf; /* Delivery conf */
+ L3UCHAR Modulus; /* Modulus */
+
+} Q931ie_PackParam;
+#endif
+
+/*****************************************************************************
+
+ Struct: Q931ie_PackWinSize
+
+ Description: Packed window size
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+ L3UCHAR IEId; /* 01000101 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR ForwardValue; /* Forward value */
+ L3UCHAR BackwardValue; /* Backward value */
+
+} Q931ie_PackWinSize;
+#endif
+
+/*****************************************************************************
+
+ Struct: Q931ie_PackSize
+
+ Description: Packet size
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+ L3UCHAR IEId; /* 01000110 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR ForwardValue; /* Forward value */
+ L3UCHAR BackwardValue; /* Backward value */
+
+} Q931ie_PackSize;
+#endif
+
+/*****************************************************************************
+
+ Struct: Q931ie_RedirNum
+
+ Description: Redirecting number
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+ L3UCHAR IEId; /* 01110100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR TypeNum; /* Type of number */
+ L3UCHAR NumPlanID; /* Number plan identification */
+ L3UCHAR PresInd; /* Presentation indicator */
+ L3UCHAR ScreenInd; /* Screening indicator */
+ L3UCHAR Reason; /* Reason for redirection */
+ L3UCHAR Digit[1]; /* Number digits (IA5) */
+
+} Q931ie_RedirNum;
+#endif
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01110100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR RepeatInd; /* 0010 Prioritized list for selecting */
+ /* one possible. */
+} Q931ie_RepeatInd;
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01110100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR Spare; /* Spare */
+ L3UCHAR Class; /* Class */
+ /* 000 Indicate channels */
+ /* 110 Single interface */
+ /* 111 All interfaces */
+} Q931ie_RestartInd;
+
+typedef struct {
+
+ L3UCHAR IEId; /* 01110100 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR Preference; /* Preference 0 = reserved, 1 = channel */
+ L3UCHAR Spare; /* Spare */
+ L3UCHAR NewStatus; /* NewStatus */
+ /* 000 In service */
+ /* 001 Maintenance */
+ /* 010 Out of service */
+} Q931ie_ChangeStatus;
+
+/*****************************************************************************
+
+ Struct: Q931ie_GenericDigits
+
+
+*****************************************************************************/
+
+typedef struct {
+
+ L3UCHAR IEId; /* 00110111 */
+ L3UCHAR Size; /* Length of Information Element */
+ L3UCHAR Type; /* Type of number */
+ L3UCHAR Encoding; /* Encoding of number */
+ L3UCHAR Digit[1]; /* Number digits (IA5) */
+
+} Q931ie_GenericDigits;
+
+
+/*****************************************************************************
+
+ Q.931 Information Element Pack/Unpack functions. Implemented in Q931ie.c
+
+*****************************************************************************/
+q931pie_func_t Q931Pie_ChangeStatus;
+q931pie_func_t Q931Pie_BearerCap;
+q931pie_func_t Q931Pie_ChanID;
+q931pie_func_t Q931Pie_ProgInd;
+q931pie_func_t Q931Pie_Display;
+q931pie_func_t Q931Pie_Signal;
+q931pie_func_t Q931Pie_HLComp;
+q931pie_func_t Q931Pie_Segment;
+q931pie_func_t Q931Pie_DateTime;
+q931pie_func_t Q931Pie_Cause;
+q931pie_func_t Q931Pie_SendComplete;
+q931pie_func_t Q931Pie_KeypadFac;
+q931pie_func_t Q931Pie_NotifInd;
+q931pie_func_t Q931Pie_CallID;
+q931pie_func_t Q931Pie_RepeatInd;
+q931pie_func_t Q931Pie_NetFac;
+q931pie_func_t Q931Pie_CallingNum;
+q931pie_func_t Q931Pie_CallingSub;
+q931pie_func_t Q931Pie_CalledNum;
+q931pie_func_t Q931Pie_CalledSub;
+q931pie_func_t Q931Pie_CalledNum;
+q931pie_func_t Q931Pie_TransNetSel;
+q931pie_func_t Q931Pie_LLComp;
+q931pie_func_t Q931Pie_CallState;
+q931pie_func_t Q931Pie_RestartInd;
+q931pie_func_t Q931Pie_UserUser;
+
+q931pie_func_t Q931Pie_GenericDigits;
+
+L3USHORT Q931Uie_CRV(Q931_TrunkInfo_t *pTrunk,L3UCHAR * IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff);
+
+q931uie_func_t Q931Uie_ChangeStatus;
+q931uie_func_t Q931Uie_BearerCap;
+q931uie_func_t Q931Uie_ChanID;
+q931uie_func_t Q931Uie_ProgInd;
+q931uie_func_t Q931Uie_Display;
+q931uie_func_t Q931Uie_Signal;
+q931uie_func_t Q931Uie_HLComp;
+q931uie_func_t Q931Uie_Segment;
+q931uie_func_t Q931Uie_DateTime;
+q931uie_func_t Q931Uie_Cause;
+q931uie_func_t Q931Uie_SendComplete;
+q931uie_func_t Q931Uie_KeypadFac;
+q931uie_func_t Q931Uie_NotifInd;
+q931uie_func_t Q931Uie_CallID;
+q931uie_func_t Q931Uie_RepeatInd;
+q931uie_func_t Q931Uie_NetFac;
+q931uie_func_t Q931Uie_CallingNum;
+q931uie_func_t Q931Uie_CallingSub;
+q931uie_func_t Q931Uie_CalledNum;
+q931uie_func_t Q931Uie_CalledSub;
+q931uie_func_t Q931Uie_TransNetSel;
+q931uie_func_t Q931Uie_LLComp;
+q931uie_func_t Q931Uie_CallState;
+q931uie_func_t Q931Uie_RestartInd;
+q931uie_func_t Q931Uie_UserUser;
+
+q931uie_func_t Q931Uie_GenericDigits;
+
+
+L3INT Q931ReadExt(L3UCHAR * IBuf, L3INT Off);
+L3INT Q931Uie_CongLevel(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff);
+L3INT Q931Pie_CongLevel(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+L3INT Q931Uie_RevChargeInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff);
+L3INT Q931Pie_RevChargeInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+
+L3INT Q931Uie_Generic(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff);
+L3INT Q931Pie_Generic(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+
+#endif /* _Q931IE_NL */
Added: freeswitch/trunk/libs/openzap/src/isdn/include/Q932.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/include/Q932.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/include/Q932.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,95 @@
+/*****************************************************************************
+
+ FileName: Q932.h
+
+ Contents: Header w/structs for Q932 Suplementary Services.
+
+ NB: Do NOT include this header directly, include Q931.h
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+/*****************************************************************************
+ Q.932 Additional Message codes
+*****************************************************************************/
+
+#define Q932mes_HOLD 0x24 /* 0010 0100 */
+#define Q932mes_HOLD_ACKNOWLEDGE 0x28 /* 0010 1000 */
+#define Q932mes_HOLD_REJECT 0x30 /* 0011 0000 */
+#define Q932mes_RETRIEVE 0x31 /* 0011 0001 */
+#define Q932mes_RETRIEVE_ACKNOWLEDGE 0x33 /* 0011 0011 */
+#define Q932mes_RETRIEVE_REJECT 0x37 /* 0011 0111 */
+#define Q932mes_FACILITY 0x62 /* 0110 0010 */
+#define Q932mes_REGISTER 0x64 /* 0110 0100 */
+
+/*****************************************************************************
+ Q.932 Additional EI Codes
+*****************************************************************************/
+#define Q932ie_FACILITY 0x1c /* 0001 1100 */
+
+/*****************************************************************************
+ Function Prototypes.
+*****************************************************************************/
+L3INT Q932ProcFacilityTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRegisterTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+
+L3INT Q932ProcFacilityNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRegisterNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+
+L3INT Q932Pmes_Facility(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_Hold(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_HoldAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_HoldReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_Register(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_Retrieve(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_RetrieveAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_RetrieveReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+L3INT Q932Umes_Facility(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_Hold(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_HoldAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_HoldReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_Register(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_Retrieve(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_RetrieveAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_RetrieveReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
Added: freeswitch/trunk/libs/openzap/src/isdn/include/mfifo.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/include/mfifo.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/include/mfifo.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,85 @@
+/*****************************************************************************
+
+ Filename: mfifo.h
+
+ Contents: header for MFIFO
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+#ifndef _MFIFO
+#define _MFIFO
+
+/*****************************************************************************
+
+ Struct: MINDEX
+
+ Description: Message Index used to index a dynamic size Message FIFO.
+
+*****************************************************************************/
+typedef struct _mindex {
+ int offset; /* offset to message in buf */
+ int size; /* size of message in bytes */
+} MINDEX;
+
+/*****************************************************************************
+
+ Struct: MFIFO
+
+ Description: Message FIFO. Provides a dynamic sized message based FIFO
+ queue.
+
+*****************************************************************************/
+typedef struct {
+ int first; /* first out */
+ int last; /* last in + 1 */
+ int bsize; /* buffer size */
+ unsigned char *buf; /* ptr to start of buffer */
+ int ixsize; /* index size */
+ MINDEX ix[1]; /* message index */
+} MFIFO;
+
+/*****************************************************************************
+ Function prototypes.
+*****************************************************************************/
+int MFIFOCreate(unsigned char *buf, int size, int index);
+void MFIFOClear(unsigned char * buf);
+int MFIFOGetLBOffset(unsigned char *buf);
+int MFIFOGetFBOffset(unsigned char *buf);
+void MFIFOWriteIX(unsigned char *buf, unsigned char *mes, int size, int ix, int off);
+int MFIFOWriteMes(unsigned char *buf, unsigned char *mes, int size);
+unsigned char * MFIFOGetMesPtr(unsigned char *buf, int *size);
+void MFIFOKillNext(unsigned char *buf);
+
+unsigned char * MFIFOGetMesPtrOffset(unsigned char *buf, int *size, const int pos);
+int MFIFOGetMesCount(unsigned char *buf);
+int MFIFOWriteMesOverwrite(unsigned char *buf, unsigned char *mes, int size);
+
+#endif
Added: freeswitch/trunk/libs/openzap/src/isdn/include/national.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/include/national.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/include/national.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,86 @@
+/******************************************************************************
+
+ FileName: national.h
+
+ Contents: Header and definition for the National ISDN dialect. The
+ header contents the following parts:
+ - Definition of codes
+ - Definition of information elements (nationalie_).
+ - Definition of messages (nationalmes_).
+ - Function prototypes.
+
+ Description: The National ISDN dialect here covers ????
+
+ Related Files: national.h National ISDN Definitions
+ nationalie.c National ISDN IE encoders/coders
+ nationalStateTE.c National ISDN TE State Engine
+ nationalStateNT.c National ISDN NT State Engine
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ 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 Case Labs, Ltd 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.
+******************************************************************************/
+
+#ifndef _national_NATIONAL_NL
+#define _national_NATIONAL_NL
+
+#include "Q931.h"
+
+/*****************************************************************************
+
+ Q.931 Message codes
+ Only National specific message and ie types
+ here the rest are inherited from national.h
+
+*****************************************************************************/
+
+
+/*****************************************************************************
+
+ Q.931 Message Pack/Unpack functions. Implemented in nationalmes.c
+
+*****************************************************************************/
+L3INT nationalUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT nationalPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+#include "DMS.h"
+
+/*****************************************************************************
+
+ Q.931 Process Function Prototyping. Implemented in nationalStateTE.c
+
+*****************************************************************************/
+
+void nationalCreateTE(L3UCHAR i);
+void nationalCreateNT(L3UCHAR i);
+
+#endif /* _national_NATIONAL_NL */
Added: freeswitch/trunk/libs/openzap/src/isdn/mfifo.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/mfifo.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/mfifo.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,399 @@
+/*****************************************************************************
+
+ Filename: mfifo.c
+
+ Description: mfifo is a message orriented fifo system with support of
+ both message and byte per byte retriaval of messages.
+
+ The fifo has been designed with two usages in mind:
+
+ - Queueing of frames for hdlc and feeding out byte per byte
+ with the possibility of re-sending of frames etc.
+
+ - fifo for messages of dynamic size.
+
+ The fifo is allocated on top of any buffer and creates an
+ index of message in the queue. The user can write/read
+ messages or write messages and read the message one byte
+ at the time.
+
+ Interface:
+ MFIFOCreate Create/reset/initialize fifo.
+ MFIFOClear Clear FIFO.
+ MFIFOWriteMes Write message into fifo
+ * MFIFOReadMes Read message from fifo.
+ MFIFOGetMesPtr Get ptr to next message.
+ MFIFOKillNext Kill next message.
+
+ * currently not implemented.
+
+ Note: The message will always be saved continuously. If there is not
+ sufficient space at the end of the buffer, the fifo will skip
+ the last bytes and save the message at the top of the buffer.
+
+ This is required to allow direct ptr access to messages
+ stored in the queue.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "mfifo.h"
+#include <memory.h>
+#include <stdlib.h>
+
+/*****************************************************************************
+
+ Function: MFIFOCreate
+
+ Description: Creates a fifo on top of an existing buffer.
+
+ Parameters: buf ptr to buffer.
+ size size of buffer in bytes.
+ index size of index entries (max no messages).
+
+ Return value: 0 if failure, 1 if ok.
+
+*****************************************************************************/
+int MFIFOCreate(unsigned char *buf, int size, int index)
+{
+ MFIFO *mf = (MFIFO *)buf;
+
+ mf->first = mf->last = 0;
+ mf->ixsize = index;
+ mf->buf = &buf[sizeof(MFIFO) + (sizeof(MINDEX) * index)];
+
+ if (mf->buf > &buf[size])
+ return 0;
+
+ mf->bsize = size - sizeof(MFIFO) - (sizeof(MINDEX) * index);
+
+ return 1;
+}
+
+/*****************************************************************************
+
+ Function: MFIFOClear
+
+ Description: Clear the FIFO
+
+ Paremeters: buf ptr to fifo
+
+ Return Value: none
+
+*****************************************************************************/
+void MFIFOClear(unsigned char * buf)
+{
+ MFIFO *mf = (MFIFO *)buf;
+
+ mf->first = mf->last = 0;
+}
+
+/*****************************************************************************
+
+ Function: MFIFOGetLBOffset
+
+ Description: Helper function caclulating offset to the 'first out' byte.
+
+ Paremeters: buf ptr to fifo
+
+ Return Value: offset.
+
+*****************************************************************************/
+int MFIFOGetLBOffset(unsigned char *buf)
+{
+ MFIFO *mf = (MFIFO *)buf;
+
+ if (mf->last != mf->first)
+ return mf->ix[mf->last].offset;
+
+ return 0;
+}
+
+/*****************************************************************************
+
+ Function: MFIFOGetFBOffset
+
+ Description: Helper function calculating the offset to the 'first in'
+ byte in the buffer. This is the position the next byte
+ entering the fifo will occupy.
+
+ Paremeters: buf ptr to fifo
+
+ Return Value: offset
+
+*****************************************************************************/
+int MFIFOGetFBOffset(unsigned char *buf)
+{
+ MFIFO *mf = (MFIFO *)buf;
+ int x;
+
+ if (mf->last == mf->first)
+ return 0;
+
+ x = mf->first - 1;
+
+ if (x < 0)
+ x = mf->ixsize - 1;
+
+ return mf->ix[x].offset + mf->ix[x].size;
+}
+
+/*****************************************************************************
+
+ Function: MFIFOWriteIX
+
+ Description: Helper function writing a calculated entry. The function
+ will perform a memcpy to move the message and set the index
+ values as well as increase the 'first in' index.
+
+ Paremeters: buf ptr to fifo
+ mes ptr to message
+ size size of message in bytes.
+ ix index to index entry.
+ off offset to position to receive the message
+
+ Return Value: none
+
+*****************************************************************************/
+void MFIFOWriteIX(unsigned char *buf, unsigned char *mes, int size, int ix, int off)
+{
+ MFIFO *mf = (MFIFO *)buf;
+ int x;
+
+ memcpy(&mf->buf[off], mes, size);
+ mf->ix[ix].offset = off;
+ mf->ix[ix].size = size;
+
+ x = mf->first + 1;
+
+ if (x >= mf->ixsize)
+ x = 0;
+
+ mf->first = x;
+}
+
+/*****************************************************************************
+
+ Function: MFIFOWriteMes
+
+ Description:
+
+ Paremeters:
+
+ Return Value:
+
+*****************************************************************************/
+int MFIFOWriteMes(unsigned char *buf, unsigned char *mes, int size)
+{
+ MFIFO *mf = (MFIFO *)buf;
+ int of, ol, x;
+
+ x = mf->first + 1;
+
+ if (x >= mf->ixsize)
+ x = 0;
+
+ if (x == mf->last)
+ return 0; /* full queue */
+
+ of = MFIFOGetFBOffset(buf);
+ ol = MFIFOGetLBOffset(buf);
+ if (mf->last == mf->first) { /* empty queue */
+ mf->first = mf->last = 0; /* optimize */
+
+ MFIFOWriteIX(buf, mes, size, mf->first, 0);
+ return 1;
+ }
+ else if (of > ol) {
+ if (mf->bsize - of >= size) {
+ MFIFOWriteIX(buf, mes, size, mf->first, of);
+ return 1;
+ }
+ else if (ol > size) {
+ MFIFOWriteIX(buf, mes, size, mf->first, ol);
+ return 1;
+ }
+ }
+ else if (ol - of > size) {
+ MFIFOWriteIX(buf, mes, size, mf->first, of);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+
+ Function: MFIFOGetMesPtr
+
+ Description:
+
+ Paremeters:
+
+ Return Value:
+
+*****************************************************************************/
+unsigned char * MFIFOGetMesPtr(unsigned char *buf, int *size)
+{
+ MFIFO *mf = (MFIFO *)buf;
+
+ if (mf->first == mf->last) {
+ return NULL;
+ }
+
+ *size = mf->ix[mf->last].size;
+ return &mf->buf[mf->ix[mf->last].offset];
+}
+
+/*****************************************************************************
+
+ Function: MFIFOKillNext
+
+ Description:
+
+ Paremeters:
+
+ Return Value:
+
+*****************************************************************************/
+void MFIFOKillNext(unsigned char *buf)
+{
+ MFIFO *mf = (MFIFO *)buf;
+ int x;
+
+ if (mf->first != mf->last) {
+ x = mf->last + 1;
+ if (x >= mf->ixsize) {
+ x = 0;
+ }
+
+ mf->last = x;
+ }
+}
+
+
+/*
+ * Queue-style accessor functions
+ */
+
+/**
+ * MFIFOGetMesPtrOffset
+ * \brief Get pointer to and size of message at position x
+ */
+unsigned char * MFIFOGetMesPtrOffset(unsigned char *buf, int *size, const int pos)
+{
+ MFIFO *mf = (MFIFO *)buf;
+ int x;
+
+ if (mf->first == mf->last) {
+ return NULL;
+ }
+
+ if (pos < 0 || pos >= mf->ixsize) {
+ return NULL;
+ }
+
+ x = pos - mf->last;
+ if (x < 0) {
+ x += (mf->ixsize - 1);
+ }
+
+ *size = mf->ix[x].size;
+ return &mf->buf[mf->ix[x].offset];
+}
+
+
+/**
+ * MFIFOGetMesCount
+ * \brief How many messages are currently in the buffer?
+ */
+int MFIFOGetMesCount(unsigned char *buf)
+{
+ MFIFO *mf = (MFIFO *)buf;
+
+ if (mf->first == mf->last) {
+ return 0;
+ }
+ else if (mf->first > mf->last) {
+ return mf->first - mf->last;
+ }
+ else {
+ return (mf->ixsize - mf->last) + mf->first;
+ }
+}
+
+/**
+ * MFIFOWriteMesOverwrite
+ * \brief Same as MFIFOWriteMes but old frames will be overwritten if the fifo is full
+ */
+int MFIFOWriteMesOverwrite(unsigned char *buf, unsigned char *mes, int size)
+{
+ MFIFO *mf = (MFIFO *)buf;
+ int of, ol, x;
+
+ x = mf->first + 1;
+
+ if (x >= mf->ixsize)
+ x = 0;
+
+ if (x == mf->last) {
+ /* advance last pointer */
+ mf->last++;
+
+ if (mf->last >= mf->ixsize)
+ mf->last = 0;
+ }
+
+ of = MFIFOGetFBOffset(buf);
+ ol = MFIFOGetLBOffset(buf);
+
+ if (mf->last == mf->first) { /* empty queue */
+ mf->first = mf->last = 0; /* optimize */
+
+ MFIFOWriteIX(buf, mes, size, mf->first, 0);
+ return 1;
+ }
+ else if (of > ol) {
+ if (mf->bsize - of >= size) {
+ MFIFOWriteIX(buf, mes, size, mf->first, of);
+ return 1;
+ }
+ else if (ol > size) {
+ MFIFOWriteIX(buf, mes, size, mf->first, ol);
+ return 1;
+ }
+ }
+ else if (ol - of > size) {
+ MFIFOWriteIX(buf, mes, size, mf->first, of);
+ return 1;
+ }
+ return 0;
+}
Added: freeswitch/trunk/libs/openzap/src/isdn/nationalStateNT.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/nationalStateNT.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/nationalStateNT.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,130 @@
+/*****************************************************************************
+
+ FileName: nationalStateNT.c
+
+ Contents: National ISDN State Engine for NT (Network Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "national.h"
+
+/*****************************************************************************
+ Function: nationalCreateNT
+
+ Description: Will create the National ISDN NT as a Dialect in the stack. The first
+ bulk set up the message handlers, the second bulk the IE
+ encoders/coders, and the last bulk set up the state table.
+
+ Parameters: i Dialect index
+*****************************************************************************/
+void nationalCreateNT(L3UCHAR i)
+{
+ Q931SetMesProc(Q931mes_ALERTING, i, Q931ProcAlertingNT, Q931Umes_Alerting, Q931Pmes_Alerting);
+ Q931SetMesProc(Q931mes_CALL_PROCEEDING, i, Q931ProcCallProceedingNT, Q931Umes_CallProceeding, Q931Pmes_CallProceeding);
+ Q931SetMesProc(Q931mes_CONNECT, i, Q931ProcConnectNT, Q931Umes_Connect, Q931Pmes_Connect);
+ Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i, Q931ProcConnectAckNT, Q931Umes_ConnectAck, Q931Pmes_ConnectAck);
+ Q931SetMesProc(Q931mes_PROGRESS, i, Q931ProcProgressNT, Q931Umes_Progress, Q931Pmes_Progress);
+ Q931SetMesProc(Q931mes_SETUP, i, Q931ProcSetupNT, nationalUmes_Setup, nationalPmes_Setup);
+ Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE, i, Q931ProcSetupAckNT, Q931Umes_SetupAck, Q931Pmes_SetupAck);
+ Q931SetMesProc(Q931mes_RESUME, i, Q931ProcResumeNT, Q931Umes_Resume, Q931Pmes_Resume);
+ Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE, i, Q931ProcResumeAckNT, Q931Umes_ResumeAck, Q931Pmes_ResumeAck);
+ Q931SetMesProc(Q931mes_RESUME_REJECT, i, Q931ProcResumeRejectNT, Q931Umes_ResumeReject, Q931Pmes_ResumeReject);
+ Q931SetMesProc(Q931mes_SUSPEND, i, Q931ProcSuspendNT, Q931Umes_Suspend, Q931Pmes_Suspend);
+ Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE, i, Q931ProcSuspendAckNT, Q931Umes_SuspendAck, Q931Pmes_SuspendAck);
+ Q931SetMesProc(Q931mes_SUSPEND_REJECT, i, Q931ProcSuspendRejectNT, Q931Umes_SuspendReject, Q931Pmes_SuspendReject);
+ Q931SetMesProc(Q931mes_USER_INFORMATION, i, Q931ProcUserInformationNT, Q931Umes_UserInformation, Q931Pmes_UserInformation);
+ Q931SetMesProc(Q931mes_DISCONNECT, i, Q931ProcDisconnectNT, Q931Umes_Disconnect, Q931Pmes_Disconnect);
+ Q931SetMesProc(Q931mes_RELEASE, i, Q931ProcReleaseNT, Q931Umes_Release, Q931Pmes_Release);
+ Q931SetMesProc(Q931mes_RELEASE_COMPLETE, i, Q931ProcReleaseCompleteNT, Q931Umes_ReleaseComplete, Q931Pmes_ReleaseComplete);
+ Q931SetMesProc(Q931mes_RESTART, i, Q931ProcRestartNT, Q931Umes_Restart, Q931Pmes_Restart);
+ Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE, i, Q931ProcRestartAckNT, Q931Umes_RestartAck, Q931Pmes_RestartAck);
+ Q931SetMesProc(Q931mes_CONGESTION_CONTROL, i, Q931ProcCongestionControlNT, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+ Q931SetMesProc(Q931mes_INFORMATION, i, Q931ProcInformationNT, Q931Umes_Information, Q931Pmes_Information);
+ Q931SetMesProc(Q931mes_NOTIFY, i, Q931ProcNotifyNT, Q931Umes_Notify, Q931Pmes_Notify);
+ Q931SetMesProc(Q931mes_STATUS, i, Q931ProcStatusNT, Q931Umes_Status, Q931Pmes_Status);
+ Q931SetMesProc(Q931mes_STATUS_ENQUIRY, i, Q931ProcStatusEnquiryNT, Q931Umes_StatusEnquiry, Q931Pmes_StatusEnquiry);
+ Q931SetMesProc(Q931mes_SEGMENT, i, Q931ProcSegmentNT, Q931Umes_Segment, Q931Pmes_Segment);
+
+ Q931SetMesProc(Q932mes_FACILITY, i, Q932ProcFacilityNT, Q932Umes_Facility, Q932Pmes_Facility);
+ Q931SetMesProc(Q932mes_HOLD, i, Q932ProcHoldNT, Q932Umes_Hold, Q932Pmes_Hold);
+ Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE, i, Q932ProcHoldAckNT, Q932Umes_HoldAck, Q932Pmes_HoldAck);
+ Q931SetMesProc(Q932mes_HOLD_REJECT, i, Q932ProcHoldRejectNT, Q932Umes_HoldReject, Q932Pmes_HoldReject);
+ Q931SetMesProc(Q932mes_REGISTER, i, Q932ProcRegisterNT, Q932Umes_Register, Q932Pmes_Register);
+ Q931SetMesProc(Q932mes_RETRIEVE, i, Q932ProcRetrieveNT, Q932Umes_Retrieve, Q932Pmes_Retrieve);
+ Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckNT, Q932Umes_RetrieveAck, Q932Pmes_RetrieveAck);
+ Q931SetMesProc(Q932mes_RETRIEVE_REJECT, i, Q932ProcRetrieveRejectNT, Q932Umes_RetrieveReject, Q932Pmes_RetrieveReject);
+
+ /* Set up the IE encoder/decoder handle table.*/
+ Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE, i, Q931Pie_Segment, Q931Uie_Segment);
+ Q931SetIEProc(Q931ie_BEARER_CAPABILITY, i, Q931Pie_BearerCap, Q931Uie_BearerCap);
+ Q931SetIEProc(Q931ie_CAUSE, i, Q931Pie_Cause, Q931Uie_Cause);
+ Q931SetIEProc(Q931ie_CALL_IDENTITY, i, Q931Pie_CallID, Q931Uie_CallID);
+ Q931SetIEProc(Q931ie_CALL_STATE, i, Q931Pie_CallState, Q931Uie_CallState);
+ Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION, i, Q931Pie_ChanID, Q931Uie_ChanID);
+ Q931SetIEProc(Q931ie_PROGRESS_INDICATOR, i, Q931Pie_ProgInd, Q931Uie_ProgInd);
+ Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES, i, Q931Pie_NetFac, Q931Uie_NetFac);
+ Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR, i, Q931Pie_NotifInd, Q931Uie_NotifInd);
+ Q931SetIEProc(Q931ie_DISPLAY, i, Q931Pie_Display, Q931Uie_Display);
+ Q931SetIEProc(Q931ie_DATETIME, i, Q931Pie_DateTime, Q931Uie_DateTime);
+ Q931SetIEProc(Q931ie_KEYPAD_FACILITY, i, Q931Pie_KeypadFac, Q931Uie_KeypadFac);
+ Q931SetIEProc(Q931ie_SIGNAL, i, Q931Pie_Signal, Q931Uie_Signal);
+ Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER, i, Q931Pie_CallingNum, Q931Uie_CallingNum);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS, i, Q931Pie_CallingSub, Q931Uie_CallingSub);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER, i, Q931Pie_CalledNum, Q931Uie_CalledNum);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS, i, Q931Pie_CalledSub, Q931Uie_CalledSub);
+ Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_RESTART_INDICATOR, i, Q931Pie_RestartInd, Q931Uie_RestartInd);
+ Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY, i, Q931Pie_LLComp, Q931Uie_LLComp);
+ Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY, i, Q931Pie_HLComp, Q931Uie_HLComp);
+ Q931SetIEProc(Q931ie_USER_USER, i, Q931Pie_UserUser, Q931Uie_UserUser);
+ Q931SetIEProc(Q931ie_GENERIC_DIGITS, i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+ Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_FACILITY, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_REDIRECTING_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+
+ /* The following define a state machine. The point is that the Message */
+ /* procs can when search this to find out if the message/state */
+ /* combination is legale. If not, the proc for unexpected message apply.*/
+
+ /* TODO define state table here */
+}
Added: freeswitch/trunk/libs/openzap/src/isdn/nationalStateTE.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/nationalStateTE.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/nationalStateTE.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,217 @@
+/*****************************************************************************
+
+ FileName: nationalStateTE.c
+
+ Contents: National ISDN State Engine for TE (User Mode).
+
+ The controlling state engine for Q.931 is the state engine
+ on the NT side. The state engine on the TE side is a slave
+ of this. The TE side maintain it's own states as described in
+ ITU-T Q931, but will in raise conditions be overridden by
+ the NT side.
+
+ This reference implementation uses a process per message,
+ meaning that each message must check call states. This
+ is easier for dialect maintenance as each message proc
+ can be replaced individually. A new TE variant only
+ need to copy the Q931CreateTE and replace those procs or
+ need to override.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ 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 Case Labs, Ltd 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.
+*****************************************************************************/
+
+#include "national.h"
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+ Function: nationalCreateTE
+
+ Description: Will create the National TE as a Dialect in the stack. The first
+ bulk set up the message handlers, the second bulk the IE
+ encoders/coders, and the last bulk set up the state table.
+
+ Parameters: i Dialect index
+*****************************************************************************/
+void nationalCreateTE(L3UCHAR i)
+{
+ Q931SetMesProc(Q931mes_ALERTING, i, Q931ProcAlertingTE, Q931Umes_Alerting, Q931Pmes_Alerting);
+ Q931SetMesProc(Q931mes_CALL_PROCEEDING, i, Q931ProcCallProceedingTE, Q931Umes_CallProceeding, Q931Pmes_CallProceeding);
+ Q931SetMesProc(Q931mes_CONNECT, i, DMSProc0x07TE, DMSUmes_0x07, DMSPmes_0x07);
+ Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i, DMSProc0x0fTE, DMSUmes_0x0f, DMSPmes_0x0f);
+ Q931SetMesProc(Q931mes_PROGRESS, i, Q931ProcProgressTE, Q931Umes_Progress, Q931Pmes_Progress);
+ Q931SetMesProc(Q931mes_SETUP, i, Q931ProcSetupTE, nationalUmes_Setup, nationalPmes_Setup);
+ Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE, i, Q931ProcSetupAckTE, Q931Umes_SetupAck, Q931Pmes_SetupAck);
+ Q931SetMesProc(Q931mes_RESUME, i, Q931ProcResumeTE, Q931Umes_Resume, Q931Pmes_Resume);
+ Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE, i, Q931ProcResumeAckTE, Q931Umes_ResumeAck, Q931Pmes_ResumeAck);
+ Q931SetMesProc(Q931mes_RESUME_REJECT, i, Q931ProcResumeRejectTE, Q931Umes_ResumeReject, Q931Pmes_ResumeReject);
+ Q931SetMesProc(Q931mes_SUSPEND, i, Q931ProcSuspendTE, Q931Umes_Suspend, Q931Pmes_Suspend);
+ Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE, i, Q931ProcSuspendAckTE, Q931Umes_SuspendAck, Q931Pmes_SuspendAck);
+ Q931SetMesProc(Q931mes_SUSPEND_REJECT, i, Q931ProcSuspendRejectTE, Q931Umes_SuspendReject, Q931Pmes_SuspendReject);
+ Q931SetMesProc(Q931mes_USER_INFORMATION, i, Q931ProcUserInformationTE, Q931Umes_UserInformation, Q931Pmes_UserInformation);
+ Q931SetMesProc(Q931mes_DISCONNECT, i, Q931ProcDisconnectTE, Q931Umes_Disconnect, Q931Pmes_Disconnect);
+ Q931SetMesProc(Q931mes_RELEASE, i, Q931ProcReleaseTE, Q931Umes_Release, Q931Pmes_Release);
+ Q931SetMesProc(Q931mes_RELEASE_COMPLETE, i, Q931ProcReleaseCompleteTE, Q931Umes_ReleaseComplete, Q931Pmes_ReleaseComplete);
+ Q931SetMesProc(Q931mes_RESTART, i, Q931ProcRestartTE, Q931Umes_Restart, Q931Pmes_Restart);
+ Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE, i, Q931ProcRestartAckTE, Q931Umes_RestartAck, Q931Pmes_RestartAck);
+ Q931SetMesProc(Q931mes_CONGESTION_CONTROL, i, Q931ProcCongestionControlTE, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+ Q931SetMesProc(Q931mes_INFORMATION, i, Q931ProcInformationTE, Q931Umes_Information, Q931Pmes_Information);
+ Q931SetMesProc(Q931mes_NOTIFY, i, Q931ProcNotifyTE, Q931Umes_Notify, Q931Pmes_Notify);
+ Q931SetMesProc(Q931mes_STATUS, i, Q931ProcStatusTE, Q931Umes_Status, Q931Pmes_Status);
+ Q931SetMesProc(Q931mes_STATUS_ENQUIRY, i, Q931ProcStatusEnquiryTE, Q931Umes_StatusEnquiry, Q931Pmes_StatusEnquiry);
+ Q931SetMesProc(Q931mes_SEGMENT, i, Q931ProcSegmentTE, Q931Umes_Segment, Q931Pmes_Segment);
+
+ Q931SetMesProc(Q932mes_FACILITY, i, Q932ProcFacilityTE, Q932Umes_Facility, Q932Pmes_Facility);
+ Q931SetMesProc(Q932mes_HOLD, i, Q932ProcHoldTE, Q932Umes_Hold, Q932Pmes_Hold);
+ Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE, i, Q932ProcHoldAckTE, Q932Umes_HoldAck, Q932Pmes_HoldAck);
+ Q931SetMesProc(Q932mes_HOLD_REJECT, i, Q932ProcHoldRejectTE, Q932Umes_HoldReject, Q932Pmes_HoldReject);
+ Q931SetMesProc(Q932mes_REGISTER, i, Q932ProcRegisterTE, Q932Umes_Register, Q932Pmes_Register);
+ Q931SetMesProc(Q932mes_RETRIEVE, i, Q932ProcRetrieveTE, Q932Umes_Retrieve, Q932Pmes_Retrieve);
+ Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckTE, Q932Umes_RetrieveAck, Q932Pmes_RetrieveAck);
+ Q931SetMesProc(Q932mes_RETRIEVE_REJECT, i, Q932ProcRetrieveRejectTE, Q932Umes_RetrieveReject, Q932Pmes_RetrieveReject);
+
+ /* Set up the IE encoder/decoder handle table.*/
+ Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE, i, Q931Pie_Segment, Q931Uie_Segment);
+ Q931SetIEProc(Q931ie_BEARER_CAPABILITY, i, Q931Pie_BearerCap, Q931Uie_BearerCap);
+ Q931SetIEProc(Q931ie_CAUSE, i, Q931Pie_Cause, Q931Uie_Cause);
+ Q931SetIEProc(Q931ie_CALL_IDENTITY, i, Q931Pie_CallID, Q931Uie_CallID);
+ Q931SetIEProc(Q931ie_CALL_STATE, i, Q931Pie_CallState, Q931Uie_CallState);
+ Q931SetIEProc(Q931ie_CHANGE_STATUS, i, Q931Pie_ChangeStatus, Q931Uie_ChangeStatus);
+ Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION, i, Q931Pie_ChanID, Q931Uie_ChanID);
+ Q931SetIEProc(Q931ie_PROGRESS_INDICATOR, i, Q931Pie_ProgInd, Q931Uie_ProgInd);
+ Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES, i, Q931Pie_NetFac, Q931Uie_NetFac);
+ Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR, i, Q931Pie_NotifInd, Q931Uie_NotifInd);
+ Q931SetIEProc(Q931ie_DISPLAY, i, Q931Pie_Display, Q931Uie_Display);
+ Q931SetIEProc(Q931ie_DATETIME, i, Q931Pie_DateTime, Q931Uie_DateTime);
+ Q931SetIEProc(Q931ie_KEYPAD_FACILITY, i, Q931Pie_KeypadFac, Q931Uie_KeypadFac);
+ Q931SetIEProc(Q931ie_SIGNAL, i, Q931Pie_Signal, Q931Uie_Signal);
+ Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER, i, Q931Pie_CallingNum, Q931Uie_CallingNum);
+ Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS, i, Q931Pie_CallingSub, Q931Uie_CallingSub);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER, i, Q931Pie_CalledNum, Q931Uie_CalledNum);
+ Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS, i, Q931Pie_CalledSub, Q931Uie_CalledSub);
+ Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION, i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+ Q931SetIEProc(Q931ie_RESTART_INDICATOR, i, Q931Pie_RestartInd, Q931Uie_RestartInd);
+ Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY, i, Q931Pie_LLComp, Q931Uie_LLComp);
+ Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY, i, Q931Pie_HLComp, Q931Uie_HLComp);
+ Q931SetIEProc(Q931ie_USER_USER, i, Q931Pie_UserUser, Q931Uie_UserUser);
+ Q931SetIEProc(Q931ie_GENERIC_DIGITS, i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+ Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_FACILITY, i, Q931Pie_Generic, Q931Uie_Generic);
+ Q931SetIEProc(Q931ie_REDIRECTING_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+
+ /* The following define a state machine. The point is that the Message
+ * procs can when search this to find out if the message/state
+ * combination is legale. If not, the proc for unexpected message apply.
+ */
+
+ /* State 0 Idle */
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RESUME, 2);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP, 2);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_STATUS, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE_COMPLETE, 4);
+
+ /* State 1 Call Initiating */
+ Q931AddStateEntry(i, Q931_U1, Q931mes_DISCONNECT, 2);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_SETUP_ACKNOWLEDGE, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_RELEASE_COMPLETE, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_CALL_PROCEEDING, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U1, Q931mes_CONNECT, 4);
+
+ /* State 2 Overlap Sending */
+ Q931AddStateEntry(i, Q931_U2, Q931mes_INFORMATION, 2);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_CALL_PROCEEDING, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_PROGRESS, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_CONNECT, 4);
+ Q931AddStateEntry(i, Q931_U2, Q931mes_RELEASE, 2);
+
+ /* State 3 Outgoing Call Proceeding */
+ Q931AddStateEntry(i, Q931_U3, Q931mes_PROGRESS, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_ALERTING, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_CONNECT, 4);
+ Q931AddStateEntry(i, Q931_U3, Q931mes_RELEASE, 2);
+
+ /* State 4 Call Delivered */
+ Q931AddStateEntry(i, Q931_U4, Q931mes_CONNECT, 4);
+
+ /* State 6 Call Precent */
+ Q931AddStateEntry(i, Q931_U6, Q931mes_INFORMATION, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_ALERTING, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_CALL_PROCEEDING, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_CONNECT, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE_COMPLETE, 2);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U6, Q931mes_DISCONNECT, 4);
+
+ /* State 7 Call Received */
+ Q931AddStateEntry(i, Q931_U7, Q931mes_CONNECT, 2);
+
+ /* State 8 Connect request */
+ Q931AddStateEntry(i, Q931_U8, Q931mes_CONNECT_ACKNOWLEDGE, 4);
+
+ /* State 9 Incoming Call Proceeding */
+ Q931AddStateEntry(i, Q931_U9, Q931mes_CONNECT, 2);
+ Q931AddStateEntry(i, Q931_U9, Q931mes_ALERTING, 2);
+ Q931AddStateEntry(i, Q931_U9, Q931mes_PROGRESS, 2);
+
+ /* State 10 Active */
+ Q931AddStateEntry(i, Q931_U10, Q931mes_SUSPEND, 2);
+ Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY, 4);
+ Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY, 2);
+
+ /* State 11 Disconnect Request */
+ Q931AddStateEntry(i, Q931_U11, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U11, Q931mes_DISCONNECT, 4);
+ Q931AddStateEntry(i, Q931_U11, Q931mes_NOTIFY, 4);
+
+ /* State 12 Disconnect Ind */
+ Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 4);
+ Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 2);
+
+ /* State 15 Suspend Request */
+ Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_ACKNOWLEDGE, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_REJECT, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_DISCONNECT, 4);
+ Q931AddStateEntry(i, Q931_U15, Q931mes_RELEASE, 4);
+
+/* TODO
+ Q931AddStateEntry(i, Q931_U17,
+ Q931AddStateEntry(i, Q931_U19,
+ Q931AddStateEntry(i, Q931_U25,
+*/
+}
Added: freeswitch/trunk/libs/openzap/src/isdn/nationalmes.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/isdn/nationalmes.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/nationalmes.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,269 @@
+/*****************************************************************************
+
+ FileName: nationalmes.c
+
+ Contents: Pack/Unpack functions. These functions will unpack a National ISDN
+ message from the bit packed original format into structs
+ that contains variables sized by the user. It will also pack
+ the struct back into a Q.931 message as required.
+
+ See national.h for description.
+
+ License/Copyright:
+
+ Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+ email:janvb@caselaboratories.com
+
+ Copyright (c) 2007, Michael Jerris. All rights reserved.
+ email:mike@jerris.com
+
+ 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 Case Labs, Ltd 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.
+
+*****************************************************************************/
+
+#include "national.h"
+
+/*****************************************************************************
+
+ Function: nationalUmes_Setup
+
+*****************************************************************************/
+L3INT nationalUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+ L3INT ir = 0;
+ L3INT OOff = 0;
+ L3INT rc = Q931E_NO_ERROR;
+ L3UCHAR last_codeset = 0, codeset = 0;
+ L3UCHAR shift_lock = 1;
+
+ while (IOff < Size) {
+ if (!shift_lock) {
+ codeset = last_codeset;
+ }
+
+ if ((IBuf[IOff] & 0xF0) == Q931ie_SHIFT ) {
+ shift_lock = (IBuf[IOff] & 0x08);
+ if (shift_lock) {
+ last_codeset = codeset;
+ }
+ codeset = ((IBuf[IOff] & 0x07));
+ IOff++;
+ }
+
+ if (codeset == 0) {
+ switch (IBuf[IOff]) {
+ case Q931ie_SENDING_COMPLETE:
+ case Q931ie_BEARER_CAPABILITY:
+ case Q931ie_CHANNEL_IDENTIFICATION:
+ case Q931ie_PROGRESS_INDICATOR:
+ case Q931ie_NETWORK_SPECIFIC_FACILITIES:
+ case Q931ie_DISPLAY:
+ case Q931ie_DATETIME:
+ case Q931ie_KEYPAD_FACILITY:
+ case Q931ie_SIGNAL:
+ case Q931ie_CALLING_PARTY_NUMBER:
+ case Q931ie_CALLING_PARTY_SUBADDRESS:
+ case Q931ie_CALLED_PARTY_NUMBER:
+ case Q931ie_CALLED_PARTY_SUBADDRESS:
+ case Q931ie_TRANSIT_NETWORK_SELECTION:
+ case Q931ie_LOW_LAYER_COMPATIBILITY:
+ case Q931ie_HIGH_LAYER_COMPATIBILITY:
+ case Q931ie_FACILITY:
+ case Q931ie_REDIRECTING_NUMBER:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ case Q931ie_REPEAT_INDICATOR:
+ if (ir < 2) {
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ ir++;
+ } else {
+ return Q931E_ILLEGAL_IE;
+ }
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+ } else if (codeset == 6) {
+ switch (IBuf[IOff]) {
+ case Q931ie_GENERIC_DIGITS:
+ rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+ if (rc != Q931E_NO_ERROR)
+ return rc;
+ break;
+ default:
+ return Q931E_ILLEGAL_IE;
+ break;
+ }
+
+ } else {
+ return Q931E_ILLEGAL_IE;
+ }
+ }
+ mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+ return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+ Function: nationalPmes_Setup
+
+ Decription: Pack a Q931mes_Generic into a real Q.931 message. The user will
+ set up a SETUP message and issue this to the stack where it
+ is processed by Q931ProcSetup that processes and validates
+ it before it actually sends it out. This function is called
+ to compute the real Q.931 message.
+
+ Parameters: IBuf[IN] Ptr to un-packed struct
+ ISize[IN] Size of input buffer (unpacked message).
+ OBuf[OUT] Ptr to packed 'octet' wise message.
+ OSize[OUT] Size of packed message.
+
+ Called By: Q931ProcSetup
+
+*****************************************************************************/
+L3INT nationalPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+ L3INT rc = Q931E_NO_ERROR;
+ Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+ L3INT Octet = 0;
+
+ /* Q931 Message Header */
+ Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+ /* Sending Complete */
+ if (Q931IsIEPresent(pMes->SendComplete)) {
+ OBuf[Octet++] = (L3UCHAR)(pMes->SendComplete & 0x00ff);
+ }
+
+ /* Repeat Indicator */
+ if (Q931IsIEPresent(pMes->RepeatInd)) {
+ OBuf[Octet++] = (L3UCHAR)(pMes->RepeatInd & 0x00ff);
+ }
+
+ /* Bearer capability */
+ if (Q931IsIEPresent(pMes->BearerCap)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+ else {
+ rc = Q931E_BEARERCAP;
+ }
+
+ /* Channel Identification */
+ if (Q931IsIEPresent(pMes->ChanID)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Progress indicator */
+ if (Q931IsIEPresent(pMes->ProgInd)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Network spesific facilities */
+ if (Q931IsIEPresent(pMes->NetFac)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_NETWORK_SPECIFIC_FACILITIES](pTrunk, Q931GetIEPtr(pMes->NetFac,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Display */
+ if (Q931IsIEPresent(pMes->Display)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Date/Time */
+ if (Q931IsIEPresent(pMes->DateTime)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Keypad Facility */
+ if (Q931IsIEPresent(pMes->KeypadFac)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Signal */
+ if (Q931IsIEPresent(pMes->Signal)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Calling Party Number */
+ if (Q931IsIEPresent(pMes->CallingNum)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CallingNum,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Calling Party Subaddress */
+ if (Q931IsIEPresent(pMes->CallingSub)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CallingSub,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Called Party number */
+ if (Q931IsIEPresent(pMes->CalledNum)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Called party subaddress */
+ if (Q931IsIEPresent(pMes->CalledSub)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CalledSub,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Transit network selection */
+ if (Q931IsIEPresent(pMes->TransNetSel)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_TRANSIT_NETWORK_SELECTION](pTrunk, Q931GetIEPtr(pMes->TransNetSel,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* Repeat Indicator */
+ if (Q931IsIEPresent(pMes->LLRepeatInd)) {
+ rc = Q931E_UNKNOWN_IE;/* TODO */
+ }
+
+ /* Low Layer Compatibility */
+ if (Q931IsIEPresent(pMes->LLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ /* High Layer Compatibility */
+ if (Q931IsIEPresent(pMes->HLComp)) {
+ if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+ return rc;
+ }
+
+ *OSize = Octet;
+ return rc;
+}
Added: freeswitch/trunk/libs/openzap/src/libteletone_detect.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/libteletone_detect.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/libteletone_detect.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,427 @@
+/*
+ * libteletone
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Much less efficient expansion interface was added to allow for the detection of
+ * a single arbitrary tone combination which may also exceed 2 simultaneous tones.
+ * (controlled by compile time constant TELETONE_MAX_TONES)
+ *
+ * Copyright (C) 2006 Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * libteletone_detect.c Tone Detection Code
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ *
+ *********************************************************************************
+ *
+ * Derived from tone_detect.c - General telephony tone detection, and specific
+ * detection of DTMF.
+ *
+ * Copyright (C) 2001 Steve Underwood <steveu@coppice.org>
+ *
+ * Despite my general liking of the GPL, I place this code in the
+ * public domain for the benefit of all mankind - even the slimy
+ * ones who might try to proprietize my work and use it to my
+ * detriment.
+ *
+ *
+ *
+ */
+
+#include <libteletone_detect.h>
+
+#ifndef _MSC_VER
+#include <stdint.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <fcntl.h>
+
+
+static teletone_detection_descriptor_t dtmf_detect_row[GRID_FACTOR];
+static teletone_detection_descriptor_t dtmf_detect_col[GRID_FACTOR];
+static teletone_detection_descriptor_t dtmf_detect_row_2nd[GRID_FACTOR];
+static teletone_detection_descriptor_t dtmf_detect_col_2nd[GRID_FACTOR];
+
+static float dtmf_row[] = {697.0f, 770.0f, 852.0f, 941.0f};
+static float dtmf_col[] = {1209.0f, 1336.0f, 1477.0f, 1633.0f};
+
+static char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
+
+static void goertzel_init(teletone_goertzel_state_t *goertzel_state, teletone_detection_descriptor_t *tdesc) {
+ goertzel_state->v2 = goertzel_state->v3 = 0.0;
+ goertzel_state->fac = tdesc->fac;
+}
+
+TELETONE_API(void) teletone_goertzel_update(teletone_goertzel_state_t *goertzel_state,
+ int16_t sample_buffer[],
+ int samples)
+{
+ int i;
+ float v1;
+
+ for (i = 0; i < samples; i++) {
+ v1 = goertzel_state->v2;
+ goertzel_state->v2 = goertzel_state->v3;
+ goertzel_state->v3 = (float)(goertzel_state->fac*goertzel_state->v2 - v1 + sample_buffer[i]);
+ }
+}
+#ifdef _MSC_VER
+#pragma warning(disable:4244)
+#endif
+
+#define teletone_goertzel_result(gs) (double)(((gs)->v3 * (gs)->v3 + (gs)->v2 * (gs)->v2 - (gs)->v2 * (gs)->v3 * (gs)->fac))
+
+TELETONE_API(void) teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate)
+{
+ int i;
+ float theta;
+
+ dtmf_detect_state->hit1 = dtmf_detect_state->hit2 = 0;
+
+ for (i = 0; i < GRID_FACTOR; i++) {
+ theta = (float)(M_TWO_PI*(dtmf_row[i]/(float)sample_rate));
+ dtmf_detect_row[i].fac = (float)(2.0*cos(theta));
+
+ theta = (float)(M_TWO_PI*(dtmf_col[i]/(float)sample_rate));
+ dtmf_detect_col[i].fac = (float)(2.0*cos(theta));
+
+ theta = (float)(M_TWO_PI*(dtmf_row[i]*2.0/(float)sample_rate));
+ dtmf_detect_row_2nd[i].fac = (float)(2.0*cos(theta));
+
+ theta = (float)(M_TWO_PI*(dtmf_col[i]*2.0/(float)sample_rate));
+ dtmf_detect_col_2nd[i].fac = (float)(2.0*cos(theta));
+
+ goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]);
+ goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]);
+ goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]);
+ goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]);
+
+ dtmf_detect_state->energy = 0.0;
+ }
+ dtmf_detect_state->current_sample = 0;
+ dtmf_detect_state->detected_digits = 0;
+ dtmf_detect_state->lost_digits = 0;
+ dtmf_detect_state->digits[0] = '\0';
+ dtmf_detect_state->mhit = 0;
+}
+
+TELETONE_API(void) teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map)
+{
+ float theta = 0;
+ int x = 0;
+
+ if (!mt->sample_rate) {
+ mt->sample_rate = 8000;
+ }
+
+ if (!mt->min_samples) {
+ mt->min_samples = 102;
+ }
+
+ mt->min_samples *= (mt->sample_rate / 8000);
+
+ if (!mt->positive_factor) {
+ mt->positive_factor = 2;
+ }
+
+ if(!mt->negative_factor) {
+ mt->negative_factor = 10;
+ }
+
+ if (!mt->hit_factor) {
+ mt->hit_factor = 2;
+ }
+
+ for(x = 0; x < TELETONE_MAX_TONES; x++) {
+ if ((int) map->freqs[x] == 0) {
+ break;
+ }
+ mt->tone_count++;
+ theta = (float)(M_TWO_PI*(map->freqs[x]/(float)mt->sample_rate));
+ mt->tdd[x].fac = (float)(2.0 * cos(theta));
+ goertzel_init (&mt->gs[x], &mt->tdd[x]);
+ goertzel_init (&mt->gs2[x], &mt->tdd[x]);
+ }
+
+}
+
+TELETONE_API(int) teletone_multi_tone_detect (teletone_multi_tone_t *mt,
+ int16_t sample_buffer[],
+ int samples)
+{
+ int sample, limit = 0, j, x = 0;
+ float v1, famp;
+ float eng_sum = 0, eng_all[TELETONE_MAX_TONES] = {0.0};
+ int gtest = 0, see_hit = 0;
+
+ for (sample = 0; sample >= 0 && sample < samples; sample = limit) {
+ mt->total_samples++;
+
+ if ((samples - sample) >= (mt->min_samples - mt->current_sample)) {
+ limit = sample + (mt->min_samples - mt->current_sample);
+ } else {
+ limit = samples;
+ }
+ if (limit < 0 || limit > samples) {
+ limit = samples;
+ }
+
+ for (j = sample; j < limit; j++) {
+ famp = sample_buffer[j];
+
+ mt->energy += famp*famp;
+
+ for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
+ v1 = mt->gs[x].v2;
+ mt->gs[x].v2 = mt->gs[x].v3;
+ mt->gs[x].v3 = (float)(mt->gs[x].fac * mt->gs[x].v2 - v1 + famp);
+
+ v1 = mt->gs2[x].v2;
+ mt->gs2[x].v2 = mt->gs2[x].v3;
+ mt->gs2[x].v3 = (float)(mt->gs2[x].fac*mt->gs2[x].v2 - v1 + famp);
+ }
+ }
+
+ mt->current_sample += (limit - sample);
+ if (mt->current_sample < mt->min_samples) {
+ continue;
+ }
+
+ eng_sum = 0;
+ for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
+ eng_all[x] = (float)(teletone_goertzel_result (&mt->gs[x]));
+ eng_sum += eng_all[x];
+ }
+
+ gtest = 0;
+ for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
+ gtest += teletone_goertzel_result (&mt->gs2[x]) < eng_all[x] ? 1 : 0;
+ }
+
+ if ((gtest >= 2 || gtest == mt->tone_count) && eng_sum > 42.0 * mt->energy) {
+ if(mt->negatives) {
+ mt->negatives--;
+ }
+ mt->positives++;
+
+ if(mt->positives >= mt->positive_factor) {
+ mt->hits++;
+ }
+ if (mt->hits >= mt->hit_factor) {
+ see_hit++;
+ mt->positives = mt->negatives = mt->hits = 0;
+ }
+ } else {
+ mt->negatives++;
+ if(mt->positives) {
+ mt->positives--;
+ }
+ if(mt->negatives > mt->negative_factor) {
+ mt->positives = mt->hits = 0;
+ }
+ }
+
+ /* Reinitialise the detector for the next block */
+ for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
+ goertzel_init (&mt->gs[x], &mt->tdd[x]);
+ goertzel_init (&mt->gs2[x], &mt->tdd[x]);
+ }
+
+ mt->energy = 0.0;
+ mt->current_sample = 0;
+ }
+
+ return see_hit;
+}
+
+
+TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
+ int16_t sample_buffer[],
+ int samples)
+{
+ float row_energy[GRID_FACTOR];
+ float col_energy[GRID_FACTOR];
+ float famp;
+ float v1;
+ int i;
+ int j;
+ int sample;
+ int best_row;
+ int best_col;
+ char hit;
+ int limit;
+
+ hit = 0;
+ for (sample = 0; sample < samples; sample = limit) {
+ /* BLOCK_LEN is optimised to meet the DTMF specs. */
+ if ((samples - sample) >= (BLOCK_LEN - dtmf_detect_state->current_sample)) {
+ limit = sample + (BLOCK_LEN - dtmf_detect_state->current_sample);
+ } else {
+ limit = samples;
+ }
+
+ for (j = sample; j < limit; j++) {
+ int x = 0;
+ famp = sample_buffer[j];
+
+ dtmf_detect_state->energy += famp*famp;
+
+ for(x = 0; x < GRID_FACTOR; x++) {
+ v1 = dtmf_detect_state->row_out[x].v2;
+ dtmf_detect_state->row_out[x].v2 = dtmf_detect_state->row_out[x].v3;
+ dtmf_detect_state->row_out[x].v3 = (float)(dtmf_detect_state->row_out[x].fac*dtmf_detect_state->row_out[x].v2 - v1 + famp);
+
+ v1 = dtmf_detect_state->col_out[x].v2;
+ dtmf_detect_state->col_out[x].v2 = dtmf_detect_state->col_out[x].v3;
+ dtmf_detect_state->col_out[x].v3 = (float)(dtmf_detect_state->col_out[x].fac*dtmf_detect_state->col_out[x].v2 - v1 + famp);
+
+ v1 = dtmf_detect_state->col_out2nd[x].v2;
+ dtmf_detect_state->col_out2nd[x].v2 = dtmf_detect_state->col_out2nd[x].v3;
+ dtmf_detect_state->col_out2nd[x].v3 = (float)(dtmf_detect_state->col_out2nd[x].fac*dtmf_detect_state->col_out2nd[x].v2 - v1 + famp);
+
+ v1 = dtmf_detect_state->row_out2nd[x].v2;
+ dtmf_detect_state->row_out2nd[x].v2 = dtmf_detect_state->row_out2nd[x].v3;
+ dtmf_detect_state->row_out2nd[x].v3 = (float)(dtmf_detect_state->row_out2nd[x].fac*dtmf_detect_state->row_out2nd[x].v2 - v1 + famp);
+ }
+
+ }
+
+ dtmf_detect_state->current_sample += (limit - sample);
+ if (dtmf_detect_state->current_sample < BLOCK_LEN) {
+ continue;
+ }
+ /* We are at the end of a DTMF detection block */
+ /* Find the peak row and the peak column */
+ row_energy[0] = teletone_goertzel_result (&dtmf_detect_state->row_out[0]);
+ col_energy[0] = teletone_goertzel_result (&dtmf_detect_state->col_out[0]);
+
+ for (best_row = best_col = 0, i = 1; i < GRID_FACTOR; i++) {
+ row_energy[i] = teletone_goertzel_result (&dtmf_detect_state->row_out[i]);
+ if (row_energy[i] > row_energy[best_row]) {
+ best_row = i;
+ }
+ col_energy[i] = teletone_goertzel_result (&dtmf_detect_state->col_out[i]);
+ if (col_energy[i] > col_energy[best_col]) {
+ best_col = i;
+ }
+ }
+ hit = 0;
+ /* Basic signal level test and the twist test */
+ if (row_energy[best_row] >= DTMF_THRESHOLD &&
+ col_energy[best_col] >= DTMF_THRESHOLD &&
+ col_energy[best_col] < row_energy[best_row]*DTMF_REVERSE_TWIST &&
+ col_energy[best_col]*DTMF_NORMAL_TWIST > row_energy[best_row]) {
+ /* Relative peak test */
+ for (i = 0; i < GRID_FACTOR; i++) {
+ if ((i != best_col && col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) ||
+ (i != best_row && row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) {
+ break;
+ }
+ }
+ /* ... and second harmonic test */
+ if (i >= GRID_FACTOR && (row_energy[best_row] + col_energy[best_col]) > 42.0*dtmf_detect_state->energy &&
+ teletone_goertzel_result (&dtmf_detect_state->col_out2nd[best_col])*DTMF_2ND_HARMONIC_COL < col_energy[best_col] &&
+ teletone_goertzel_result (&dtmf_detect_state->row_out2nd[best_row])*DTMF_2ND_HARMONIC_ROW < row_energy[best_row]) {
+ hit = dtmf_positions[(best_row << 2) + best_col];
+ /* Look for two successive similar results */
+ /* The logic in the next test is:
+ We need two successive identical clean detects, with
+ something different preceeding it. This can work with
+ back to back differing digits. More importantly, it
+ can work with nasty phones that give a very wobbly start
+ to a digit. */
+ if (hit == dtmf_detect_state->hit3 && dtmf_detect_state->hit3 != dtmf_detect_state->hit2) {
+ dtmf_detect_state->mhit = hit;
+ dtmf_detect_state->digit_hits[(best_row << 2) + best_col]++;
+ dtmf_detect_state->detected_digits++;
+ if (dtmf_detect_state->current_digits < TELETONE_MAX_DTMF_DIGITS) {
+ dtmf_detect_state->digits[dtmf_detect_state->current_digits++] = hit;
+ dtmf_detect_state->digits[dtmf_detect_state->current_digits] = '\0';
+ }
+ else
+ {
+ dtmf_detect_state->lost_digits++;
+ }
+ }
+ }
+ }
+ dtmf_detect_state->hit1 = dtmf_detect_state->hit2;
+ dtmf_detect_state->hit2 = dtmf_detect_state->hit3;
+ dtmf_detect_state->hit3 = hit;
+ /* Reinitialise the detector for the next block */
+ for (i = 0; i < GRID_FACTOR; i++) {
+ goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]);
+ goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]);
+ goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]);
+ goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]);
+ }
+ dtmf_detect_state->energy = 0.0;
+ dtmf_detect_state->current_sample = 0;
+ }
+ if ((!dtmf_detect_state->mhit) || (dtmf_detect_state->mhit != hit)) {
+ dtmf_detect_state->mhit = 0;
+ return(0);
+ }
+ return (hit);
+}
+
+
+TELETONE_API(int) teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state,
+ char *buf,
+ int max)
+{
+ teletone_assert(dtmf_detect_state->current_digits <= TELETONE_MAX_DTMF_DIGITS);
+
+ if (max > dtmf_detect_state->current_digits) {
+ max = dtmf_detect_state->current_digits;
+ }
+ if (max > 0) {
+ memcpy (buf, dtmf_detect_state->digits, max);
+ memmove (dtmf_detect_state->digits, dtmf_detect_state->digits + max, dtmf_detect_state->current_digits - max);
+ dtmf_detect_state->current_digits -= max;
+ }
+ buf[max] = '\0';
+ return max;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/libteletone_generate.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/libteletone_generate.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/libteletone_generate.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,464 @@
+/*
+ * libteletone_generate.c -- Tone Generator
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#include <libteletone.h>
+
+#define SMAX 32767
+#define SMIN -32768
+#define normalize_to_16bit(n) if (n > SMAX) n = SMAX; else if (n < SMIN) n = SMIN;
+
+#ifdef _MSC_VER
+#pragma warning(disable:4706)
+#endif
+
+TELETONE_API_DATA int16_t TELETONE_SINES[SINE_TABLE_MAX] = {
+ 0x00c9, 0x025b, 0x03ed, 0x057f, 0x0711, 0x08a2, 0x0a33, 0x0bc4,
+ 0x0d54, 0x0ee4, 0x1073, 0x1201, 0x138f, 0x151c, 0x16a8, 0x1833,
+ 0x19be, 0x1b47, 0x1cd0, 0x1e57, 0x1fdd, 0x2162, 0x22e5, 0x2467,
+ 0x25e8, 0x2768, 0x28e5, 0x2a62, 0x2bdc, 0x2d55, 0x2ecc, 0x3042,
+ 0x31b5, 0x3327, 0x3497, 0x3604, 0x3770, 0x38d9, 0x3a40, 0x3ba5,
+ 0x3d08, 0x3e68, 0x3fc6, 0x4121, 0x427a, 0x43d1, 0x4524, 0x4675,
+ 0x47c4, 0x490f, 0x4a58, 0x4b9e, 0x4ce1, 0x4e21, 0x4f5e, 0x5098,
+ 0x51cf, 0x5303, 0x5433, 0x5560, 0x568a, 0x57b1, 0x58d4, 0x59f4,
+ 0x5b10, 0x5c29, 0x5d3e, 0x5e50, 0x5f5e, 0x6068, 0x616f, 0x6272,
+ 0x6371, 0x646c, 0x6564, 0x6657, 0x6747, 0x6832, 0x691a, 0x69fd,
+ 0x6add, 0x6bb8, 0x6c8f, 0x6d62, 0x6e31, 0x6efb, 0x6fc2, 0x7083,
+ 0x7141, 0x71fa, 0x72af, 0x735f, 0x740b, 0x74b3, 0x7556, 0x75f4,
+ 0x768e, 0x7723, 0x77b4, 0x7840, 0x78c8, 0x794a, 0x79c9, 0x7a42,
+ 0x7ab7, 0x7b27, 0x7b92, 0x7bf9, 0x7c5a, 0x7cb7, 0x7d0f, 0x7d63,
+ 0x7db1, 0x7dfb, 0x7e3f, 0x7e7f, 0x7eba, 0x7ef0, 0x7f22, 0x7f4e,
+ 0x7f75, 0x7f98, 0x7fb5, 0x7fce, 0x7fe2, 0x7ff1, 0x7ffa, 0x7fff
+};
+
+
+TELETONE_API(int) teletone_set_tone(teletone_generation_session_t *ts, int index, ...)
+{
+ va_list ap;
+ int i = 0;
+ teletone_process_t x = 0;
+
+ va_start(ap, index);
+ while (i < TELETONE_MAX_TONES && (x = va_arg(ap, teletone_process_t))) {
+ ts->TONES[index].freqs[i++] = x;
+ }
+ va_end(ap);
+
+ return (i > TELETONE_MAX_TONES) ? -1 : 0;
+
+}
+
+TELETONE_API(int) teletone_set_map(teletone_tone_map_t *map, ...)
+{
+ va_list ap;
+ int i = 0;
+ teletone_process_t x = 0;
+
+ va_start(ap, map);
+ while (i < TELETONE_MAX_TONES && (x = va_arg(ap, teletone_process_t))) {
+ map->freqs[i++] = x;
+ }
+ va_end(ap);
+
+ return (i > TELETONE_MAX_TONES) ? -1 : 0;
+
+}
+
+TELETONE_API(int) teletone_init_session(teletone_generation_session_t *ts, int buflen, tone_handler handler, void *user_data)
+{
+ memset(ts, 0, sizeof(*ts));
+ ts->rate = 8000;
+ ts->channels = 1;
+ ts->duration = 2000;
+ ts->wait = 500;
+ ts->tmp_duration = -1;
+ ts->tmp_wait = -1;
+ ts->handler = handler;
+ ts->user_data = user_data;
+ ts->volume = -7;
+ ts->decay_step = 0;
+ ts->decay_factor = 1;
+ if (buflen) {
+ if ((ts->buffer = calloc(buflen, sizeof(teletone_audio_t))) == 0) {
+ return -1;
+ }
+ ts->datalen = buflen;
+ } else {
+ ts->dynamic = 1024;
+ }
+ /* Add Standard DTMF Tones */
+ teletone_set_tone(ts, '1', 697.0, 1209.0, 0.0);
+ teletone_set_tone(ts, '2', 697.0, 1336.0, 0.0);
+ teletone_set_tone(ts, '3', 697.0, 1477.0, 0.0);
+ teletone_set_tone(ts, 'A', 697.0, 1633.0, 0.0);
+ teletone_set_tone(ts, '4', 770.0, 1209.0, 0.0);
+ teletone_set_tone(ts, '5', 770.0, 1336.0, 0.0);
+ teletone_set_tone(ts, '6', 770.0, 1477.0, 0.0);
+ teletone_set_tone(ts, 'B', 770.0, 1633.0, 0.0);
+ teletone_set_tone(ts, '7', 859.0, 1209.0, 0.0);
+ teletone_set_tone(ts, '8', 859.0, 1336.0, 0.0);
+ teletone_set_tone(ts, '9', 859.0, 1477.0, 0.0);
+ teletone_set_tone(ts, 'C', 859.0, 1633.0, 0.0);
+ teletone_set_tone(ts, '*', 941.0, 1209.0, 0.0);
+ teletone_set_tone(ts, '0', 941.0, 1336.0, 0.0);
+ teletone_set_tone(ts, '#', 941.0, 1477.0, 0.0);
+ teletone_set_tone(ts, 'D', 941.0, 1633.0, 0.0);
+
+ return 0;
+}
+
+TELETONE_API(int) teletone_destroy_session(teletone_generation_session_t *ts)
+{
+ if (ts->buffer) {
+ free(ts->buffer);
+ ts->buffer = NULL;
+ ts->samples = 0;
+ }
+ return 0;
+}
+
+static int ensure_buffer(teletone_generation_session_t *ts, int need)
+{
+ need += ts->samples;
+ need *= sizeof(teletone_audio_t);
+ need *= ts->channels;
+
+ if (need > ts->datalen) {
+ teletone_audio_t *tmp;
+ ts->datalen = need + ts->dynamic;
+ tmp = realloc(ts->buffer, ts->datalen);
+ if (!tmp) {
+ return -1;
+ }
+ ts->buffer = tmp;
+ }
+
+ return 0;
+}
+
+TELETONE_API(int) teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+ /*teletone_process_t period = (1.0 / ts->rate) / ts->channels;*/
+ int i, c;
+ int freqlen = 0;
+ teletone_dds_state_t tones[TELETONE_MAX_TONES+1];
+ //int decay = 0;
+ int duration;
+ int wait = 0;
+ int32_t sample;
+ int32_t dc = 0;
+ float vol = ts->volume;
+ ts->samples = 0;
+ memset(tones, 0, sizeof(tones[0]) * TELETONE_MAX_TONES);
+ duration = (ts->tmp_duration > -1) ? ts->tmp_duration : ts->duration;
+ wait = (ts->tmp_wait > -1) ? ts->tmp_wait : ts->wait;
+
+ if (map->freqs[0] > 0) {
+ for (freqlen = 0; freqlen < TELETONE_MAX_TONES && map->freqs[freqlen]; freqlen++) {
+ teletone_dds_state_set_tone(&tones[freqlen], map->freqs[freqlen], ts->rate, 0);
+ teletone_dds_state_set_tx_level(&tones[freqlen], vol);
+ }
+
+ if (ts->channels > 1) {
+ duration *= ts->channels;
+ }
+
+ if (ts->dynamic) {
+ if (ensure_buffer(ts, duration)) {
+ return -1;
+ }
+ }
+
+ for (ts->samples = 0; ts->samples < ts->datalen && ts->samples < duration; ts->samples++) {
+ if (ts->decay_direction && ++dc >= ts->decay_step) {
+ float nvol = vol + ts->decay_direction * ts->decay_factor;
+ int j;
+
+ if (nvol <= TELETONE_VOL_DB_MAX && nvol >= TELETONE_VOL_DB_MIN) {
+ vol = nvol;
+ for (j = 0; j < TELETONE_MAX_TONES && map->freqs[j]; j++) {
+ teletone_dds_state_set_tx_level(&tones[j], vol);
+ }
+ dc = 0;
+ }
+ }
+
+ sample = 128;
+
+ for (i = 0; i < freqlen; i++) {
+ int32_t s = teletone_dds_state_modulate_sample(&tones[i], 0);
+ sample += s;
+ }
+ sample /= freqlen;
+ ts->buffer[ts->samples] = (teletone_audio_t)sample;
+
+ for (c = 1; c < ts->channels; c++) {
+ ts->buffer[ts->samples+1] = ts->buffer[ts->samples];
+ ts->samples++;
+ }
+
+ }
+ }
+ if (ts->dynamic) {
+ if (ensure_buffer(ts, wait)) {
+ return -1;
+ }
+ }
+ for (c = 0; c < ts->channels; c++) {
+ for (i = 0; i < wait && ts->samples < ts->datalen; i++) {
+ ts->buffer[ts->samples++] = 0;
+ }
+ }
+
+ if (ts->debug && ts->debug_stream) {
+ if (map->freqs[0] <= 0) {
+ fprintf(ts->debug_stream, "wait %d (%dms)\n", wait, wait / (ts->rate / 1000));
+ } else {
+ fprintf(ts->debug_stream, "Generate: (");
+
+ for (i = 0; i < TELETONE_MAX_TONES && map->freqs[i]; i++) {
+ fprintf(ts->debug_stream, "%s%0.2f", i == 0 ? "" : "+",map->freqs[i]);
+ }
+
+ fprintf(ts->debug_stream,
+ ") [volume %0.2fdB; samples %d(%dms) x %d channel%s; wait %d(%dms); decay_factor %0.2fdB; decay_step %d(%dms); wrote %d bytes]\n",
+ ts->volume,
+ duration,
+ duration / (ts->rate / 1000),
+ ts->channels,
+ ts->channels == 1 ? "" : "s",
+ wait,
+ wait / (ts->rate / 1000),
+ ts->decay_factor,
+ ts->decay_step,
+ ts->decay_step / (ts->rate / 1000),
+ ts->samples * 2);
+ }
+ }
+ return ts->samples;
+}
+
+/* don't ask */
+static char *my_strdup (const char *s)
+{
+ size_t len = strlen (s) + 1;
+ void *new = malloc (len);
+
+ if (new == NULL) {
+ return NULL;
+ }
+
+ return (char *) memcpy (new, s, len);
+}
+
+TELETONE_API(int) teletone_run(teletone_generation_session_t *ts, const char *cmd)
+{
+ char *data = NULL, *cur = NULL, *end = NULL;
+ int var = 0, LOOPING = 0;
+
+ if (!cmd) {
+ return -1;
+ }
+
+ do {
+ if (!(data = my_strdup(cmd))) {
+ return -1;
+ }
+
+ cur = data;
+
+ while (*cur) {
+ var = 0;
+ if (*cur == ' ' || *cur == '\r' || *cur == '\n') {
+ cur++;
+ continue;
+ }
+
+ if ((end = strchr(cur, ';')) != 0) {
+ *end++ = '\0';
+ }
+
+ if (*(cur + 1) == '=') {
+ var = 1;
+ switch(*cur) {
+ case 'c':
+ ts->channels = atoi(cur + 2);
+ break;
+ case 'r':
+ ts->rate = atoi(cur + 2);
+ break;
+ case 'd':
+ ts->duration = atoi(cur + 2) * (ts->rate / 1000);
+ break;
+ case 'v':
+ {
+ float vol = (float)atof(cur + 2);
+ if (vol <= TELETONE_VOL_DB_MAX && vol >= TELETONE_VOL_DB_MIN) {
+ ts->volume = vol;
+ }
+ }
+ break;
+ case '>':
+ ts->decay_step = atoi(cur + 2) * (ts->rate / 1000);
+ ts->decay_direction = -1;
+ break;
+ case '<':
+ ts->decay_step = atoi(cur + 2) * (ts->rate / 1000);
+ ts->decay_direction = 1;
+ break;
+ case '+':
+ ts->decay_factor = (float)atof(cur + 2);
+ break;
+ case 'w':
+ ts->wait = atoi(cur + 2) * (ts->rate / 1000);
+ break;
+ case 'l':
+ ts->loops = atoi(cur + 2);
+ break;
+ case 'L':
+ if (!LOOPING) {
+ ts->LOOPS = atoi(cur + 2);
+ }
+ LOOPING++;
+ break;
+ }
+ } else {
+ while (*cur) {
+ char *p = NULL, *e = NULL;
+ teletone_tone_map_t mymap, *mapp = NULL;
+
+ if (*cur == ' ' || *cur == '\r' || *cur == '\n') {
+ cur++;
+ continue;
+ }
+
+ ts->tmp_duration = -1;
+ ts->tmp_wait = -1;
+
+ memset(&mymap, 0, sizeof(mymap));
+
+ if (*(cur + 1) == '(') {
+ p = cur + 2;
+ if (*cur) {
+ char *next;
+ int i = 0;
+ if ((e = strchr(p, ')')) != 0) {
+ *e++ = '\0';
+ }
+ do {
+ if ((next = strchr(p, ',')) != 0) {
+ *next++ = '\0';
+ }
+ if (i == 0) {
+ ts->tmp_duration = atoi(p) * (ts->rate / 1000);
+ i++;
+ } else if (i == 1) {
+ ts->tmp_wait = atoi(p) * (ts->rate / 1000);
+ i++;
+ } else {
+ mymap.freqs[i++ - 2] = atof(p);
+ }
+ p = next;
+
+ } while (next && (i-2) < TELETONE_MAX_TONES);
+ if (i > 2 && *cur == '%') {
+ mapp = &mymap;
+ } else if ((i != 2 || *cur == '%')) {
+ if (ts->debug && ts->debug_stream) {
+ fprintf(ts->debug_stream, "Syntax Error!\n");
+ }
+ goto bottom;
+ }
+ }
+ }
+
+ if (*cur && !mapp) {
+ if (*cur > 0 && *cur < TELETONE_TONE_RANGE) {
+ mapp = &ts->TONES[(int)*cur];
+ } else if (ts->debug && ts->debug_stream) {
+ fprintf(ts->debug_stream, "Map [%c] Out Of Range!\n", *cur);
+ }
+ }
+
+ if (mapp) {
+ if (mapp->freqs[0]) {
+ if (ts->handler) {
+ do {
+ ts->handler(ts, mapp);
+ if (ts->loops > 0) {
+ ts->loops--;
+ }
+ } while (ts->loops);
+ }
+ } else if (ts->debug && ts->debug_stream) {
+ fprintf(ts->debug_stream, "Ignoring Empty Map [%c]!\n", *cur);
+ }
+ }
+
+ if (e) {
+ cur = e;
+ } else {
+ cur++;
+ }
+ }
+ }
+
+ if (end) {
+ cur = end;
+ } else if (*cur){
+ cur++;
+ }
+ }
+ bottom:
+ free(data);
+ data = NULL;
+ if (ts->LOOPS > 0) {
+ ts->LOOPS--;
+ }
+
+ } while (ts->LOOPS);
+
+ return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/m3ua/mstm3ua.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/m3ua/mstm3ua.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/m3ua/mstm3ua.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,62 @@
+/* WARNING WORK IN PROGRESS
+ * mstm3ua.c
+ * mstss7d port
+ *
+ * Created by Shane Burrell on 2/2/08.
+ * Copyright 2008 Shane Burrell. 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.
+ */
+
+#include "mstm3ua.h"
+
+
+
+
+
+int build_m3ua_hdr(unsigned char len,unsigned char *bytemsg)
+
+{
+
+ *bytemsg++ = M_VERSION_REL1; // 1 Verison
+ //bytemsg[1] = 0x00; // 2 RESERVED
+ //bytemsg[2] = M_CLASS_XFER; // 3 Msg Class
+ //SS7 BOX Kludge
+ *bytemsg++ = 0x01; // 2 RESERVED
+ *bytemsg++ = 0x00; // 2 RESERVED
+
+ *bytemsg++ = M_TYPE_DATA ; // 4 Msg Type
+
+ *bytemsg++ = len; // 5 Msg LENGTH 81 32bit field
+ *bytemsg++ = 0x00; // 6
+ *bytemsg++ = 0x00; // 7
+ *bytemsg++ = 0x00; // 8
+ return(0);
+
+};
\ No newline at end of file
Added: freeswitch/trunk/libs/openzap/src/m3ua/mstm3ua.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/m3ua/mstm3ua.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/m3ua/mstm3ua.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,96 @@
+/*
+ * mstm3ua.h
+ * mstss7d
+ *
+ * Created by Shane Burrell on 3/2/08.
+ * Copyright 2008 Shane Burrell. 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.
+ */
+typedef unsigned long m3ua_ulong;
+typedef unsigned short m3ua_ushort;
+typedef unsigned char m3ua_uchar;
+
+typedef unsigned char u8;
+typedef unsigned short u16; /* Note: multi-byte values are little-endian */
+typedef unsigned long u32;
+
+
+
+
+#define M_TAG_NETWORK_APPEARANCE 1
+#define M_TAG_PROTOCOL_DATA 3
+#define M_TAG_INFO_STRING 4
+#define M_TAG_AFFECTED_DPC 5
+#define M_TAG_ROUTING_CONTEXT 6
+#define M_TAG_DIAGNOSTIC_INFORMATION 7
+#define M_TAG_HEARTBEAT_DATA 8
+#define M_TAG_UNAVAILABILITY_CAUSE 9
+#define M_TAG_REASON 10
+#define M_TAG_TRAFFIC_MODE_TYPE 11
+#define M_TAG_ERROR_CODE 12
+#define M_TAG_STATUS_TYPE 13
+#define M_TAG_CONGESTED_INDICATIONS 14
+
+#define M_VERSION_REL1 1
+
+#define M_CLASS_MGMT 0x00
+#define M_CLASS_XFER 0x01
+#define M_CLASS_SSNM 0x02
+#define M_CLASS_ASPSM 0x03
+#define M_CLASS_ASPTM 0x04
+#define M_CLASS_RKM 0x09
+
+#define M_TYPE_ERR (0|M_CLASS_MGMT
+
+#define M_TYPE_NTFY (1|M_CLASS_XFER)
+#define M_TYPE_DATA (1|M_CLASS_XFER)
+
+#define M_TYPE_DUNA (1|M_CLASS_SSNM)
+#define M_TYPE_DAVA (2|M_CLASS_SSNM)
+#define M_TYPE_DUAD (3|M_CLASS_SSNM)
+#define M_TYPE_SCON (4|M_CLASS_SSNM)
+#define M_TYPE_DUPU (5|M_CLASS_SSNM)
+
+#define M_TYPE_UP (1|M_CLASS_ASPSM)
+#define M_TYPE_DOWN (2|M_CLASS_ASPSM)
+#define M_TYPE_BEAT (3|M_CLASS_ASPSM)
+#define M_TYPE_UP_ACK (4|M_CLASS_ASPSM)
+#define M_TYPE_DOWN_ACK (5|M_CLASS_ASPSM)
+#define M_TYPE_BEAT_ACK (6|M_CLASS_ASPSM)
+
+#define M_TYPE_ACTIVE (1|M_CLASS_ASPTM)
+#define M_TYPE_INACTIVE (2|M_CLASS_ASPTM)
+#define M_TYPE_ACTIVE_ACK (3|M_CLASS_ASPTM)
+#define M_TYPE_INACTIVE_ACK (4|M_CLASS_ASPTM)
+
+#define M_CLASS_MASK 0xff00
+#define M_TYPE_MASK 0x00ff
+
Added: freeswitch/trunk/libs/openzap/src/m3ua_client.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/m3ua_client.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/m3ua_client.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,333 @@
+/*
+ * m3ua_client.c
+ * openzap
+ *
+ * Created by Shane Burrell on 4/3/08.
+ * Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ *
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ * 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.
+ */
+
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include "openzap.h"
+#include <m3ua_client.h>
+
+
+#ifndef HAVE_GETHOSTBYNAME_R
+extern int gethostbyname_r (const char *__name,
+ struct hostent *__result_buf,
+ char *__buf, size_t __buflen,
+ struct hostent **__result,
+ int *__h_errnop);
+#endif
+
+struct m3uac_map {
+ uint32_t event_id;
+ const char *name;
+};
+
+static struct m3uac_map m3uac_table[] = {
+ {M3UA_EVENT_CALL_START, "CALL_START"},
+ {M3UA_EVENT_CALL_START_ACK, "CALL_START_ACK"},
+ {M3UA_EVENT_CALL_START_NACK, "CALL_START_NACK"},
+ {M3UA_EVENT_CALL_START_NACK_ACK, "CALL_START_NACK_ACK"},
+ {M3UA_EVENT_CALL_ANSWERED, "CALL_ANSWERED"},
+ {M3UA_EVENT_CALL_STOPPED, "CALL_STOPPED"},
+ {M3UA_EVENT_CALL_STOPPED_ACK, "CALL_STOPPED_ACK"},
+ {M3UA_EVENT_SYSTEM_RESTART, "SYSTEM_RESTART"},
+ {M3UA_EVENT_SYSTEM_RESTART_ACK, "SYSTEM_RESTART_ACK"},
+ {M3UA_EVENT_HEARTBEAT, "HEARTBEAT"},
+ {M3UA_EVENT_INSERT_CHECK_LOOP, "LOOP START"},
+ {M3UA_EVENT_REMOVE_CHECK_LOOP, "LOOP STOP"}
+};
+
+
+
+static int create_conn_socket(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
+{
+ int rc;
+ struct hostent *result, *local_result;
+ char buf[512], local_buf[512];
+ int err = 0;
+
+ memset(&mcon->remote_hp, 0, sizeof(mcon->remote_hp));
+ memset(&mcon->local_hp, 0, sizeof(mcon->local_hp));
+ mcon->socket = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+ zap_log(ZAP_LOG_DEBUG, "Creating L=%s:%d R=%s:%d\n",
+ local_ip,local_port,ip,port);
+
+ if (mcon->socket >= 0) {
+ int flag;
+
+ flag = 1;
+ gethostbyname_r(ip, &mcon->remote_hp, buf, sizeof(buf), &result, &err);
+ gethostbyname_r(local_ip, &mcon->local_hp, local_buf, sizeof(local_buf), &local_result, &err);
+ if (result && local_result) {
+ mcon->remote_addr.sin_family = mcon->remote_hp.h_addrtype;
+ memcpy((char *) &mcon->remote_addr.sin_addr.s_addr, mcon->remote_hp.h_addr_list[0], mcon->remote_hp.h_length);
+ mcon->remote_addr.sin_port = htons(port);
+
+ mcon->local_addr.sin_family = mcon->local_hp.h_addrtype;
+ memcpy((char *) &mcon->local_addr.sin_addr.s_addr, mcon->local_hp.h_addr_list[0], mcon->local_hp.h_length);
+ mcon->local_addr.sin_port = htons(local_port);
+
+
+ setsockopt(mcon->socket, IPPROTO_SCTP, SCTP_NODELAY, (char *)&flag, sizeof(int));
+
+ rc=listen(mcon->socket,100);
+ if (rc) {
+ close(mcon->socket);
+ mcon->socket = -1;
+
+ }
+ }
+ }
+
+ zap_mutex_create(&mcon->mutex);
+
+ return mcon->socket;
+}
+
+int m3uac_connection_close(m3uac_connection_t *mcon)
+{
+ if (mcon->socket > -1) {
+ close(mcon->socket);
+ }
+
+ zap_mutex_lock(mcon->mutex);
+ zap_mutex_unlock(mcon->mutex);
+ zap_mutex_destroy(&mcon->mutex);
+ memset(mcon, 0, sizeof(*mcon));
+ mcon->socket = -1;
+
+ return 0;
+}
+
+int m3uac_connection_open(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
+{
+ create_conn_socket(mcon, local_ip, local_port, ip, port);
+ return mcon->socket;
+}
+
+
+int m3uac_exec_command(m3uac_connection_t *mcon, int span, int chan, int id, int cmd, int cause)
+{
+ m3uac_event_t oevent;
+ int retry = 5;
+
+ m3uac_event_init(&oevent, cmd, chan, span);
+ oevent.release_cause = cause;
+
+ if (cmd == SIGBOOST_EVENT_SYSTEM_RESTART) {
+ mcon->rxseq_reset = 1;
+ mcon->txseq = 0;
+ mcon->rxseq = 0;
+ mcon->txwindow = 0;
+ }
+
+ if (id >= 0) {
+ oevent.call_setup_id = id;
+ }
+
+ while (m3uac_connection_write(mcon, &oevent) <= 0) {
+ if (--retry <= 0) {
+ zap_log(ZAP_LOG_CRIT, "Failed to tx on M3UA socket: %s\n", strerror(errno));
+ return -1;
+ } else {
+ zap_log(ZAP_LOG_WARNING, "Failed to tx on M3UA socket: %s :retry %i\n", strerror(errno), retry);
+ zap_sleep(1);
+ }
+ }
+
+ return 0;
+}
+
+
+
+m3uac_event_t *m3uac_connection_read(m3uac_connection_t *mcon, int iteration)
+{
+ unsigned int fromlen = sizeof(struct sockaddr_in);
+ int bytes = 0;
+
+ bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT,
+ (struct sockaddr *) &mcon->local_addr, &fromlen);
+
+ if (bytes == sizeof(mcon->event) || bytes == (sizeof(mcon->event)-sizeof(uint32_t))) {
+
+ if (mcon->rxseq_reset) {
+ if (mcon->event.event_id == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
+ zap_log(ZAP_LOG_DEBUG, "Rx sync ok\n");
+ mcon->rxseq = mcon->event.fseqno;
+ return &mcon->event;
+ }
+ errno=EAGAIN;
+ zap_log(ZAP_LOG_DEBUG, "Waiting for rx sync...\n");
+ return NULL;
+ }
+
+ mcon->txwindow = mcon->txseq - mcon->event.bseqno;
+ mcon->rxseq++;
+
+ if (mcon->rxseq != mcon->event.fseqno) {
+ zap_log(ZAP_LOG_CRIT, "Invalid Sequence Number Expect=%i Rx=%i\n", mcon->rxseq, mcon->event.fseqno);
+ return NULL;
+ }
+
+ return &mcon->event;
+ } else {
+ if (iteration == 0) {
+ zap_log(ZAP_LOG_CRIT, "Invalid Event length from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+m3uac_event_t *m3uac_connection_readp(m3uac_connection_t *mcon, int iteration)
+{
+ unsigned int fromlen = sizeof(struct sockaddr_in);
+ int bytes = 0;
+
+ bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT, (struct sockaddr *) &mcon->local_addr, &fromlen);
+
+ if (bytes == sizeof(mcon->event) || bytes == (sizeof(mcon->event)-sizeof(uint32_t))) {
+ return &mcon->event;
+ } else {
+ if (iteration == 0) {
+ zap_log(ZAP_LOG_CRIT, "Critical Error: PQ Invalid Event lenght from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+
+int m3uac_connection_write(m3uac_connection_t *mcon, ss7bc_event_t *event)
+{
+ int err;
+
+ if (!event || mcon->socket < 0 || !mcon->mutex) {
+ zap_log(ZAP_LOG_DEBUG, "Critical Error: No Event Device\n");
+ return -EINVAL;
+ }
+
+ if (event->span > 16 || event->chan > 31) {
+ zap_log(ZAP_LOG_CRIT, "Critical Error: TX Cmd=%s Invalid Span=%i Chan=%i\n", m3uac_event_id_name(event->event_id), event->span,event->chan);
+ return -1;
+ }
+
+ gettimeofday(&event->tv,NULL);
+
+ zap_mutex_lock(mcon->mutex);
+ event->fseqno = mcon->txseq++;
+ event->bseqno = mcon->rxseq;
+ err = sendto(mcon->socket, event, sizeof(m3uac_event_t), 0, (struct sockaddr *) &mcon->remote_addr, sizeof(mcon->remote_addr));
+ zap_mutex_unlock(mcon->mutex);
+
+ if (err != sizeof(m3uac_event_t)) {
+ err = -1;
+ }
+
+ zap_log(ZAP_LOG_DEBUG, "TX EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n",
+ m3uac_event_id_name(event->event_id),
+ event->event_id,
+ event->span+1,
+ event->chan+1,
+ event->release_cause,
+ event->call_setup_id,
+ event->fseqno,
+ (event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
+ (event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A")
+ );
+
+ return err;
+}
+
+void m3uac_call_init(m3uac_event_t *event, const char *calling, const char *called, int setup_id)
+{
+ memset(event, 0, sizeof(m3uac_event_t));
+ event->event_id = M3UA_EVENT_CALL_START;
+
+ if (calling) {
+ strncpy((char*)event->calling_number_digits, calling, sizeof(event->calling_number_digits)-1);
+ event->calling_number_digits_count = strlen(calling);
+ }
+
+ if (called) {
+ strncpy((char*)event->called_number_digits, called, sizeof(event->called_number_digits)-1);
+ event->called_number_digits_count = strlen(called);
+ }
+
+ event->call_setup_id = setup_id;
+
+}
+
+void m3uac_event_init(m3uac_event_t *event, m3uac_event_id_t event_id, int chan, int span)
+{
+ memset(event, 0, sizeof(ss7bc_event_t));
+ event->event_id = event_id;
+ event->chan = chan;
+ event->span = span;
+}
+
+const char *m3uac_event_id_name(uint32_t event_id)
+{
+ unsigned int x;
+ const char *ret = NULL;
+
+ for (x = 0 ; x < sizeof(m3uac_table)/sizeof(struct m3uac_map); x++) {
+ if (m3uac_table[x].event_id == event_id) {
+ ret = m3uac_table[x].name;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
+
Added: freeswitch/trunk/libs/openzap/src/m3ua_client.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/m3ua_client.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/m3ua_client.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,164 @@
+/*
+ * m3ua_client.h
+ * openzap
+ *
+ * Created by Shane Burrell on 4/3/08.
+ * Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ *
+ * 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.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+// Fix this for portability
+#include <sctp.h>
+//#include <netinet/sctp.h>
+#include <arpa/inet.h>
+#include <stdarg.h>
+#include <netdb.h>
+//#include <sigboost.h>
+#include <sys/time.h>
+
+#define MAX_DIALED_DIGITS 31
+#define MAX_CALLING_NAME 31
+
+/* Next two defines are used to create the range of values for call_setup_id
+ * in the t_sigboost structure.
+ * 0..((CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN) - 1) */
+#define CORE_MAX_SPANS 200
+#define CORE_MAX_CHAN_PER_SPAN 30
+#define MAX_PENDING_CALLS CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN
+/* 0..(MAX_PENDING_CALLS-1) is range of call_setup_id below */
+#define SIZE_RDNIS 80
+
+//#undef MSGWINDOW
+#define MSGWINDOW
+
+
+typedef struct
+{
+ uint32_t event_id;
+ uint32_t fseqno;
+#ifdef MSGWINDOW
+ uint32_t bseqno;
+#endif
+ uint16_t call_setup_id;
+ uint32_t trunk_group;
+ uint32_t span;
+ uint32_t chan;
+ uint8_t called_number_digits_count;
+ char called_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
+ uint8_t calling_number_digits_count; /* it's an array */
+ char calling_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
+ uint8_t release_cause;
+ struct timeval tv;
+ /* ref. Q.931 Table 4-11 and Q.951 Section 3 */
+ uint8_t calling_number_screening_ind;
+ uint8_t calling_number_presentation;
+ char redirection_string [SIZE_RDNIS]; /* it's a null terminated string */
+
+} t_m3ua;
+
+typedef t_m3ua m3uac_event_t;
+typedef uint32_t m3uac_event_id_t;
+
+
+typedef struct m3uac_ip_cfg
+{
+ char local_ip[25];
+ int local_port;
+ char remote_ip[25];
+ int remote_port;
+}m3uac_ip_cfg_t;
+
+struct m3uac_connection {
+ zap_socket_t socket;
+ struct sockaddr_in local_addr;
+ struct sockaddr_in remote_addr;
+ m3uac_event_t event;
+ struct hostent remote_hp;
+ struct hostent local_hp;
+ unsigned int flags;
+ zap_mutex_t *mutex;
+ FILE *log;
+ unsigned int txseq;
+ unsigned int rxseq;
+ unsigned int txwindow;
+ unsigned int rxseq_reset;
+ m3uac_ip_cfg_t cfg;
+ uint32_t hb_elapsed;
+ int up;
+};
+
+typedef enum {
+ MSU_FLAG_EVENT = (1 << 0)
+} m3uac_flag_t;
+
+typedef struct m3uac_connection m3uac_connection_t;
+
+static inline void sctp_no_nagle(int socket)
+{
+ //int flag = 1;
+ //setsockopt(socket, IPPROTO_SCTP, SCTP_NODELAY, (char *) &flag, sizeof(int));
+}
+
+int m3uac_connection_close(m3uac_connection_t *mcon);
+int m3uac_connection_open(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port);
+m3uac_event_t *m3uac_connection_read(m3uac_connection_t *mcon, int iteration);
+m3uac_event_t *m3uac_connection_readp(m3uac_connection_t *mcon, int iteration);
+int m3uac_connection_write(m3uac_connection_t *mcon, m3uac_event_t *event);
+void m3uac_event_init(m3uac_event_t *event, m3uac_event_id_t event_id, int chan, int span);
+void m3uac_call_init(m3uac_event_t *event, const char *calling, const char *called, int setup_id);
+const char *m3uac_event_id_name(uint32_t event_id);
+int m3uac_exec_command(m3uac_connection_t *mcon, int span, int chan, int id, int cmd, int cause);
+
+
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.2005.vcproj (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.2005.vcproj (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.2005.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ozmod_analog"
+ ProjectGUID="{37C94798-6E33-4B4F-8EE0-C72A7DC91157}"
+ RootNamespace="ozmod_analog"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="ozmod_analog.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="zap_analog.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,353 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="ozmod_analog"
+ ProjectGUID="{37C94798-6E33-4B4F-8EE0-C72A7DC91157}"
+ RootNamespace="ozmod_analog"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="ozmod_analog.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="zap_analog.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1012 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#include "openzap.h"
+#include "zap_analog.h"
+
+#ifndef localtime_r
+struct tm * localtime_r(const time_t *clock, struct tm *result);
+#endif
+
+static void *zap_analog_channel_run(zap_thread_t *me, void *obj);
+
+/**
+ * \brief Starts an FXO channel thread (outgoing call)
+ * \param zchan Channel to initiate call on
+ * \return Success or failure
+ *
+ * Initialises state, starts tone progress detection and runs the channel in a new a thread.
+ */
+static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxo_outgoing_call)
+{
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
+ zap_channel_clear_needed_tones(zchan);
+ zap_channel_clear_detected_tones(zchan);
+
+ zap_channel_command(zchan, ZAP_COMMAND_OFFHOOK, NULL);
+ zap_channel_command(zchan, ZAP_COMMAND_ENABLE_PROGRESS_DETECT, NULL);
+ zchan->needed_tones[ZAP_TONEMAP_DIAL] = 1;
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DIALING);
+ zap_thread_create_detached(zap_analog_channel_run, zchan);
+ return ZAP_SUCCESS;
+ }
+
+ return ZAP_FAIL;
+}
+
+/**
+ * \brief Starts an FXS channel thread (outgoing call)
+ * \param zchan Channel to initiate call on
+ * \return Success or failure
+ *
+ * Indicates call waiting if channel is already in use, otherwise runs the channel in a new thread.
+ */
+static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxs_outgoing_call)
+{
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_CALLWAITING);
+ } else {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_GENRING);
+ zap_thread_create_detached(zap_analog_channel_run, zchan);
+ }
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Starts an analog span thread (monitor)
+ * \param span Span to monitor
+ * \return Success or failure
+ */
+static zap_status_t zap_analog_start(zap_span_t *span)
+{
+ zap_analog_data_t *analog_data = span->signal_data;
+ zap_set_flag(analog_data, ZAP_ANALOG_RUNNING);
+ return zap_thread_create_detached(zap_analog_run, span);
+}
+
+/**
+ * \brief Initialises an analog span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static ZIO_SIG_CONFIGURE_FUNCTION(zap_analog_configure_span)
+//zap_status_t zap_analog_configure_span(zap_span_t *span, char *tonemap, uint32_t digit_timeout, uint32_t max_dialstr, zio_signal_cb_t sig_cb)
+{
+ zap_analog_data_t *analog_data;
+ const char *tonemap = "us";
+ const char *hotline = "";
+ uint32_t digit_timeout = 10;
+ uint32_t max_dialstr = MAX_DTMF;
+ const char *var, *val;
+ int *intval;
+ uint32_t flags = ZAP_ANALOG_CALLERID;
+
+ assert(sig_cb != NULL);
+
+ if (span->signal_type) {
+ snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
+ return ZAP_FAIL;
+ }
+
+ analog_data = malloc(sizeof(*analog_data));
+ assert(analog_data != NULL);
+ memset(analog_data, 0, sizeof(*analog_data));
+
+ while ((var = va_arg(ap, char *))) {
+ if (!strcasecmp(var, "tonemap")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ tonemap = val;
+ } else if (!strcasecmp(var, "digit_timeout")) {
+ if (!(intval = va_arg(ap, int *))) {
+ break;
+ }
+ digit_timeout = *intval;
+ } else if (!strcasecmp(var, "enable_callerid")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+
+ if (zap_true(val)) {
+ flags |= ZAP_ANALOG_CALLERID;
+ } else {
+ flags &= ~ZAP_ANALOG_CALLERID;
+ }
+ } else if (!strcasecmp(var, "max_dialstr")) {
+ if (!(intval = va_arg(ap, int *))) {
+ break;
+ }
+ max_dialstr = *intval;
+ } else if (!strcasecmp(var, "hotline")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ hotline = val;
+ } else {
+ snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+ return ZAP_FAIL;
+ }
+ }
+
+
+ if (digit_timeout < 2000 || digit_timeout > 10000) {
+ digit_timeout = 2000;
+ }
+
+ if ((max_dialstr < 1 && !strlen(hotline)) || max_dialstr > MAX_DTMF) {
+ max_dialstr = MAX_DTMF;
+ }
+
+ span->start = zap_analog_start;
+ analog_data->flags = flags;
+ analog_data->digit_timeout = digit_timeout;
+ analog_data->max_dialstr = max_dialstr;
+ span->signal_cb = sig_cb;
+ strncpy(analog_data->hotline, hotline, sizeof(analog_data->hotline));
+ span->signal_type = ZAP_SIGTYPE_ANALOG;
+ span->signal_data = analog_data;
+ span->outgoing_call = span->trunk_type == ZAP_TRUNK_FXS ? analog_fxs_outgoing_call : analog_fxo_outgoing_call;
+ zap_span_load_tones(span, tonemap);
+
+ return ZAP_SUCCESS;
+
+}
+
+/**
+ * \brief Retrieves tone generation output to be sent
+ * \param ts Teletone generator
+ * \param map Tone map
+ * \return -1 on error, 0 on success
+ */
+static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+ zap_buffer_t *dt_buffer = ts->user_data;
+ int wrote;
+
+ if (!dt_buffer) {
+ return -1;
+ }
+ wrote = teletone_mux_tones(ts, map);
+ zap_buffer_write(dt_buffer, ts->buffer, wrote * 2);
+ return 0;
+}
+
+/**
+ * \brief Sends caller id on an analog channel (FSK coded)
+ * \param zchan Channel to send caller id on
+ */
+static void send_caller_id(zap_channel_t *zchan)
+{
+ zap_fsk_data_state_t fsk_data;
+ uint8_t databuf[1024] = "";
+ char time_str[9];
+ struct tm tm;
+ time_t now;
+ zap_mdmf_type_t mt = MDMF_INVALID;
+
+ time(&now);
+#ifdef WIN32
+ _tzset();
+ _localtime64_s(&tm, &now);
+#else
+ localtime_r(&now, &tm);
+#endif
+ strftime(time_str, sizeof(time_str), "%m%d%H%M", &tm);
+
+ zap_fsk_data_init(&fsk_data, databuf, sizeof(databuf));
+ zap_fsk_data_add_mdmf(&fsk_data, MDMF_DATETIME, (uint8_t *) time_str, 8);
+
+ if (zap_strlen_zero(zchan->caller_data.cid_num.digits)) {
+ mt = MDMF_NO_NUM;
+ zap_set_string(zchan->caller_data.cid_num.digits, "O");
+ } else if (!strcasecmp(zchan->caller_data.cid_num.digits, "P") || !strcasecmp(zchan->caller_data.cid_num.digits, "O")) {
+ mt = MDMF_NO_NUM;
+ } else {
+ mt = MDMF_PHONE_NUM;
+ }
+ zap_fsk_data_add_mdmf(&fsk_data, mt, (uint8_t *) zchan->caller_data.cid_num.digits, (uint8_t)strlen(zchan->caller_data.cid_num.digits));
+
+ if (zap_strlen_zero(zchan->caller_data.cid_name)) {
+ mt = MDMF_NO_NAME;
+ zap_set_string(zchan->caller_data.cid_name, "O");
+ } else if (!strcasecmp(zchan->caller_data.cid_name, "P") || !strcasecmp(zchan->caller_data.cid_name, "O")) {
+ mt = MDMF_NO_NAME;
+ } else {
+ mt = MDMF_PHONE_NAME;
+ }
+ zap_fsk_data_add_mdmf(&fsk_data, mt, (uint8_t *) zchan->caller_data.cid_name, (uint8_t)strlen(zchan->caller_data.cid_name));
+
+ zap_fsk_data_add_checksum(&fsk_data);
+ zap_channel_send_fsk_data(zchan, &fsk_data, -14);
+}
+
+/**
+ * \brief Main thread function for analog channel (outgoing call)
+ * \param me Current thread
+ * \param obj Channel to run in this thread
+ */
+static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
+{
+ zap_channel_t *zchan = (zap_channel_t *) obj;
+ zap_buffer_t *dt_buffer = NULL;
+ teletone_generation_session_t ts;
+ uint8_t frame[1024];
+ zap_size_t len, rlen;
+ zap_tone_type_t tt = ZAP_TONE_DTMF;
+ char dtmf[MAX_DTMF+1] = "";
+ zap_size_t dtmf_offset = 0;
+ zap_analog_data_t *analog_data = zchan->span->signal_data;
+ zap_channel_t *closed_chan;
+ uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = 30000;
+ zap_sigmsg_t sig;
+ zap_status_t status;
+
+ zap_log(ZAP_LOG_DEBUG, "ANALOG CHANNEL thread starting.\n");
+
+ ts.buffer = NULL;
+
+ if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "OPEN ERROR [%s]\n", zchan->last_error);
+ goto done;
+ }
+
+ if (zap_buffer_create(&dt_buffer, 1024, 3192, 0) != ZAP_SUCCESS) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "memory error!");
+ zap_log(ZAP_LOG_ERROR, "MEM ERROR\n");
+ goto done;
+ }
+
+ if (zap_channel_command(zchan, ZAP_COMMAND_ENABLE_DTMF_DETECT, &tt) != ZAP_SUCCESS) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "error initilizing tone detector!");
+ zap_log(ZAP_LOG_ERROR, "TONE ERROR\n");
+ goto done;
+ }
+
+ zap_set_flag_locked(zchan, ZAP_CHANNEL_INTHREAD);
+ teletone_init_session(&ts, 0, teletone_handler, dt_buffer);
+ ts.rate = 8000;
+#if 0
+ ts.debug = 1;
+ ts.debug_stream = stdout;
+#endif
+ zap_channel_command(zchan, ZAP_COMMAND_GET_INTERVAL, &interval);
+ zap_buffer_set_loops(dt_buffer, -1);
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = zchan->chan_id;
+ sig.span_id = zchan->span_id;
+ sig.channel = zchan;
+
+ assert(interval != 0);
+
+ while (zap_running() && zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
+ zap_wait_flag_t flags = ZAP_READ;
+ zap_size_t dlen = 0;
+
+ len = sizeof(frame);
+
+ elapsed += interval;
+ state_counter += interval;
+
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_STATE_CHANGE)) {
+ switch(zchan->state) {
+ case ZAP_CHANNEL_STATE_GET_CALLERID:
+ {
+ if (state_counter > 5000 || !zap_test_flag(zchan, ZAP_CHANNEL_CALLERID_DETECT)) {
+ zap_channel_command(zchan, ZAP_COMMAND_DISABLE_CALLERID_DETECT, NULL);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_IDLE);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_DIALING:
+ {
+ if (state_counter > dial_timeout) {
+ if (zchan->needed_tones[ZAP_TONEMAP_DIAL]) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+ } else {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
+ }
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_GENRING:
+ {
+ if (state_counter > 60000) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ } else if (!zchan->fsk_buffer || !zap_buffer_inuse(zchan->fsk_buffer)) {
+ zap_sleep(interval);
+ continue;
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_DIALTONE:
+ {
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_HOLD) && state_counter > 10000) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_BUSY:
+ {
+ if (state_counter > 20000) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_ATTN);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_ATTN:
+ {
+ if (state_counter > 20000) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_HANGUP:
+ {
+ if (state_counter > 500) {
+ if (zap_test_flag(zchan, ZAP_CHANNEL_RINGING)) {
+ zap_channel_command(zchan, ZAP_COMMAND_GENERATE_RING_OFF, NULL);
+ }
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) &&
+ (zchan->last_state == ZAP_CHANNEL_STATE_RING || zchan->last_state == ZAP_CHANNEL_STATE_DIALTONE
+ || zchan->last_state >= ZAP_CHANNEL_STATE_IDLE)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+ } else {
+ zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_CLEARING;
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ }
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_CALLWAITING:
+ {
+ int done = 0;
+
+ if (zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK] == 1) {
+ send_caller_id(zchan);
+ zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]++;
+ } else if (state_counter > 600 && !zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]) {
+ send_caller_id(zchan);
+ zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]++;
+ } else if (state_counter > 1000 && !zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]) {
+ done = 1;
+ } else if (state_counter > 10000) {
+ if (zchan->fsk_buffer) {
+ zap_buffer_zero(zchan->fsk_buffer);
+ } else {
+ zap_buffer_create(&zchan->fsk_buffer, 128, 128, 0);
+ }
+
+ ts.user_data = zchan->fsk_buffer;
+ teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_CALLWAITING_SAS]);
+ ts.user_data = dt_buffer;
+ done = 1;
+ }
+
+ if (done) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_STATE_CHANGE);
+ zap_clear_flag_locked(zchan->span, ZAP_SPAN_STATE_CHANGE);
+ zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK] = 0;
+ }
+ }
+ case ZAP_CHANNEL_STATE_UP:
+ case ZAP_CHANNEL_STATE_IDLE:
+ {
+ zap_sleep(interval);
+ continue;
+ }
+ break;
+ case ZAP_CHANNEL_STATE_DOWN:
+ {
+ goto done;
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_STATE_CHANGE);
+ zap_clear_flag_locked(zchan->span, ZAP_SPAN_STATE_CHANGE);
+ zap_channel_complete_state(zchan);
+ indicate = 0;
+ state_counter = 0;
+
+ zap_log(ZAP_LOG_DEBUG, "Executing state handler on %d:%d for %s\n",
+ zchan->span_id, zchan->chan_id,
+ zap_channel_state2str(zchan->state));
+ switch(zchan->state) {
+ case ZAP_CHANNEL_STATE_UP:
+ {
+ zap_channel_use(zchan);
+ zap_channel_clear_needed_tones(zchan);
+ zap_channel_flush_dtmf(zchan);
+
+ if (zchan->type == ZAP_CHAN_TYPE_FXO && !zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK)) {
+ zap_channel_command(zchan, ZAP_COMMAND_OFFHOOK, NULL);
+ }
+
+ if (zchan->fsk_buffer && zap_buffer_inuse(zchan->fsk_buffer)) {
+ zap_log(ZAP_LOG_DEBUG, "Cancel FSK transmit due to early answer.\n");
+ zap_buffer_zero(zchan->fsk_buffer);
+ }
+
+ if (zchan->type == ZAP_CHAN_TYPE_FXS && zap_test_flag(zchan, ZAP_CHANNEL_RINGING)) {
+ zap_channel_command(zchan, ZAP_COMMAND_GENERATE_RING_OFF, NULL);
+ }
+
+ if (zchan->token_count == 1) {
+ zap_clear_flag(zchan, ZAP_CHANNEL_HOLD);
+ }
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_HOLD)) {
+ zap_clear_flag(zchan, ZAP_CHANNEL_HOLD);
+ sig.event_id = ZAP_SIGEVENT_ADD_CALL;
+ } else {
+ sig.event_id = ZAP_SIGEVENT_UP;
+ }
+
+ zap_span_send_signal(zchan->span, &sig);
+ continue;
+ }
+ break;
+ case ZAP_CHANNEL_STATE_DIALING:
+ {
+ zap_channel_use(zchan);
+ }
+ break;
+ case ZAP_CHANNEL_STATE_IDLE:
+ {
+ zap_channel_use(zchan);
+ sig.event_id = ZAP_SIGEVENT_START;
+
+ if (zchan->type == ZAP_CHAN_TYPE_FXO) {
+ zap_set_string(zchan->caller_data.dnis.digits, zchan->chan_number);
+ } else {
+ zap_set_string(zchan->caller_data.dnis.digits, dtmf);
+ }
+
+ zap_span_send_signal(zchan->span, &sig);
+ continue;
+ }
+ break;
+ case ZAP_CHANNEL_STATE_DOWN:
+ {
+ sig.event_id = ZAP_SIGEVENT_STOP;
+ zap_span_send_signal(zchan->span, &sig);
+ goto done;
+ }
+ break;
+ case ZAP_CHANNEL_STATE_DIALTONE:
+ {
+ memset(&zchan->caller_data, 0, sizeof(zchan->caller_data));
+ *dtmf = '\0';
+ dtmf_offset = 0;
+ zap_buffer_zero(dt_buffer);
+ teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_DIAL]);
+ indicate = 1;
+ }
+ break;
+ case ZAP_CHANNEL_STATE_CALLWAITING:
+ {
+ zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK] = 0;
+ if (zchan->fsk_buffer) {
+ zap_buffer_zero(zchan->fsk_buffer);
+ } else {
+ zap_buffer_create(&zchan->fsk_buffer, 128, 128, 0);
+ }
+
+ ts.user_data = zchan->fsk_buffer;
+ teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_CALLWAITING_SAS]);
+ teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_CALLWAITING_CAS]);
+ ts.user_data = dt_buffer;
+ }
+ break;
+ case ZAP_CHANNEL_STATE_GENRING:
+ {
+ zap_sigmsg_t sig;
+
+ send_caller_id(zchan);
+ zap_channel_command(zchan, ZAP_COMMAND_GENERATE_RING_ON, NULL);
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = zchan->chan_id;
+ sig.span_id = zchan->span_id;
+ sig.channel = zchan;
+ sig.event_id = ZAP_SIGEVENT_PROGRESS;
+ zap_span_send_signal(zchan->span, &sig);
+
+ }
+ break;
+ case ZAP_CHANNEL_STATE_GET_CALLERID:
+ {
+ memset(&zchan->caller_data, 0, sizeof(zchan->caller_data));
+ zap_channel_command(zchan, ZAP_COMMAND_ENABLE_CALLERID_DETECT, NULL);
+ continue;
+ }
+ break;
+ case ZAP_CHANNEL_STATE_RING:
+ {
+ zap_buffer_zero(dt_buffer);
+ teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_RING]);
+ indicate = 1;
+
+ }
+ break;
+ case ZAP_CHANNEL_STATE_BUSY:
+ {
+ zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+ if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ zap_buffer_zero(dt_buffer);
+ teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_BUSY]);
+ indicate = 1;
+ } else {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_ATTN:
+ {
+ if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ zap_buffer_zero(dt_buffer);
+ teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_ATTN]);
+ indicate = 1;
+ } else {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+
+ if (zchan->state == ZAP_CHANNEL_STATE_DIALTONE || zchan->state == ZAP_CHANNEL_STATE_COLLECT) {
+ if ((dlen = zap_channel_dequeue_dtmf(zchan, dtmf + dtmf_offset, sizeof(dtmf) - strlen(dtmf)))) {
+
+ if (zchan->state == ZAP_CHANNEL_STATE_DIALTONE) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_COLLECT);
+ collecting = 1;
+ }
+ dtmf_offset = strlen(dtmf);
+ last_digit = elapsed;
+ sig.event_id = ZAP_SIGEVENT_COLLECTED_DIGIT;
+ sig.raw_data = dtmf;
+ if (zap_span_send_signal(zchan->span, &sig) == ZAP_BREAK) {
+ collecting = 0;
+ }
+ }
+ else if(!analog_data->max_dialstr)
+ {
+ last_digit = elapsed;
+ collecting = 0;
+ strcpy(dtmf, analog_data->hotline);
+ }
+ }
+
+
+ if (last_digit && (!collecting || ((elapsed - last_digit > analog_data->digit_timeout) || strlen(dtmf) >= analog_data->max_dialstr))) {
+ zap_log(ZAP_LOG_DEBUG, "Number obtained [%s]\n", dtmf);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_IDLE);
+ last_digit = 0;
+ collecting = 0;
+ }
+
+ if (zap_channel_wait(zchan, &flags, interval * 2) != ZAP_SUCCESS) {
+ continue;
+ }
+
+ if (!(flags & ZAP_READ)) {
+ continue;
+ }
+
+ if (zap_channel_read(zchan, frame, &len) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "READ ERROR [%s]\n", zchan->last_error);
+ goto done;
+ }
+
+ if (zchan->type == ZAP_CHAN_TYPE_FXO && zchan->detected_tones[0]) {
+ zap_sigmsg_t sig;
+ int i;
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = zchan->chan_id;
+ sig.span_id = zchan->span_id;
+ sig.channel = zchan;
+ sig.event_id = ZAP_SIGEVENT_TONE_DETECTED;
+
+ for (i = 1; i < ZAP_TONEMAP_INVALID; i++) {
+ if (zchan->detected_tones[i]) {
+ zap_log(ZAP_LOG_DEBUG, "Detected tone %s on %d:%d\n", zap_tonemap2str(i), zchan->span_id, zchan->chan_id);
+ sig.raw_data = &i;
+ zap_span_send_signal(zchan->span, &sig);
+ }
+ }
+
+ if (zchan->detected_tones[ZAP_TONEMAP_BUSY] ||
+ zchan->detected_tones[ZAP_TONEMAP_FAIL1] ||
+ zchan->detected_tones[ZAP_TONEMAP_FAIL2] ||
+ zchan->detected_tones[ZAP_TONEMAP_FAIL3] ||
+ zchan->detected_tones[ZAP_TONEMAP_ATTN]
+ ) {
+ zap_log(ZAP_LOG_ERROR, "Failure indication detected!\n");
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+ } else if (zchan->detected_tones[ZAP_TONEMAP_DIAL]) {
+ if (zap_strlen_zero(zchan->caller_data.ani.digits)) {
+ zap_log(ZAP_LOG_ERROR, "No Digits to send!\n");
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+ } else {
+ if (zap_channel_command(zchan, ZAP_COMMAND_SEND_DTMF, zchan->caller_data.ani.digits) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Send Digits Failed [%s]\n", zchan->last_error);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+ } else {
+ state_counter = 0;
+ zchan->needed_tones[ZAP_TONEMAP_RING] = 1;
+ zchan->needed_tones[ZAP_TONEMAP_BUSY] = 1;
+ zchan->needed_tones[ZAP_TONEMAP_FAIL1] = 1;
+ zchan->needed_tones[ZAP_TONEMAP_FAIL2] = 1;
+ zchan->needed_tones[ZAP_TONEMAP_FAIL3] = 1;
+ dial_timeout = ((zchan->dtmf_on + zchan->dtmf_off) * strlen(zchan->caller_data.ani.digits)) + 2000;
+ }
+ }
+ } else if (zchan->detected_tones[ZAP_TONEMAP_RING]) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
+ }
+
+ zap_channel_clear_detected_tones(zchan);
+ }
+
+ if ((zchan->dtmf_buffer && zap_buffer_inuse(zchan->dtmf_buffer)) || (zchan->fsk_buffer && zap_buffer_inuse(zchan->fsk_buffer))) {
+ //rlen = len;
+ //memset(frame, 0, len);
+ //zap_channel_write(zchan, frame, sizeof(frame), &rlen);
+ continue;
+ }
+
+ if (!indicate) {
+ continue;
+ }
+
+ if (zchan->type == ZAP_CHAN_TYPE_FXO && !zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK)) {
+ zap_channel_command(zchan, ZAP_COMMAND_OFFHOOK, NULL);
+ }
+
+ if (zchan->effective_codec != ZAP_CODEC_SLIN) {
+ len *= 2;
+ }
+
+ rlen = zap_buffer_read_loop(dt_buffer, frame, len);
+
+ if (zchan->effective_codec != ZAP_CODEC_SLIN) {
+ zio_codec_t codec_func = NULL;
+
+ if (zchan->native_codec == ZAP_CODEC_ULAW) {
+ codec_func = zio_slin2ulaw;
+ } else if (zchan->native_codec == ZAP_CODEC_ALAW) {
+ codec_func = zio_slin2alaw;
+ }
+
+ if (codec_func) {
+ status = codec_func(frame, sizeof(frame), &rlen);
+ } else {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "codec error!");
+ goto done;
+ }
+ }
+
+ zap_channel_write(zchan, frame, sizeof(frame), &rlen);
+ }
+
+ done:
+
+
+ if (zchan->type == ZAP_CHAN_TYPE_FXO && zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK)) {
+ zap_channel_command(zchan, ZAP_COMMAND_ONHOOK, NULL);
+ }
+
+ if (zchan->type == ZAP_CHAN_TYPE_FXS && zap_test_flag(zchan, ZAP_CHANNEL_RINGING)) {
+ zap_channel_command(zchan, ZAP_COMMAND_GENERATE_RING_OFF, NULL);
+ }
+
+
+ closed_chan = zchan;
+ zap_channel_close(&zchan);
+
+ zap_channel_command(closed_chan, ZAP_COMMAND_SET_NATIVE_CODEC, NULL);
+
+ if (ts.buffer) {
+ teletone_destroy_session(&ts);
+ }
+
+ if (dt_buffer) {
+ zap_buffer_destroy(&dt_buffer);
+ }
+
+ if (closed_chan->state != ZAP_CHANNEL_STATE_DOWN) {
+ zap_set_state_locked(closed_chan, ZAP_CHANNEL_STATE_DOWN);
+ }
+
+ zap_log(ZAP_LOG_DEBUG, "ANALOG CHANNEL %d:%d thread ended.\n", closed_chan->span_id, closed_chan->chan_id);
+ zap_clear_flag(closed_chan, ZAP_CHANNEL_INTHREAD);
+
+ return NULL;
+}
+
+/**
+ * \brief Processes openzap event
+ * \param span Span on which the event was fired
+ * \param event Event to be treated
+ * \return Success or failure
+ */
+static __inline__ zap_status_t process_event(zap_span_t *span, zap_event_t *event)
+{
+ zap_sigmsg_t sig;
+ zap_analog_data_t *analog_data = event->channel->span->signal_data;
+ int locked = 0;
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = event->channel->chan_id;
+ sig.span_id = event->channel->span_id;
+ sig.channel = event->channel;
+
+
+ zap_log(ZAP_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n",
+ zap_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, zap_channel_state2str(event->channel->state));
+
+ zap_mutex_lock(event->channel->mutex);
+ locked++;
+
+ switch(event->enum_id) {
+ case ZAP_OOB_RING_START:
+ {
+ if (event->channel->type != ZAP_CHAN_TYPE_FXO) {
+ zap_log(ZAP_LOG_ERROR, "Cannot get a RING_START event on a non-fxo channel, please check your config.\n");
+ zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DOWN);
+ goto end;
+ }
+ if (!event->channel->ring_count && (event->channel->state == ZAP_CHANNEL_STATE_DOWN && !zap_test_flag(event->channel, ZAP_CHANNEL_INTHREAD))) {
+ if (zap_test_flag(analog_data, ZAP_ANALOG_CALLERID)) {
+ zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_GET_CALLERID);
+ } else {
+ zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_IDLE);
+ }
+ event->channel->ring_count = 1;
+ zap_mutex_unlock(event->channel->mutex);
+ locked = 0;
+ zap_thread_create_detached(zap_analog_channel_run, event->channel);
+ } else {
+ event->channel->ring_count++;
+ }
+ }
+ break;
+ case ZAP_OOB_ONHOOK:
+ {
+ if (zap_test_flag(event->channel, ZAP_CHANNEL_RINGING)) {
+ zap_channel_command(event->channel, ZAP_COMMAND_GENERATE_RING_OFF, NULL);
+ }
+
+ if (event->channel->state != ZAP_CHANNEL_STATE_DOWN) {
+ zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DOWN);
+ }
+
+ }
+ break;
+ case ZAP_OOB_FLASH:
+ {
+ if (event->channel->state == ZAP_CHANNEL_STATE_CALLWAITING) {
+ zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_UP);
+ zap_clear_flag_locked(event->channel, ZAP_CHANNEL_STATE_CHANGE);
+ zap_clear_flag_locked(event->channel->span, ZAP_SPAN_STATE_CHANGE);
+ event->channel->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK] = 0;
+ }
+
+ zap_channel_rotate_tokens(event->channel);
+
+ if (zap_test_flag(event->channel, ZAP_CHANNEL_HOLD) && event->channel->token_count != 1) {
+ zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_UP);
+ } else {
+ sig.event_id = ZAP_SIGEVENT_FLASH;
+ zap_span_send_signal(span, &sig);
+ }
+ }
+ break;
+ case ZAP_OOB_OFFHOOK:
+ {
+ if (event->channel->type == ZAP_CHAN_TYPE_FXS) {
+ if (zap_test_flag(event->channel, ZAP_CHANNEL_INTHREAD)) {
+ if (zap_test_flag(event->channel, ZAP_CHANNEL_RINGING)) {
+ zap_channel_command(event->channel, ZAP_COMMAND_GENERATE_RING_OFF, NULL);
+ }
+ zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_UP);
+ } else {
+ if(!analog_data->max_dialstr) {
+ zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_COLLECT);
+ } else {
+ zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DIALTONE);
+ }
+ zap_mutex_unlock(event->channel->mutex);
+ locked = 0;
+ zap_thread_create_detached(zap_analog_channel_run, event->channel);
+ }
+ } else {
+ if (!zap_test_flag(event->channel, ZAP_CHANNEL_INTHREAD)) {
+ if (zap_test_flag(event->channel, ZAP_CHANNEL_OFFHOOK)) {
+ zap_channel_command(event->channel, ZAP_COMMAND_ONHOOK, NULL);
+ }
+ }
+ zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DOWN);
+ }
+ }
+ case ZAP_OOB_DTMF:
+ {
+ const char * digit_str = (const char *)event->data;
+ if(digit_str) {
+ if (event->channel->state == ZAP_CHANNEL_STATE_CALLWAITING && (*digit_str == 'D' || *digit_str == 'A')) {
+ event->channel->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]++;
+ } else {
+ zio_event_cb_t event_callback = NULL;
+
+ zap_channel_queue_dtmf(event->channel, digit_str);
+ if (span->event_callback) {
+ event_callback = span->event_callback;
+ } else if (event->channel->event_callback) {
+ event_callback = event->channel->event_callback;
+ }
+
+ if (event_callback) {
+ event->channel->event_header.channel = event->channel;
+ event->channel->event_header.e_type = ZAP_EVENT_DTMF;
+ event->channel->event_header.data = (void *)digit_str;
+ event_callback(event->channel, &event->channel->event_header);
+ event->channel->event_header.e_type = ZAP_EVENT_NONE;
+ event->channel->event_header.data = NULL;
+ }
+
+ }
+ zap_safe_free(event->data);
+ }
+ }
+ case ZAP_OOB_ALARM_TRAP:
+ {
+ zap_set_flag_locked(event->channel, ZAP_CHANNEL_SUSPENDED);
+ }
+ case ZAP_OOB_ALARM_CLEAR:
+ {
+ zap_clear_flag_locked(event->channel, ZAP_CHANNEL_SUSPENDED);
+ }
+ }
+
+ end:
+
+ if (locked) {
+ zap_mutex_unlock(event->channel->mutex);
+ }
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Main thread function for analog span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *zap_analog_run(zap_thread_t *me, void *obj)
+{
+ zap_span_t *span = (zap_span_t *) obj;
+ zap_analog_data_t *analog_data = span->signal_data;
+ int errs = 0;
+
+ zap_log(ZAP_LOG_DEBUG, "ANALOG thread starting.\n");
+
+ while(zap_running() && zap_test_flag(analog_data, ZAP_ANALOG_RUNNING)) {
+ int waitms = 1000;
+ zap_status_t status;
+
+ if ((status = zap_span_poll_event(span, waitms)) != ZAP_FAIL) {
+ errs = 0;
+ }
+
+ switch(status) {
+ case ZAP_SUCCESS:
+ {
+ zap_event_t *event;
+ while (zap_span_next_event(span, &event) == ZAP_SUCCESS) {
+ if (event->enum_id == ZAP_OOB_NOOP) {
+ continue;
+ }
+ if (process_event(span, event) != ZAP_SUCCESS) {
+ goto end;
+ }
+ }
+ }
+ break;
+ case ZAP_FAIL:
+ {
+ zap_log(ZAP_LOG_ERROR, "Failure Polling event! [%s]\n", span->last_error);
+ if (++errs > 300) {
+ zap_log(ZAP_LOG_CRIT, "Too Many Errors!\n");
+ goto end;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ end:
+
+ zap_clear_flag(analog_data, ZAP_ANALOG_RUNNING);
+
+ zap_log(ZAP_LOG_DEBUG, "ANALOG thread ending.\n");
+
+ return NULL;
+}
+
+/**
+ * \brief Openzap analog signaling module initialisation
+ * \return Success
+ */
+static ZIO_SIG_LOAD_FUNCTION(zap_analog_init)
+{
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Openzap analog signaling module definition
+ */
+EX_DECLARE_DATA zap_module_t zap_module = {
+ "analog",
+ NULL,
+ NULL,
+ zap_analog_init,
+ zap_analog_configure_span,
+ NULL
+};
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/zap_analog.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/zap_analog.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/zap_analog.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#ifndef ZAP_ANALOG_H
+#define ZAP_ANALOG_H
+#include "openzap.h"
+
+typedef enum {
+ ZAP_ANALOG_RUNNING = (1 << 0),
+ ZAP_ANALOG_CALLERID = (1 << 1)
+} zap_analog_flag_t;
+
+#define ZAP_MAX_HOTLINE_STR 20
+#define MAX_DTMF 256
+
+struct zap_analog_data {
+ uint32_t flags;
+ uint32_t max_dialstr;
+ uint32_t digit_timeout;
+ char hotline[ZAP_MAX_HOTLINE_STR];
+};
+
+
+
+static void *zap_analog_run(zap_thread_t *me, void *obj);
+typedef struct zap_analog_data zap_analog_data_t;
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.2005.vcproj (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.2005.vcproj (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.2005.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ozmod_analog_em"
+ ProjectGUID="{C539D7C8-26A8-4A94-B938-77672165C130}"
+ RootNamespace="ozmod_analog_em"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EM_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EM_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="ozmod_analog_em.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="zap_analog_em.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,353 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="ozmod_analog_em"
+ ProjectGUID="{B3F49375-2834-4937-9D8C-4AC2EC911010}"
+ RootNamespace="ozmod_analog_em"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EM_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EM_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EM_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EM_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4100"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="ozmod_analog_em.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="zap_analog_em.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,707 @@
+/*
+ * Copyright (c) 2008, Anthony Minessale II
+ * 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.
+ *
+ * Contributor(s):
+ *
+ * John Wehle (john@feith.com)
+ *
+ */
+
+#include "openzap.h"
+#include "zap_analog_em.h"
+
+#ifndef localtime_r
+struct tm * localtime_r(const time_t *clock, struct tm *result);
+#endif
+
+static void *zap_analog_em_channel_run(zap_thread_t *me, void *obj);
+
+/**
+ * \brief Starts an EM channel thread (outgoing call)
+ * \param zchan Channel to initiate call on
+ * \return Success or failure
+ *
+ * Initialises state, starts tone progress detection and runs the channel in a new a thread.
+ */
+static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_em_outgoing_call)
+{
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
+ zap_channel_clear_needed_tones(zchan);
+ zap_channel_clear_detected_tones(zchan);
+
+ zap_set_flag(zchan, ZAP_CHANNEL_OUTBOUND);
+
+ zap_channel_command(zchan, ZAP_COMMAND_OFFHOOK, NULL);
+ zap_channel_command(zchan, ZAP_COMMAND_ENABLE_PROGRESS_DETECT, NULL);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DIALING);
+ zap_thread_create_detached(zap_analog_em_channel_run, zchan);
+ return ZAP_SUCCESS;
+ }
+
+ return ZAP_FAIL;
+}
+
+/**
+ * \brief Starts an EM span thread (monitor)
+ * \param span Span to monitor
+ * \return Success or failure
+ */
+static zap_status_t zap_analog_em_start(zap_span_t *span)
+{
+ zap_analog_em_data_t *analog_data = span->signal_data;
+ zap_set_flag(analog_data, ZAP_ANALOG_EM_RUNNING);
+ return zap_thread_create_detached(zap_analog_em_run, span);
+}
+
+/**
+ * \brief Initialises an EM span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static ZIO_SIG_CONFIGURE_FUNCTION(zap_analog_em_configure_span)
+//zap_status_t zap_analog_em_configure_span(zap_span_t *span, char *tonemap, uint32_t digit_timeout, uint32_t max_dialstr, zio_signal_cb_t sig_cb)
+{
+ zap_analog_em_data_t *analog_data;
+ const char *tonemap = "us";
+ uint32_t digit_timeout = 10;
+ uint32_t max_dialstr = 11;
+ const char *var, *val;
+ int *intval;
+
+ assert(sig_cb != NULL);
+
+ if (span->signal_type) {
+ snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
+ return ZAP_FAIL;
+ }
+
+ analog_data = malloc(sizeof(*analog_data));
+ assert(analog_data != NULL);
+ memset(analog_data, 0, sizeof(*analog_data));
+
+ while((var = va_arg(ap, char *))) {
+ if (!strcasecmp(var, "tonemap")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ tonemap = val;
+ } else if (!strcasecmp(var, "digit_timeout")) {
+ if (!(intval = va_arg(ap, int *))) {
+ break;
+ }
+ digit_timeout = *intval;
+ } else if (!strcasecmp(var, "max_dialstr")) {
+ if (!(intval = va_arg(ap, int *))) {
+ break;
+ }
+ max_dialstr = *intval;
+ } else {
+ snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+ return ZAP_FAIL;
+ }
+ }
+
+
+ if (digit_timeout < 2000 || digit_timeout > 10000) {
+ digit_timeout = 2000;
+ }
+
+ if (max_dialstr < 2 || max_dialstr > MAX_DIALSTRING) {
+ zap_log(ZAP_LOG_ERROR, "Invalid max_dialstr, setting to %d\n", MAX_DIALSTRING);
+ max_dialstr = MAX_DIALSTRING;
+ }
+
+ span->start = zap_analog_em_start;
+ analog_data->digit_timeout = digit_timeout;
+ analog_data->max_dialstr = max_dialstr;
+ span->signal_cb = sig_cb;
+ span->signal_type = ZAP_SIGTYPE_ANALOG;
+ span->signal_data = analog_data;
+ span->outgoing_call = analog_em_outgoing_call;
+ zap_span_load_tones(span, tonemap);
+
+ return ZAP_SUCCESS;
+
+}
+
+/**
+ * \brief Retrieves tone generation output to be sent
+ * \param ts Teletone generator
+ * \param map Tone map
+ * \return -1 on error, 0 on success
+ */
+static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+ zap_buffer_t *dt_buffer = ts->user_data;
+ int wrote;
+
+ if (!dt_buffer) {
+ return -1;
+ }
+ wrote = teletone_mux_tones(ts, map);
+ zap_buffer_write(dt_buffer, ts->buffer, wrote * 2);
+ return 0;
+}
+
+/**
+ * \brief Main thread function for EM channel (outgoing call)
+ * \param me Current thread
+ * \param obj Channel to run in this thread
+ */
+static void *zap_analog_em_channel_run(zap_thread_t *me, void *obj)
+{
+ zap_channel_t *zchan = (zap_channel_t *) obj;
+ zap_buffer_t *dt_buffer = NULL;
+ teletone_generation_session_t ts;
+ uint8_t frame[1024];
+ zap_size_t len, rlen;
+ zap_tone_type_t tt = ZAP_TONE_DTMF;
+ char dtmf[128] = "";
+ zap_size_t dtmf_offset = 0;
+ zap_analog_em_data_t *analog_data = zchan->span->signal_data;
+ zap_channel_t *closed_chan;
+ uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = 30000;
+ zap_sigmsg_t sig;
+ zap_status_t status;
+
+ zap_log(ZAP_LOG_DEBUG, "ANALOG EM CHANNEL thread starting.\n");
+
+ ts.buffer = NULL;
+
+ if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "OPEN ERROR [%s]\n", zchan->last_error);
+ goto done;
+ }
+
+ if (zap_buffer_create(&dt_buffer, 1024, 3192, 0) != ZAP_SUCCESS) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "memory error!");
+ zap_log(ZAP_LOG_ERROR, "MEM ERROR\n");
+ goto done;
+ }
+
+ if (zap_channel_command(zchan, ZAP_COMMAND_ENABLE_DTMF_DETECT, &tt) != ZAP_SUCCESS) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "error initilizing tone detector!");
+ zap_log(ZAP_LOG_ERROR, "TONE ERROR\n");
+ goto done;
+ }
+
+ zap_set_flag_locked(zchan, ZAP_CHANNEL_INTHREAD);
+ teletone_init_session(&ts, 0, teletone_handler, dt_buffer);
+ ts.rate = 8000;
+#if 0
+ ts.debug = 1;
+ ts.debug_stream = stdout;
+#endif
+ zap_channel_command(zchan, ZAP_COMMAND_GET_INTERVAL, &interval);
+ zap_buffer_set_loops(dt_buffer, -1);
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = zchan->chan_id;
+ sig.span_id = zchan->span_id;
+ sig.channel = zchan;
+
+ assert(interval != 0);
+
+ while (zap_running() && zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
+ zap_wait_flag_t flags = ZAP_READ;
+ zap_size_t dlen = 0;
+
+ len = sizeof(frame);
+
+ elapsed += interval;
+ state_counter += interval;
+
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_STATE_CHANGE)) {
+ switch(zchan->state) {
+ case ZAP_CHANNEL_STATE_DIALING:
+ {
+ if (! zchan->needed_tones[ZAP_TONEMAP_RING]
+ && zap_test_flag(zchan, ZAP_CHANNEL_WINK)) {
+ if (zap_strlen_zero(zchan->caller_data.ani.digits)) {
+ zap_log(ZAP_LOG_ERROR, "No Digits to send!\n");
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+ } else {
+ if (zap_channel_command(zchan, ZAP_COMMAND_SEND_DTMF, zchan->caller_data.ani.digits) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Send Digits Failed [%s]\n", zchan->last_error);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+ } else {
+ state_counter = 0;
+ zchan->needed_tones[ZAP_TONEMAP_RING] = 1;
+ zchan->needed_tones[ZAP_TONEMAP_BUSY] = 1;
+ zchan->needed_tones[ZAP_TONEMAP_FAIL1] = 1;
+ zchan->needed_tones[ZAP_TONEMAP_FAIL2] = 1;
+ zchan->needed_tones[ZAP_TONEMAP_FAIL3] = 1;
+ dial_timeout = ((zchan->dtmf_on + zchan->dtmf_off) * strlen(zchan->caller_data.ani.digits)) + 2000;
+ }
+ }
+ break;
+ }
+ if (state_counter > dial_timeout) {
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_WINK)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+ } else {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
+ }
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_DIALTONE:
+ {
+ if (state_counter > 10000) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_BUSY:
+ {
+ if (state_counter > 20000) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_ATTN);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_ATTN:
+ {
+ if (state_counter > 20000) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_HANGUP:
+ {
+ if (state_counter > 500) {
+ if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) &&
+ (zchan->last_state == ZAP_CHANNEL_STATE_RING || zchan->last_state == ZAP_CHANNEL_STATE_DIALTONE
+ || zchan->last_state >= ZAP_CHANNEL_STATE_IDLE)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+ } else {
+ zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_CLEARING;
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ }
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_UP:
+ case ZAP_CHANNEL_STATE_IDLE:
+ {
+ zap_sleep(interval);
+ continue;
+ }
+ break;
+ case ZAP_CHANNEL_STATE_DOWN:
+ {
+ goto done;
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_STATE_CHANGE);
+ zap_clear_flag_locked(zchan->span, ZAP_SPAN_STATE_CHANGE);
+ zap_channel_complete_state(zchan);
+ indicate = 0;
+ state_counter = 0;
+
+ zap_log(ZAP_LOG_DEBUG, "Executing state handler on %d:%d for %s\n",
+ zchan->span_id, zchan->chan_id,
+ zap_channel_state2str(zchan->state));
+ switch(zchan->state) {
+ case ZAP_CHANNEL_STATE_UP:
+ {
+ zap_channel_use(zchan);
+ zap_channel_clear_needed_tones(zchan);
+ zap_channel_flush_dtmf(zchan);
+
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK)) {
+ zap_channel_command(zchan, ZAP_COMMAND_OFFHOOK, NULL);
+ }
+
+ sig.event_id = ZAP_SIGEVENT_UP;
+
+ zap_span_send_signal(zchan->span, &sig);
+ continue;
+ }
+ break;
+ case ZAP_CHANNEL_STATE_DIALING:
+ {
+ zap_channel_use(zchan);
+ }
+ break;
+ case ZAP_CHANNEL_STATE_IDLE:
+ {
+ zap_channel_use(zchan);
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ zap_set_string(zchan->caller_data.dnis.digits, zchan->chan_number);
+ } else {
+ zap_set_string(zchan->caller_data.dnis.digits, dtmf);
+ }
+
+ sig.event_id = ZAP_SIGEVENT_START;
+
+ zap_span_send_signal(zchan->span, &sig);
+ continue;
+ }
+ break;
+ case ZAP_CHANNEL_STATE_DOWN:
+ {
+ sig.event_id = ZAP_SIGEVENT_STOP;
+ zap_span_send_signal(zchan->span, &sig);
+ goto done;
+ }
+ break;
+ case ZAP_CHANNEL_STATE_DIALTONE:
+ {
+ memset(&zchan->caller_data, 0, sizeof(zchan->caller_data));
+ *dtmf = '\0';
+ dtmf_offset = 0;
+ zap_buffer_zero(dt_buffer);
+ teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_DIAL]);
+ indicate = 1;
+
+ zap_channel_command(zchan, ZAP_COMMAND_WINK, NULL);
+ }
+ break;
+ case ZAP_CHANNEL_STATE_RING:
+ {
+ zap_buffer_zero(dt_buffer);
+ teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_RING]);
+ indicate = 1;
+ }
+ break;
+ case ZAP_CHANNEL_STATE_BUSY:
+ {
+ zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+ if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ zap_buffer_zero(dt_buffer);
+ teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_BUSY]);
+ indicate = 1;
+ } else {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_ATTN:
+ {
+ if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ zap_buffer_zero(dt_buffer);
+ teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_ATTN]);
+ indicate = 1;
+ } else {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+
+ if (zchan->state == ZAP_CHANNEL_STATE_DIALTONE || zchan->state == ZAP_CHANNEL_STATE_COLLECT) {
+ if ((dlen = zap_channel_dequeue_dtmf(zchan, dtmf + dtmf_offset, sizeof(dtmf) - strlen(dtmf)))) {
+
+ if (zchan->state == ZAP_CHANNEL_STATE_DIALTONE) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_COLLECT);
+ collecting = 1;
+ }
+ dtmf_offset = strlen(dtmf);
+ last_digit = elapsed;
+ sig.event_id = ZAP_SIGEVENT_COLLECTED_DIGIT;
+ sig.raw_data = dtmf;
+ if (zap_span_send_signal(zchan->span, &sig) == ZAP_BREAK) {
+ collecting = 0;
+ }
+ }
+ }
+
+
+ if (last_digit && (!collecting || ((elapsed - last_digit > analog_data->digit_timeout) || strlen(dtmf) > analog_data->max_dialstr))) {
+ zap_log(ZAP_LOG_DEBUG, "Number obtained [%s]\n", dtmf);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_IDLE);
+ last_digit = 0;
+ collecting = 0;
+ }
+
+ if (zap_channel_wait(zchan, &flags, interval * 2) != ZAP_SUCCESS) {
+ continue;
+ }
+
+ if (!(flags & ZAP_READ)) {
+ continue;
+ }
+
+ if (zap_channel_read(zchan, frame, &len) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "READ ERROR [%s]\n", zchan->last_error);
+ goto done;
+ }
+
+ if (zchan->detected_tones[0]) {
+ zap_sigmsg_t sig;
+ int i;
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = zchan->chan_id;
+ sig.span_id = zchan->span_id;
+ sig.channel = zchan;
+ sig.event_id = ZAP_SIGEVENT_TONE_DETECTED;
+
+ for (i = 1; i < ZAP_TONEMAP_INVALID; i++) {
+ if (zchan->detected_tones[i]) {
+ zap_log(ZAP_LOG_DEBUG, "Detected tone %s on %d:%d\n", zap_tonemap2str(i), zchan->span_id, zchan->chan_id);
+ sig.raw_data = &i;
+ zap_span_send_signal(zchan->span, &sig);
+ }
+ }
+
+ if (zchan->detected_tones[ZAP_TONEMAP_BUSY] ||
+ zchan->detected_tones[ZAP_TONEMAP_FAIL1] ||
+ zchan->detected_tones[ZAP_TONEMAP_FAIL2] ||
+ zchan->detected_tones[ZAP_TONEMAP_FAIL3] ||
+ zchan->detected_tones[ZAP_TONEMAP_ATTN]
+ ) {
+ zap_log(ZAP_LOG_ERROR, "Failure indication detected!\n");
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+ } else if (zchan->detected_tones[ZAP_TONEMAP_RING]) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
+ }
+
+ zap_channel_clear_detected_tones(zchan);
+ }
+
+ if ((zchan->dtmf_buffer && zap_buffer_inuse(zchan->dtmf_buffer))) {
+ rlen = len;
+ memset(frame, 0, len);
+ zap_channel_write(zchan, frame, sizeof(frame), &rlen);
+ continue;
+ }
+
+ if (!indicate) {
+ continue;
+ }
+
+ if (zchan->effective_codec != ZAP_CODEC_SLIN) {
+ len *= 2;
+ }
+
+ rlen = zap_buffer_read_loop(dt_buffer, frame, len);
+
+ if (zchan->effective_codec != ZAP_CODEC_SLIN) {
+ zio_codec_t codec_func = NULL;
+
+ if (zchan->native_codec == ZAP_CODEC_ULAW) {
+ codec_func = zio_slin2ulaw;
+ } else if (zchan->native_codec == ZAP_CODEC_ALAW) {
+ codec_func = zio_slin2alaw;
+ }
+
+ if (codec_func) {
+ status = codec_func(frame, sizeof(frame), &rlen);
+ } else {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "codec error!");
+ goto done;
+ }
+ }
+
+ zap_channel_write(zchan, frame, sizeof(frame), &rlen);
+ }
+
+ done:
+
+ zap_channel_command(zchan, ZAP_COMMAND_ONHOOK, NULL);
+
+ closed_chan = zchan;
+ zap_channel_close(&zchan);
+
+ zap_channel_command(closed_chan, ZAP_COMMAND_SET_NATIVE_CODEC, NULL);
+
+ if (ts.buffer) {
+ teletone_destroy_session(&ts);
+ }
+
+ if (dt_buffer) {
+ zap_buffer_destroy(&dt_buffer);
+ }
+
+ zap_clear_flag(closed_chan, ZAP_CHANNEL_INTHREAD);
+
+ zap_log(ZAP_LOG_DEBUG, "ANALOG EM CHANNEL thread ended.\n");
+
+ return NULL;
+}
+
+/**
+ * \brief Processes EM events coming from zaptel/dahdi
+ * \param span Span on which the event was fired
+ * \param event Event to be treated
+ * \return Success or failure
+ */
+static __inline__ zap_status_t process_event(zap_span_t *span, zap_event_t *event)
+{
+ zap_sigmsg_t sig;
+ int locked = 0;
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = event->channel->chan_id;
+ sig.span_id = event->channel->span_id;
+ sig.channel = event->channel;
+
+
+ zap_log(ZAP_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n",
+ zap_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, zap_channel_state2str(event->channel->state));
+
+ zap_mutex_lock(event->channel->mutex);
+ locked++;
+
+ switch(event->enum_id) {
+ case ZAP_OOB_ONHOOK:
+ {
+ if (event->channel->state != ZAP_CHANNEL_STATE_DOWN) {
+ zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DOWN);
+ }
+
+ }
+ break;
+ case ZAP_OOB_OFFHOOK:
+ {
+ if (zap_test_flag(event->channel, ZAP_CHANNEL_INTHREAD)) {
+ zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_UP);
+ } else {
+ zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DIALTONE);
+ zap_mutex_unlock(event->channel->mutex);
+ locked = 0;
+ zap_thread_create_detached(zap_analog_em_channel_run, event->channel);
+ }
+ break;
+ }
+ case ZAP_OOB_WINK:
+ {
+ if (event->channel->state != ZAP_CHANNEL_STATE_DIALING) {
+ zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DOWN);
+ } else {
+ zap_set_flag_locked(event->channel, ZAP_CHANNEL_WINK);
+ }
+
+ }
+ break;
+ }
+ if (locked) {
+ zap_mutex_unlock(event->channel->mutex);
+ }
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Main thread function for EM span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *zap_analog_em_run(zap_thread_t *me, void *obj)
+{
+ zap_span_t *span = (zap_span_t *) obj;
+ zap_analog_em_data_t *analog_data = span->signal_data;
+
+ zap_log(ZAP_LOG_DEBUG, "ANALOG EM thread starting.\n");
+
+ while(zap_running() && zap_test_flag(analog_data, ZAP_ANALOG_EM_RUNNING)) {
+ int waitms = 10;
+ zap_status_t status;
+
+ status = zap_span_poll_event(span, waitms);
+
+ switch(status) {
+ case ZAP_SUCCESS:
+ {
+ zap_event_t *event;
+ while (zap_span_next_event(span, &event) == ZAP_SUCCESS) {
+ if (event->enum_id == ZAP_OOB_NOOP) {
+ continue;
+ }
+ if (process_event(span, event) != ZAP_SUCCESS) {
+ goto end;
+ }
+ }
+ }
+ break;
+ case ZAP_FAIL:
+ {
+ zap_log(ZAP_LOG_ERROR, "Failure Polling event! [%s]\n", span->last_error);
+ }
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ end:
+
+ zap_clear_flag(analog_data, ZAP_ANALOG_EM_RUNNING);
+
+ zap_log(ZAP_LOG_DEBUG, "ANALOG EM thread ending.\n");
+
+ return NULL;
+}
+
+/**
+ * \brief Openzap analog EM module initialisation
+ * \return Success
+ */
+static ZIO_SIG_LOAD_FUNCTION(zap_analog_em_init)
+{
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Openzap analog EM module definition
+ */
+EX_DECLARE_DATA zap_module_t zap_module = {
+ "analog_em",
+ NULL,
+ NULL,
+ zap_analog_em_init,
+ zap_analog_em_configure_span,
+ NULL
+};
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/zap_analog_em.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/zap_analog_em.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/zap_analog_em.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2008, Anthony Minessale II
+ * 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.
+ *
+ * Contributor(s):
+ *
+ * John Wehle (john@feith.com)
+ *
+ */
+
+#ifndef ZAP_ANALOG_EM_H
+#define ZAP_ANALOG_EM_H
+#include "openzap.h"
+
+#define MAX_DIALSTRING 256
+
+typedef enum {
+ ZAP_ANALOG_EM_RUNNING = (1 << 0)
+} zap_analog_em_flag_t;
+
+
+struct zap_analog_data {
+ uint32_t flags;
+ uint32_t max_dialstr;
+ uint32_t digit_timeout;
+};
+
+static void *zap_analog_em_run(zap_thread_t *me, void *obj);
+typedef struct zap_analog_data zap_analog_em_data_t;
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.2005.vcproj (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.2005.vcproj (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.2005.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,316 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ozmod_isdn"
+ ProjectGUID="{729344A5-D5E9-434D-8EE8-AF8C6C795D15}"
+ RootNamespace="ozmod_isdn"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\isdn\5ESSmes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\5ESSStateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\5ESSStateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\DMSmes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\DMSStateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\DMSStateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\EuroISDNStateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\EuroISDNStateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\mfifo.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\nationalmes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\nationalStateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\nationalStateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="ozmod_isdn.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q921.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931api.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931ie.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931mes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931StateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931StateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q932mes.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\isdn\include\5ESS.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\DMS.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\mfifo.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\national.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q921.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q921priv.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q931.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q931ie.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q932.h"
+ >
+ </File>
+ <File
+ RelativePath="zap_isdn.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,465 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="ozmod_isdn"
+ ProjectGUID="{729344A5-D5E9-434D-8EE8-AF8C6C795D15}"
+ RootNamespace="ozmod_isdn"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\isdn\5ESSmes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\5ESSStateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\5ESSStateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\DMSmes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\DMSStateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\DMSStateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\EuroISDNStateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\EuroISDNStateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\mfifo.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\nationalmes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\nationalStateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\nationalStateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="ozmod_isdn.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q921.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931api.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931ie.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931mes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931StateNT.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q931StateTE.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\Q932mes.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\isdn\include\5ESS.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\DMS.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\mfifo.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\national.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q921.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q921priv.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q931.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q931ie.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\isdn\include\Q932.h"
+ >
+ </File>
+ <File
+ RelativePath="zap_isdn.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,2420 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+/**
+ * Workaround for missing u_int / u_short types on solaris
+ */
+#if defined(HAVE_LIBPCAP) && defined(__SunOS)
+#define __EXTENSIONS__
+#endif
+
+#include "openzap.h"
+#include "Q931.h"
+#include "Q921.h"
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <sys/time.h>
+#endif
+
+#include "zap_isdn.h"
+
+#define LINE "--------------------------------------------------------------------------------"
+//#define IODEBUG
+
+/* helper macros */
+#define ZAP_SPAN_IS_BRI(x) ((x)->trunk_type == ZAP_TRUNK_BRI || (x)->trunk_type == ZAP_TRUNK_BRI_PTMP)
+#define ZAP_SPAN_IS_NT(x) (((zap_isdn_data_t *)(x)->signal_data)->mode == Q921_NT)
+
+
+#ifdef HAVE_LIBPCAP
+/*-------------------------------------------------------------------------*/
+/*Q931ToPcap functions*/
+#include <pcap.h>
+#endif
+
+#define SNAPLEN 1522
+#define MAX_ETHER_PAYLOAD_SIZE 1500
+#define MIN_ETHER_PAYLOAD_SIZE 42
+#define SIZE_ETHERNET 18
+#define VLANID_OFFSET 15
+#define SIZE_IP 20
+#define SIZE_TCP 20
+#define SIZE_TPKT 4
+#define SIZE_ETHERNET_CRC 4
+#define OVERHEAD SIZE_ETHERNET+SIZE_IP+SIZE_TCP+SIZE_TPKT
+#define MAX_Q931_SIZE MAX_ETHER_PAYLOAD_SIZE-SIZE_IP-SIZE_TCP-SIZE_TPKT
+#define TPKT_SIZE_OFFSET SIZE_ETHERNET+SIZE_IP+SIZE_TCP+2
+#define IP_SIZE_OFFSET SIZE_ETHERNET+2
+#define TCP_SEQ_OFFSET SIZE_ETHERNET+SIZE_IP+4
+
+#ifdef HAVE_LIBPCAP
+/*Some globals*/
+unsigned long pcapfilesize = 0;
+unsigned long tcp_next_seq_no_send = 0;
+unsigned long tcp_next_seq_no_rec = 0;
+pcap_dumper_t *pcapfile = NULL;
+struct pcap_pkthdr pcaphdr;
+pcap_t *pcaphandle = NULL;
+char *pcapfn = NULL;
+int do_q931ToPcap= 0;
+
+/*Predefined Ethernet Frame with Q931-over-IP encapsulated - From remote TDM host to FreeSWITCH*/
+L3UCHAR recFrame[SNAPLEN]= {
+ /*IEEE 802.3 VLAN 802.1q Ethernet Frame Header*/
+ 2,0,1,0xAA,0xAA,0xAA,2,0,1,0xBB,0xBB,0xBB,0x81,0,0xE0,0,0x08,0,
+ /*IPv4 Header (minimal size; no options)*/
+ 0x45,0,0,44,0,0,0,0,64,6,0,0,2,2,2,2,1,1,1,1,
+ /*TCP-Header*/
+ 0,0x66,0,0x66,0,0,0,0,0,0,0,0,0x50,0,0,1,0,0,0,0,
+ /*TPKT-Header RFC 1006*/
+ 3,0,0,0
+ };
+
+/*Predefined Ethernet Frame with Q931-over-IP encapsulated - Frome FreeSWITCH to remote TDM host*/
+L3UCHAR sendFrame[SNAPLEN]= {
+ /*IEEE 802.3 VLAN 802.1q Ethernet Frame Header*/
+ 2,0,1,0xBB,0xBB,0xBB,2,0,1,0xAA,0xAA,0xAA,0x81,0,0xE0,0,0x08,0,
+ /*IPv4 Header (minimal size; no options)*/
+ 0x45,0,0,44,0,0,0,0,64,6,0,0,1,1,1,1,2,2,2,2,
+ /*TCP-Header*/
+ 0,0x66,0,0x66,0,0,0,0,0,0,0,0,0x50,0,0,1,0,0,0,0,
+ /*TPKT-Header RFC 1006*/
+ 3,0,0,0
+ };
+
+/**
+ * \brief Opens a pcap file for capture
+ * \return Success or failure
+ */
+static zap_status_t openPcapFile(void)
+{
+ if(!pcaphandle)
+ {
+ pcaphandle = pcap_open_dead(DLT_EN10MB, SNAPLEN);
+ if (!pcaphandle)
+ {
+ zap_log(ZAP_LOG_ERROR, "Can't open pcap session: (%s)\n", pcap_geterr(pcaphandle));
+ return ZAP_FAIL;
+ }
+ }
+
+ if(!pcapfile){
+ /* Open the dump file */
+ if(!(pcapfile=pcap_dump_open(pcaphandle, pcapfn))){
+ zap_log(ZAP_LOG_ERROR, "Error opening output file (%s)\n", pcap_geterr(pcaphandle));
+ return ZAP_FAIL;
+ }
+ }
+ else{
+ zap_log(ZAP_LOG_WARNING, "Pcap file is already open!\n");
+ return ZAP_FAIL;
+ }
+
+ zap_log(ZAP_LOG_DEBUG, "Pcap file '%s' successfully opened!\n", pcapfn);
+
+ pcaphdr.ts.tv_sec = 0;
+ pcaphdr.ts.tv_usec = 0;
+ pcapfilesize = 24; /*current pcap file header seems to be 24 bytes*/
+ tcp_next_seq_no_send = 0;
+ tcp_next_seq_no_rec = 0;
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Closes a pcap file
+ * \return Success
+ */
+static zap_status_t closePcapFile(void)
+{
+ if (pcapfile) {
+ pcap_dump_close(pcapfile);
+ if (pcaphandle) pcap_close(pcaphandle);
+
+ zap_log(ZAP_LOG_DEBUG, "Pcap file closed! File size is %lu bytes.\n", pcapfilesize);
+
+ pcaphdr.ts.tv_sec = 0;
+ pcaphdr.ts.tv_usec = 0;
+ pcapfile = NULL;
+ pcaphandle = NULL;
+ pcapfilesize = 0;
+ tcp_next_seq_no_send = 0;
+ tcp_next_seq_no_rec = 0;
+ }
+
+ /*We have allways success with this? I think so*/
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Writes a Q931 packet to a pcap file
+ * \return Success or failure
+ */
+static zap_status_t writeQ931PacketToPcap(L3UCHAR* q931buf, L3USHORT q931size, L3ULONG span_id, L3USHORT direction)
+{
+ L3UCHAR *frame = NULL;
+ struct timeval ts;
+ u_char spanid = (u_char)span_id;
+ unsigned long *tcp_next_seq_no = NULL;
+
+ spanid=span_id;
+
+ /*The total length of the ethernet frame generated by this function has a min length of 66
+ so we don't have to care about padding :)*/
+
+
+ /*FS is sending the packet*/
+ if(direction==0){
+ frame=sendFrame;
+ tcp_next_seq_no = &tcp_next_seq_no_send;
+ }
+ /*FS is receiving the packet*/
+ else{
+ frame=recFrame;
+ tcp_next_seq_no = &tcp_next_seq_no_rec;
+ }
+
+ /*Set spanid in VLAN-ID tag*/
+ frame[VLANID_OFFSET] = spanid;
+
+ /*** Write sent packet ***/
+ if(q931size > MAX_Q931_SIZE)
+ {
+ /*WARNING*/
+ zap_log(ZAP_LOG_WARNING, "Q931 packet size is too big (%u)! Ignoring it!\n", q931size);
+ return ZAP_FAIL;
+ }
+
+ /*Copy q931 buffer into frame*/
+ memcpy(frame+OVERHEAD,q931buf,q931size);
+
+ /*Store TCP sequence number in TCP header*/
+ frame[TCP_SEQ_OFFSET]=(*tcp_next_seq_no>>24)&0xFF;
+ frame[TCP_SEQ_OFFSET+1]=(*tcp_next_seq_no>>16)&0xFF;
+ frame[TCP_SEQ_OFFSET+2]=(*tcp_next_seq_no>>8)&0xFF;
+ frame[TCP_SEQ_OFFSET+3]=*tcp_next_seq_no & 0xFF;
+
+ /*Store size of TPKT packet*/
+ q931size+=4;
+ frame[TPKT_SIZE_OFFSET]=(q931size>>8)&0xFF;
+ frame[TPKT_SIZE_OFFSET+1]=q931size&0xFF;
+
+ /*Calc next TCP sequence number*/
+ *tcp_next_seq_no+=q931size;
+
+ /*Store size of IP packet*/
+ q931size+=SIZE_IP+SIZE_TCP;
+ frame[IP_SIZE_OFFSET]=(q931size>>8)&0xFF;
+ frame[IP_SIZE_OFFSET+1]=q931size&0xFF;
+
+ pcaphdr.caplen = SIZE_ETHERNET+SIZE_ETHERNET_CRC+q931size;
+ pcaphdr.len = pcaphdr.caplen;
+
+ /* Set Timestamp */
+ /* Get Time in ms. usecs would be better ... */
+ gettimeofday(&ts, NULL);
+ /*Write it into packet header*/
+ pcaphdr.ts.tv_sec = ts.tv_sec;
+ pcaphdr.ts.tv_usec = ts.tv_usec;
+
+ pcap_dump((u_char*)pcapfile, &pcaphdr, frame);
+ pcap_dump_flush(pcapfile);
+
+ /*Maintain pcap file size*/
+ pcapfilesize+=pcaphdr.caplen;
+ pcapfilesize+=sizeof(struct pcap_pkthdr);
+
+ zap_log(ZAP_LOG_DEBUG, "Added %u bytes to pcap file. File size is now %lu, \n", q931size, pcapfilesize);
+
+ return ZAP_SUCCESS;
+}
+
+#endif
+
+/**
+ * \brief Unloads pcap IO
+ * \return Success or failure
+ */
+static ZIO_IO_UNLOAD_FUNCTION(close_pcap)
+{
+#ifdef HAVE_LIBPCAP
+ return closePcapFile();
+#else
+ return ZAP_SUCCESS;
+#endif
+}
+
+/*Q931ToPcap functions DONE*/
+/*-------------------------------------------------------------------------*/
+
+/**
+ * \brief Gets current time
+ * \return Current time (in ms)
+ */
+static L2ULONG zap_time_now(void)
+{
+ return (L2ULONG)zap_current_time_in_ms();
+}
+
+/**
+ * \brief Initialises an ISDN channel (outgoing call)
+ * \param zchan Channel to initiate call on
+ * \return Success or failure
+ */
+static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(isdn_outgoing_call)
+{
+ zap_status_t status = ZAP_SUCCESS;
+ zap_set_flag(zchan, ZAP_CHANNEL_OUTBOUND);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DIALING);
+ return status;
+}
+
+/**
+ * \brief Requests an ISDN channel on a span (outgoing call)
+ * \param span Span where to get a channel
+ * \param chan_id Specific channel to get (0 for any)
+ * \param direction Call direction (inbound, outbound)
+ * \param caller_data Caller information
+ * \param zchan Channel to initialise
+ * \return Success or failure
+ */
+static ZIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request)
+{
+ Q931mes_Generic *gen = (Q931mes_Generic *) caller_data->raw_data;
+ Q931ie_BearerCap BearerCap;
+ Q931ie_ChanID ChanID = { 0 };
+ Q931ie_CallingNum CallingNum;
+ Q931ie_CallingNum *ptrCallingNum;
+ Q931ie_CalledNum CalledNum;
+ Q931ie_CalledNum *ptrCalledNum;
+ Q931ie_Display Display, *ptrDisplay;
+ Q931ie_HLComp HLComp; /* High-Layer Compatibility IE */
+ Q931ie_ProgInd Progress; /* Progress Indicator IE */
+ zap_status_t status = ZAP_FAIL;
+ zap_isdn_data_t *isdn_data = span->signal_data;
+ int sanity = 60000;
+ int codec = 0;
+
+ /*
+ * get codec type
+ */
+ zap_channel_command(span->channels[chan_id], ZAP_COMMAND_GET_NATIVE_CODEC, &codec);
+
+ /*
+ * Q.931 Setup Message
+ */
+ Q931InitMesGeneric(gen);
+ gen->MesType = Q931mes_SETUP;
+ gen->CRVFlag = 0; /* outgoing call */
+
+ /*
+ * Bearer Capability IE
+ */
+ Q931InitIEBearerCap(&BearerCap);
+ BearerCap.CodStand = Q931_CODING_ITU; /* ITU-T = 0, ISO/IEC = 1, National = 2, Network = 3 */
+ BearerCap.ITC = Q931_ITC_SPEECH; /* Speech */
+ BearerCap.TransMode = 0; /* Circuit = 0, Packet = 1 */
+ BearerCap.ITR = Q931_ITR_64K; /* 64k */
+ BearerCap.Layer1Ident = 1;
+ BearerCap.UIL1Prot = (codec == ZAP_CODEC_ALAW) ? Q931_UIL1P_G711A : Q931_UIL1P_G711U; /* U-law = 2, A-law = 3 */
+ gen->BearerCap = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &BearerCap);
+
+ /*
+ * Channel ID IE
+ */
+ Q931InitIEChanID(&ChanID);
+ ChanID.IntType = ZAP_SPAN_IS_BRI(span) ? 0 : 1; /* PRI = 1, BRI = 0 */
+
+ if(!ZAP_SPAN_IS_NT(span)) {
+ ChanID.PrefExcl = (isdn_data->opts & ZAP_ISDN_OPT_SUGGEST_CHANNEL) ? 0 : 1; /* 0 = preferred, 1 exclusive */
+ } else {
+ ChanID.PrefExcl = 1; /* always exclusive in NT-mode */
+ }
+
+ if(ChanID.IntType) {
+ ChanID.InfoChanSel = 1; /* None = 0, See Slot = 1, Any = 3 */
+ ChanID.ChanMapType = 3; /* B-Chan */
+ ChanID.ChanSlot = (unsigned char)chan_id;
+ } else {
+ ChanID.InfoChanSel = (unsigned char)chan_id & 0x03; /* None = 0, B1 = 1, B2 = 2, Any = 3 */
+ }
+ gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID);
+
+ /*
+ * Progress IE
+ */
+ Q931InitIEProgInd(&Progress);
+ Progress.CodStand = Q931_CODING_ITU; /* 0 = ITU */
+ Progress.Location = 0; /* 0 = User, 1 = Private Network */
+ Progress.ProgDesc = 3; /* 1 = Not end-to-end ISDN */
+ gen->ProgInd = Q931AppendIE((L3UCHAR *)gen, (L3UCHAR *)&Progress);
+
+ /*
+ * Display IE
+ */
+ if (!(isdn_data->opts & ZAP_ISDN_OPT_OMIT_DISPLAY_IE)) {
+ Q931InitIEDisplay(&Display);
+ Display.Size = Display.Size + (unsigned char)strlen(caller_data->cid_name);
+ gen->Display = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &Display);
+ ptrDisplay = Q931GetIEPtr(gen->Display, gen->buf);
+ zap_copy_string((char *)ptrDisplay->Display, caller_data->cid_name, strlen(caller_data->cid_name)+1);
+ }
+
+ /*
+ * Calling Number IE
+ */
+ Q931InitIECallingNum(&CallingNum);
+ CallingNum.TypNum = Q931_TON_UNKNOWN;
+ CallingNum.NumPlanID = Q931_NUMPLAN_E164;
+ CallingNum.PresInd = Q931_PRES_ALLOWED;
+ CallingNum.ScreenInd = Q931_SCREEN_USER_NOT_SCREENED;
+ CallingNum.Size = CallingNum.Size + (unsigned char)strlen(caller_data->cid_num.digits);
+ gen->CallingNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CallingNum);
+ ptrCallingNum = Q931GetIEPtr(gen->CallingNum, gen->buf);
+ zap_copy_string((char *)ptrCallingNum->Digit, caller_data->cid_num.digits, strlen(caller_data->cid_num.digits)+1);
+
+
+ /*
+ * Called number IE
+ */
+ Q931InitIECalledNum(&CalledNum);
+ CalledNum.TypNum = Q931_TON_UNKNOWN;
+ CalledNum.NumPlanID = Q931_NUMPLAN_E164;
+ CalledNum.Size = CalledNum.Size + (unsigned char)strlen(caller_data->ani.digits);
+ gen->CalledNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CalledNum);
+ ptrCalledNum = Q931GetIEPtr(gen->CalledNum, gen->buf);
+ zap_copy_string((char *)ptrCalledNum->Digit, caller_data->ani.digits, strlen(caller_data->ani.digits)+1);
+
+ /*
+ * High-Layer Compatibility IE (Note: Required for AVM FritzBox)
+ */
+ Q931InitIEHLComp(&HLComp);
+ HLComp.CodStand = Q931_CODING_ITU; /* ITU */
+ HLComp.Interpret = 4; /* only possible value */
+ HLComp.PresMeth = 1; /* High-layer protocol profile */
+ HLComp.HLCharID = 1; /* Telephony = 1, Fax G2+3 = 4, Fax G4 = 65 (Class I)/ 68 (Class II or III) */
+ gen->HLComp = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &HLComp);
+
+ caller_data->call_state = ZAP_CALLER_STATE_DIALING;
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+
+ isdn_data->outbound_crv[gen->CRV] = caller_data;
+ //isdn_data->channels_local_crv[gen->CRV] = zchan;
+
+ while(zap_running() && caller_data->call_state == ZAP_CALLER_STATE_DIALING) {
+ zap_sleep(1);
+
+ if (!--sanity) {
+ caller_data->call_state = ZAP_CALLER_STATE_FAIL;
+ break;
+ }
+ }
+ isdn_data->outbound_crv[gen->CRV] = NULL;
+
+ if (caller_data->call_state == ZAP_CALLER_STATE_SUCCESS) {
+ zap_channel_t *new_chan = NULL;
+ int fail = 1;
+
+ new_chan = NULL;
+ if (caller_data->chan_id < ZAP_MAX_CHANNELS_SPAN && caller_data->chan_id <= span->chan_count) {
+ new_chan = span->channels[caller_data->chan_id];
+ }
+
+ if (new_chan && (status = zap_channel_open_chan(new_chan) == ZAP_SUCCESS)) {
+ if (zap_test_flag(new_chan, ZAP_CHANNEL_INUSE) || new_chan->state != ZAP_CHANNEL_STATE_DOWN) {
+ if (new_chan->state == ZAP_CHANNEL_STATE_DOWN || new_chan->state >= ZAP_CHANNEL_STATE_TERMINATING) {
+ int x = 0;
+ zap_log(ZAP_LOG_WARNING, "Channel %d:%d ~ %d:%d is already in use waiting for it to become available.\n");
+
+ for (x = 0; x < 200; x++) {
+ if (!zap_test_flag(new_chan, ZAP_CHANNEL_INUSE)) {
+ break;
+ }
+ zap_sleep(5);
+ }
+ }
+ if (zap_test_flag(new_chan, ZAP_CHANNEL_INUSE)) {
+ zap_log(ZAP_LOG_ERROR, "Channel %d:%d ~ %d:%d is already in use.\n",
+ new_chan->span_id,
+ new_chan->chan_id,
+ new_chan->physical_span_id,
+ new_chan->physical_chan_id
+ );
+ new_chan = NULL;
+ }
+ }
+
+ if (new_chan && new_chan->state == ZAP_CHANNEL_STATE_DOWN) {
+ isdn_data->channels_local_crv[gen->CRV] = new_chan;
+ memset(&new_chan->caller_data, 0, sizeof(new_chan->caller_data));
+ zap_set_flag(new_chan, ZAP_CHANNEL_OUTBOUND);
+ zap_set_state_locked(new_chan, ZAP_CHANNEL_STATE_DIALING);
+ switch(gen->MesType) {
+ case Q931mes_ALERTING:
+ new_chan->init_state = ZAP_CHANNEL_STATE_PROGRESS_MEDIA;
+ break;
+ case Q931mes_CONNECT:
+ new_chan->init_state = ZAP_CHANNEL_STATE_UP;
+ break;
+ default:
+ new_chan->init_state = ZAP_CHANNEL_STATE_PROGRESS;
+ break;
+ }
+
+ fail = 0;
+ }
+ }
+
+ if (!fail) {
+ *zchan = new_chan;
+ return ZAP_SUCCESS;
+ } else {
+ Q931ie_Cause cause;
+ gen->MesType = Q931mes_DISCONNECT;
+ cause.IEId = Q931ie_CAUSE;
+ cause.Size = sizeof(Q931ie_Cause);
+ cause.CodStand = 0;
+ cause.Location = 1;
+ cause.Recom = 1;
+ //should we be casting here.. or do we need to translate value?
+ cause.Value = (unsigned char) ZAP_CAUSE_WRONG_CALL_STATE;
+ *cause.Diag = '\0';
+ gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+
+ if (gen->CRV) {
+ Q931ReleaseCRV(&isdn_data->q931, gen->CRV);
+ }
+
+ if (new_chan) {
+ zap_log(ZAP_LOG_CRIT, "Channel is busy\n");
+ } else {
+ zap_log(ZAP_LOG_CRIT, "Failed to open channel for new setup message\n");
+ }
+ }
+ }
+
+ *zchan = NULL;
+ return ZAP_FAIL;
+
+}
+
+/**
+ * \brief Handler for Q931 error
+ * \param pvt Private structure (span?)
+ * \param id Error number
+ * \param p1 ??
+ * \param p2 ??
+ * \return 0
+ */
+static L3INT zap_isdn_931_err(void *pvt, L3INT id, L3INT p1, L3INT p2)
+{
+ zap_log(ZAP_LOG_ERROR, "ERROR: [%s] [%d] [%d]\n", q931_error_to_name(id), p1, p2);
+ return 0;
+}
+
+/**
+ * \brief Handler for Q931 event message
+ * \param pvt Span to handle
+ * \param msg Message string
+ * \param mlen Message string length
+ * \return 0
+ */
+static L3INT zap_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen)
+{
+ zap_span_t *span = (zap_span_t *) pvt;
+ zap_isdn_data_t *isdn_data = span->signal_data;
+ Q931mes_Generic *gen = (Q931mes_Generic *) msg;
+ uint32_t chan_id = 0;
+ int chan_hunt = 0;
+ zap_channel_t *zchan = NULL;
+ zap_caller_data_t *caller_data = NULL;
+
+ if (Q931IsIEPresent(gen->ChanID)) {
+ Q931ie_ChanID *chanid = Q931GetIEPtr(gen->ChanID, gen->buf);
+
+ if(chanid->IntType)
+ chan_id = chanid->ChanSlot;
+ else
+ chan_id = chanid->InfoChanSel;
+
+ /* "any" channel specified */
+ if(chanid->InfoChanSel == 3) {
+ chan_hunt++;
+ }
+ } else if (ZAP_SPAN_IS_NT(span)) {
+ /* no channel ie */
+ chan_hunt++;
+ }
+
+ assert(span != NULL);
+ assert(isdn_data != NULL);
+
+ zap_log(ZAP_LOG_DEBUG, "Yay I got an event! Type:[%02x] Size:[%d] CRV: %d (%#hx, CTX: %s)\n", gen->MesType, gen->Size, gen->CRV, gen->CRV, gen->CRVFlag ? "Terminator" : "Originator");
+
+ if (gen->CRVFlag && (caller_data = isdn_data->outbound_crv[gen->CRV])) {
+ if (chan_id) {
+ caller_data->chan_id = chan_id;
+ }
+
+ switch(gen->MesType) {
+ case Q931mes_STATUS:
+ case Q931mes_CALL_PROCEEDING:
+ break;
+ case Q931mes_ALERTING:
+ case Q931mes_PROGRESS:
+ case Q931mes_CONNECT:
+ {
+ caller_data->call_state = ZAP_CALLER_STATE_SUCCESS;
+ }
+ break;
+ default:
+ caller_data->call_state = ZAP_CALLER_STATE_FAIL;
+ break;
+ }
+
+ return 0;
+ }
+
+ if (gen->CRVFlag) {
+ zchan = isdn_data->channels_local_crv[gen->CRV];
+ } else {
+ zchan = isdn_data->channels_remote_crv[gen->CRV];
+ }
+
+ zap_log(ZAP_LOG_DEBUG, "zchan %x (%d:%d) source isdn_data->channels_%s_crv[%#hx]\n", zchan, zchan ? zchan->span_id : -1, zchan ? zchan->chan_id : -1, gen->CRVFlag ? "local" : "remote", gen->CRV);
+
+
+ if (gen->ProtDisc == 3) {
+ switch(gen->MesType) {
+ case Q931mes_SERVICE:
+ {
+ Q931ie_ChangeStatus *changestatus = Q931GetIEPtr(gen->ChangeStatus, gen->buf);
+ if (zchan) {
+ switch (changestatus->NewStatus) {
+ case 0: /* change status to "in service" */
+ {
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_SUSPENDED);
+ zap_log(ZAP_LOG_DEBUG, "Channel %d:%d in service\n", zchan->span_id, zchan->chan_id);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+ }
+ break;
+ case 1:
+ { /* change status to "maintenance" */
+ zap_set_flag_locked(zchan, ZAP_CHANNEL_SUSPENDED);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_SUSPENDED);
+ }
+ break;
+ case 2:
+ { /* change status to "out of service" */
+ zap_set_flag_locked(zchan, ZAP_CHANNEL_SUSPENDED);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_SUSPENDED);
+ }
+ break;
+ default: /* unknown */
+ {
+ break;
+ }
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch(gen->MesType) {
+ case Q931mes_RESTART:
+ {
+ if (chan_id) {
+ zchan = span->channels[chan_id];
+ }
+ if (zchan) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+ } else {
+ uint32_t i;
+ for (i = 1; i < span->chan_count; i++) {
+ zap_set_state_locked((span->channels[i]), ZAP_CHANNEL_STATE_RESTART);
+ }
+ }
+ }
+ break;
+ case Q931mes_RELEASE:
+ case Q931mes_RELEASE_COMPLETE:
+ {
+ const char *what = gen->MesType == Q931mes_RELEASE ? "Release" : "Release Complete";
+ if (zchan) {
+ if (zchan->state == ZAP_CHANNEL_STATE_TERMINATING || zchan->state == ZAP_CHANNEL_STATE_HANGUP) {
+ if (gen->MesType == Q931mes_RELEASE) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP_COMPLETE);
+ } else {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ }
+ }
+ else if((gen->MesType == Q931mes_RELEASE && zchan->state <= ZAP_CHANNEL_STATE_UP) ||
+ (gen->MesType == Q931mes_RELEASE_COMPLETE && zchan->state == ZAP_CHANNEL_STATE_DIALING)) {
+
+ /*
+ * Don't keep inbound channels open if the remote side hangs up before we answered
+ */
+ Q931ie_Cause *cause = Q931GetIEPtr(gen->Cause, gen->buf);
+ zap_sigmsg_t sig;
+ zap_status_t status;
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = zchan->chan_id;
+ sig.span_id = zchan->span_id;
+ sig.channel = zchan;
+ sig.channel->caller_data.hangup_cause = (cause) ? cause->Value : ZAP_CAUSE_NORMAL_UNSPECIFIED;
+
+ sig.event_id = ZAP_SIGEVENT_STOP;
+ status = zap_span_send_signal(zchan->span, &sig);
+
+ zap_log(ZAP_LOG_DEBUG, "Received %s in state %s, requested hangup for channel %d:%d\n", what, zap_channel_state2str(zchan->state), zchan->span_id, chan_id);
+ }
+ else {
+ zap_log(ZAP_LOG_DEBUG, "Ignoring %s on channel %d\n", what, chan_id);
+ }
+ } else {
+ zap_log(ZAP_LOG_CRIT, "Received %s with no matching channel %d\n", what, chan_id);
+ }
+ }
+ break;
+ case Q931mes_DISCONNECT:
+ {
+ if (zchan) {
+ Q931ie_Cause *cause = Q931GetIEPtr(gen->Cause, gen->buf);
+ zchan->caller_data.hangup_cause = cause->Value;
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_TERMINATING);
+ } else {
+ zap_log(ZAP_LOG_CRIT, "Received Disconnect with no matching channel %d\n", chan_id);
+ }
+ }
+ break;
+ case Q931mes_ALERTING:
+ {
+ if (zchan) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS_MEDIA);
+ } else {
+ zap_log(ZAP_LOG_CRIT, "Received Alerting with no matching channel %d\n", chan_id);
+ }
+ }
+ break;
+ case Q931mes_PROGRESS:
+ {
+ if (zchan) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS);
+ } else {
+ zap_log(ZAP_LOG_CRIT, "Received Progress with no matching channel %d\n", chan_id);
+ }
+ }
+ break;
+ case Q931mes_CONNECT:
+ {
+ if (zchan) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
+
+ gen->MesType = Q931mes_CONNECT_ACKNOWLEDGE;
+ gen->CRVFlag = 0; /* outbound */
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+ } else {
+ zap_log(ZAP_LOG_CRIT, "Received Connect with no matching channel %d\n", chan_id);
+ }
+ }
+ break;
+ case Q931mes_SETUP:
+ {
+ Q931ie_CallingNum *callingnum = Q931GetIEPtr(gen->CallingNum, gen->buf);
+ Q931ie_CalledNum *callednum = Q931GetIEPtr(gen->CalledNum, gen->buf);
+ int fail = 1;
+ int fail_cause = 0;
+ int overlap_dial = 0;
+ uint32_t cplen = mlen;
+
+ if(zchan && zchan == isdn_data->channels_remote_crv[gen->CRV]) {
+ zap_log(ZAP_LOG_INFO, "Duplicate SETUP message(?) for Channel %d:%d ~ %d:%d in state %s [ignoring]\n",
+ zchan->span_id,
+ zchan->chan_id,
+ zchan->physical_span_id,
+ zchan->physical_chan_id,
+ zap_channel_state2str(zchan->state));
+ break;
+ }
+
+ zchan = NULL;
+ /*
+ * Channel selection for incoming calls:
+ */
+ if (ZAP_SPAN_IS_NT(span) && chan_hunt) {
+ uint32_t x;
+
+ /*
+ * In NT-mode with channel selection "any",
+ * try to find a free channel
+ */
+ for (x = 1; x <= span->chan_count; x++) {
+ zap_channel_t *zc = span->channels[x];
+
+ if (!zap_test_flag(zc, ZAP_CHANNEL_INUSE) && zc->state == ZAP_CHANNEL_STATE_DOWN) {
+ zchan = zc;
+ break;
+ }
+ }
+ }
+ else if (!ZAP_SPAN_IS_NT(span) && chan_hunt) {
+ /*
+ * In TE-mode this ("any") is invalid
+ */
+ fail_cause = ZAP_CAUSE_CHANNEL_UNACCEPTABLE;
+
+ zap_log(ZAP_LOG_ERROR, "Invalid channel selection in incoming call (network side didn't specify a channel)\n");
+ }
+ else {
+ /*
+ * Otherwise simply try to select the channel we've been told
+ *
+ * TODO: NT mode is abled to select a different channel if the one chosen
+ * by the TE side is already in use
+ */
+ if (chan_id > 0 && chan_id < ZAP_MAX_CHANNELS_SPAN && chan_id <= span->chan_count) {
+ zchan = span->channels[chan_id];
+ }
+ else {
+ /* invalid channel id */
+ fail_cause = ZAP_CAUSE_CHANNEL_UNACCEPTABLE;
+
+ zap_log(ZAP_LOG_ERROR, "Invalid channel selection in incoming call (none selected or out of bounds)\n");
+ }
+ }
+
+ if (!callednum || !strlen((char *)callednum->Digit)) {
+ if (ZAP_SPAN_IS_NT(span)) {
+ zap_log(ZAP_LOG_NOTICE, "No destination number found, assuming overlap dial\n");
+ overlap_dial++;
+ }
+ else {
+ zap_log(ZAP_LOG_ERROR, "No destination number found\n");
+ zchan = NULL;
+ }
+ }
+
+ if (zchan) {
+ if (zap_test_flag(zchan, ZAP_CHANNEL_INUSE) || zchan->state != ZAP_CHANNEL_STATE_DOWN) {
+ if (zchan->state == ZAP_CHANNEL_STATE_DOWN || zchan->state >= ZAP_CHANNEL_STATE_TERMINATING) {
+ int x = 0;
+ zap_log(ZAP_LOG_WARNING, "Channel %d:%d ~ %d:%d is already in use waiting for it to become available.\n",
+ zchan->span_id,
+ zchan->chan_id,
+ zchan->physical_span_id,
+ zchan->physical_chan_id);
+
+ for (x = 0; x < 200; x++) {
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_INUSE)) {
+ break;
+ }
+ zap_sleep(5);
+ }
+ }
+ if (zap_test_flag(zchan, ZAP_CHANNEL_INUSE)) {
+ zap_log(ZAP_LOG_ERROR, "Channel %d:%d ~ %d:%d is already in use.\n",
+ zchan->span_id,
+ zchan->chan_id,
+ zchan->physical_span_id,
+ zchan->physical_chan_id
+ );
+ zchan = NULL;
+ }
+ }
+
+ if (zchan && zchan->state == ZAP_CHANNEL_STATE_DOWN) {
+ isdn_data->channels_remote_crv[gen->CRV] = zchan;
+ memset(&zchan->caller_data, 0, sizeof(zchan->caller_data));
+
+ if (zchan->mod_data) {
+ memset(zchan->mod_data, 0, sizeof(zap_isdn_bchan_data_t));
+ }
+
+ zap_set_string(zchan->caller_data.cid_num.digits, (char *)callingnum->Digit);
+ zap_set_string(zchan->caller_data.cid_name, (char *)callingnum->Digit);
+ zap_set_string(zchan->caller_data.ani.digits, (char *)callingnum->Digit);
+ if (!overlap_dial) {
+ zap_set_string(zchan->caller_data.dnis.digits, (char *)callednum->Digit);
+ }
+
+ zchan->caller_data.CRV = gen->CRV;
+ if (cplen > sizeof(zchan->caller_data.raw_data)) {
+ cplen = sizeof(zchan->caller_data.raw_data);
+ }
+ gen->CRVFlag = !(gen->CRVFlag);
+ memcpy(zchan->caller_data.raw_data, msg, cplen);
+ zchan->caller_data.raw_data_len = cplen;
+ fail = 0;
+ }
+ }
+
+ if (fail) {
+ Q931ie_Cause cause;
+ gen->MesType = Q931mes_DISCONNECT;
+ gen->CRVFlag = 1; /* inbound call */
+ cause.IEId = Q931ie_CAUSE;
+ cause.Size = sizeof(Q931ie_Cause);
+ cause.CodStand = Q931_CODING_ITU;
+ cause.Location = 1;
+ cause.Recom = 1;
+ //should we be casting here.. or do we need to translate value?
+ cause.Value = (unsigned char)((fail_cause) ? fail_cause : ZAP_CAUSE_WRONG_CALL_STATE);
+ *cause.Diag = '\0';
+ gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+
+ if (gen->CRV) {
+ Q931ReleaseCRV(&isdn_data->q931, gen->CRV);
+ }
+
+ if (zchan) {
+ zap_log(ZAP_LOG_CRIT, "Channel is busy\n");
+ } else {
+ zap_log(ZAP_LOG_CRIT, "Failed to open channel for new setup message\n");
+ }
+
+ } else {
+ Q931ie_ChanID ChanID;
+
+ /*
+ * Update Channel ID IE
+ */
+ Q931InitIEChanID(&ChanID);
+ ChanID.IntType = ZAP_SPAN_IS_BRI(zchan->span) ? 0 : 1; /* PRI = 1, BRI = 0 */
+ ChanID.PrefExcl = ZAP_SPAN_IS_NT(zchan->span) ? 1 : 0; /* Exclusive in NT-mode = 1, Preferred otherwise = 0 */
+ if(ChanID.IntType) {
+ ChanID.InfoChanSel = 1; /* None = 0, See Slot = 1, Any = 3 */
+ ChanID.ChanMapType = 3; /* B-Chan */
+ ChanID.ChanSlot = (unsigned char)zchan->chan_id;
+ } else {
+ ChanID.InfoChanSel = (unsigned char)zchan->chan_id & 0x03; /* None = 0, B1 = 1, B2 = 2, Any = 3 */
+ }
+ gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID);
+
+ if (overlap_dial) {
+ Q931ie_ProgInd progress;
+
+ /*
+ * Setup Progress indicator
+ */
+ progress.IEId = Q931ie_PROGRESS_INDICATOR;
+ progress.Size = sizeof(Q931ie_ProgInd);
+ progress.CodStand = Q931_CODING_ITU; /* ITU */
+ progress.Location = 1; /* private network serving the local user */
+ progress.ProgDesc = 8; /* call is not end-to-end isdn = 1, in-band information available = 8 */
+ gen->ProgInd = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &progress);
+
+ /*
+ * Send SETUP ACK
+ */
+ gen->MesType = Q931mes_SETUP_ACKNOWLEDGE;
+ gen->CRVFlag = 1; /* inbound call */
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DIALTONE);
+ } else {
+ /*
+ * Advance to RING state
+ */
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RING);
+ }
+ }
+ }
+ break;
+
+ case Q931mes_CALL_PROCEEDING:
+ {
+ if (zchan) {
+ zap_log(ZAP_LOG_CRIT, "Received CALL PROCEEDING message for channel %d\n", chan_id);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS);
+ } else {
+ zap_log(ZAP_LOG_CRIT, "Received CALL PROCEEDING with no matching channel %d\n", chan_id);
+ }
+ }
+ break;
+ case Q931mes_CONNECT_ACKNOWLEDGE:
+ {
+ if (zchan) {
+ zap_log(ZAP_LOG_DEBUG, "Received CONNECT_ACK message for channel %d\n", chan_id);
+ } else {
+ zap_log(ZAP_LOG_DEBUG, "Received CONNECT_ACK with no matching channel %d\n", chan_id);
+ }
+ }
+ break;
+
+ case Q931mes_INFORMATION:
+ {
+ if (zchan) {
+ zap_log(ZAP_LOG_CRIT, "Received INFORMATION message for channel %d\n", zchan->chan_id);
+
+ if (zchan->state == ZAP_CHANNEL_STATE_DIALTONE) {
+ char digit = '\0';
+
+ /*
+ * overlap dial digit indication
+ */
+ if (Q931IsIEPresent(gen->CalledNum)) {
+ zap_isdn_bchan_data_t *data = (zap_isdn_bchan_data_t *)zchan->mod_data;
+ Q931ie_CalledNum *callednum = Q931GetIEPtr(gen->CalledNum, gen->buf);
+ int pos;
+
+ digit = callednum->Digit[strlen((char *)callednum->Digit) - 1];
+ if (digit == '#') {
+ callednum->Digit[strlen((char *)callednum->Digit) - 1] = '\0';
+ }
+
+ /* TODO: make this more safe with strncat() */
+ pos = (int)strlen(zchan->caller_data.dnis.digits);
+ strcat(&zchan->caller_data.dnis.digits[pos], (char *)callednum->Digit);
+
+ /* update timer */
+ data->digit_timeout = zap_time_now() + isdn_data->digit_timeout;
+
+ zap_log(ZAP_LOG_DEBUG, "Received new overlap digit (%s), destination number: %s\n", callednum->Digit, zchan->caller_data.dnis.digits);
+ }
+
+ if (Q931IsIEPresent(gen->SendComplete) || digit == '#') {
+ zap_log(ZAP_LOG_DEBUG, "Leaving overlap dial mode\n");
+
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RING);
+ }
+ }
+ } else {
+ zap_log(ZAP_LOG_CRIT, "Received INFORMATION message with no matching channel\n");
+ }
+ }
+ break;
+
+ case Q931mes_STATUS_ENQUIRY:
+ {
+ /*
+ * !! HACK ALERT !!
+ *
+ * Map OpenZAP channel states to Q.931 states
+ */
+ Q931ie_CallState state;
+ Q931ie_Cause cause;
+
+ gen->MesType = Q931mes_STATUS;
+ gen->CRVFlag = gen->CRVFlag ? 0 : 1;
+
+ state.CodStand = Q931_CODING_ITU; /* ITU-T */
+ state.CallState = Q931_U0; /* Default: Null */
+
+ cause.IEId = Q931ie_CAUSE;
+ cause.Size = sizeof(Q931ie_Cause);
+ cause.CodStand = Q931_CODING_ITU; /* ITU */
+ cause.Location = 1; /* private network */
+ cause.Recom = 1; /* */
+ *cause.Diag = '\0';
+
+ if(zchan) {
+ switch(zchan->state) {
+ case ZAP_CHANNEL_STATE_UP:
+ state.CallState = Q931_U10; /* Active */
+ break;
+ case ZAP_CHANNEL_STATE_RING:
+ state.CallState = Q931_U6; /* Call present */
+ break;
+ case ZAP_CHANNEL_STATE_DIALING:
+ state.CallState = Q931_U1; /* Call initiated */
+ break;
+ case ZAP_CHANNEL_STATE_DIALTONE:
+ state.CallState = Q931_U25; /* Overlap receiving */
+ break;
+
+ /* TODO: map missing states */
+
+ default:
+ state.CallState = Q931_U0;
+ }
+
+ cause.Value = 30; /* response to STATUS ENQUIRY */
+ } else {
+ cause.Value = 98; /* */
+ }
+
+ gen->CallState = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &state);
+ gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+ }
+ break;
+
+ default:
+ zap_log(ZAP_LOG_CRIT, "Received unhandled message %d (%#x)\n", (int)gen->MesType, (int)gen->MesType);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Handler for Q921 read event
+ * \param pvt Span were message is coming from
+ * \param ind Q921 indication
+ * \param tei Terminal Endpoint Identifier
+ * \param msg Message string
+ * \param mlen Message string length
+ * \return 0 on success, 1 on failure
+ */
+static int zap_isdn_921_23(void *pvt, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *msg, L2INT mlen)
+{
+ int ret, offset = (ind == Q921_DL_DATA) ? 4 : 3;
+ char bb[4096] = "";
+
+ switch(ind) {
+ case Q921_DL_DATA:
+ case Q921_DL_UNIT_DATA:
+ print_hex_bytes(msg + offset, mlen - offset, bb, sizeof(bb));
+#ifdef HAVE_LIBPCAP
+ /*Q931ToPcap*/
+ if(do_q931ToPcap==1){
+ zap_span_t *span = (zap_span_t *) pvt;
+ if(writeQ931PacketToPcap(msg + offset, mlen - offset, span->span_id, 1) != ZAP_SUCCESS){
+ zap_log(ZAP_LOG_WARNING, "Couldn't write Q931 buffer to pcap file!\n");
+ }
+ }
+ /*Q931ToPcap done*/
+#endif
+ zap_log(ZAP_LOG_DEBUG, "READ %d\n%s\n%s\n\n\n", (int)mlen - offset, LINE, bb);
+
+ default:
+ ret = Q931Rx23(pvt, ind, tei, msg, mlen);
+ if (ret != 0)
+ zap_log(ZAP_LOG_DEBUG, "931 parse error [%d] [%s]\n", ret, q931_error_to_name(ret));
+ break;
+ }
+
+ return ((ret >= 0) ? 1 : 0);
+}
+
+/**
+ * \brief Handler for Q921 write event
+ * \param pvt Span were message is coming from
+ * \param msg Message string
+ * \param mlen Message string length
+ * \return 0 on success, -1 on failure
+ */
+static int zap_isdn_921_21(void *pvt, L2UCHAR *msg, L2INT mlen)
+{
+ zap_span_t *span = (zap_span_t *) pvt;
+ zap_size_t len = (zap_size_t) mlen;
+ zap_isdn_data_t *isdn_data = span->signal_data;
+
+#ifdef IODEBUG
+ char bb[4096] = "";
+ print_hex_bytes(msg, len, bb, sizeof(bb));
+ print_bits(msg, (int)len, bb, sizeof(bb), ZAP_ENDIAN_LITTLE, 0);
+ zap_log(ZAP_LOG_DEBUG, "WRITE %d\n%s\n%s\n\n", (int)len, LINE, bb);
+
+#endif
+
+ assert(span != NULL);
+ return zap_channel_write(isdn_data->dchan, msg, len, &len) == ZAP_SUCCESS ? 0 : -1;
+}
+
+/**
+ * \brief Handler for channel state change
+ * \param zchan Channel to handle
+ */
+static __inline__ void state_advance(zap_channel_t *zchan)
+{
+ Q931mes_Generic *gen = (Q931mes_Generic *) zchan->caller_data.raw_data;
+ zap_isdn_data_t *isdn_data = zchan->span->signal_data;
+ zap_sigmsg_t sig;
+ zap_status_t status;
+
+ zap_log(ZAP_LOG_DEBUG, "%d:%d STATE [%s]\n",
+ zchan->span_id, zchan->chan_id, zap_channel_state2str(zchan->state));
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = zchan->chan_id;
+ sig.span_id = zchan->span_id;
+ sig.channel = zchan;
+
+ switch (zchan->state) {
+ case ZAP_CHANNEL_STATE_DOWN:
+ {
+ if (gen->CRV) {
+ if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ isdn_data->channels_local_crv[gen->CRV] = NULL;
+ } else {
+ isdn_data->channels_remote_crv[gen->CRV] = NULL;
+ }
+ Q931ReleaseCRV(&isdn_data->q931, gen->CRV);
+ }
+ zap_channel_done(zchan);
+ }
+ break;
+ case ZAP_CHANNEL_STATE_PROGRESS:
+ {
+ if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ sig.event_id = ZAP_SIGEVENT_PROGRESS;
+ if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ } else {
+ gen->MesType = Q931mes_CALL_PROCEEDING;
+ gen->CRVFlag = 1; /* inbound */
+
+ if (ZAP_SPAN_IS_NT(zchan->span)) {
+ Q931ie_ChanID ChanID;
+
+ /*
+ * Set new Channel ID
+ */
+ Q931InitIEChanID(&ChanID);
+ ChanID.IntType = ZAP_SPAN_IS_BRI(zchan->span) ? 0 : 1; /* PRI = 1, BRI = 0 */
+ ChanID.PrefExcl = 1; /* always exclusive in NT-mode */
+
+ if(ChanID.IntType) {
+ ChanID.InfoChanSel = 1; /* None = 0, See Slot = 1, Any = 3 */
+ ChanID.ChanMapType = 3; /* B-Chan */
+ ChanID.ChanSlot = (unsigned char)zchan->chan_id;
+ } else {
+ ChanID.InfoChanSel = (unsigned char)zchan->chan_id & 0x03; /* None = 0, B1 = 1, B2 = 2, Any = 3 */
+ }
+ gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID);
+ }
+
+ Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_DIALTONE:
+ {
+ zap_isdn_bchan_data_t *data = (zap_isdn_bchan_data_t *)zchan->mod_data;
+
+ if (data) {
+ data->digit_timeout = zap_time_now() + isdn_data->digit_timeout;
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_RING:
+ {
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ sig.event_id = ZAP_SIGEVENT_START;
+ if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_RESTART:
+ {
+ zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_UNSPECIFIED;
+ sig.event_id = ZAP_SIGEVENT_RESTART;
+ status = zap_span_send_signal(zchan->span, &sig);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ }
+ break;
+ case ZAP_CHANNEL_STATE_PROGRESS_MEDIA:
+ {
+ if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ sig.event_id = ZAP_SIGEVENT_PROGRESS_MEDIA;
+ if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ } else {
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) {
+ if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ return;
+ }
+ }
+ gen->MesType = Q931mes_ALERTING;
+ gen->CRVFlag = 1; /* inbound call */
+ Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_UP:
+ {
+ if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ sig.event_id = ZAP_SIGEVENT_UP;
+ if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ } else {
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) {
+ if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ return;
+ }
+ }
+ gen->MesType = Q931mes_CONNECT;
+ gen->BearerCap = 0;
+ gen->CRVFlag = 1; /* inbound call */
+ Q931Rx43(&isdn_data->q931, (void *)gen, zchan->caller_data.raw_data_len);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_DIALING:
+ if (!(isdn_data->opts & ZAP_ISDN_OPT_SUGGEST_CHANNEL)) {
+ Q931ie_BearerCap BearerCap;
+ Q931ie_ChanID ChanID;
+ Q931ie_CallingNum CallingNum;
+ Q931ie_CallingNum *ptrCallingNum;
+ Q931ie_CalledNum CalledNum;
+ Q931ie_CalledNum *ptrCalledNum;
+ Q931ie_Display Display, *ptrDisplay;
+ Q931ie_HLComp HLComp; /* High-Layer Compatibility IE */
+ Q931ie_ProgInd Progress; /* Progress Indicator IE */
+ int codec = 0;
+
+ /*
+ * get codec type
+ */
+ zap_channel_command(zchan->span->channels[zchan->chan_id], ZAP_COMMAND_GET_NATIVE_CODEC, &codec);
+
+ /*
+ * Q.931 Setup Message
+ */
+ Q931InitMesGeneric(gen);
+ gen->MesType = Q931mes_SETUP;
+ gen->CRVFlag = 0; /* outbound(?) */
+
+ /*
+ * Bearer Capability IE
+ */
+ Q931InitIEBearerCap(&BearerCap);
+ BearerCap.CodStand = Q931_CODING_ITU; /* ITU-T = 0, ISO/IEC = 1, National = 2, Network = 3 */
+ BearerCap.ITC = Q931_ITC_SPEECH; /* Speech */
+ BearerCap.TransMode = 0; /* Circuit = 0, Packet = 1 */
+ BearerCap.ITR = Q931_ITR_64K; /* 64k = 16, Packet mode = 0 */
+ BearerCap.Layer1Ident = 1;
+ BearerCap.UIL1Prot = (codec == ZAP_CODEC_ALAW) ? 3 : 2; /* U-law = 2, A-law = 3 */
+ gen->BearerCap = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &BearerCap);
+
+ /*
+ * ChannelID IE
+ */
+ Q931InitIEChanID(&ChanID);
+ ChanID.IntType = ZAP_SPAN_IS_BRI(zchan->span) ? 0 : 1; /* PRI = 1, BRI = 0 */
+ ChanID.PrefExcl = ZAP_SPAN_IS_NT(zchan->span) ? 1 : 0; /* Exclusive in NT-mode = 1, Preferred otherwise = 0 */
+ if(ChanID.IntType) {
+ ChanID.InfoChanSel = 1; /* None = 0, See Slot = 1, Any = 3 */
+ ChanID.ChanMapType = 3; /* B-Chan */
+ ChanID.ChanSlot = (unsigned char)zchan->chan_id;
+ } else {
+ ChanID.InfoChanSel = (unsigned char)zchan->chan_id & 0x03; /* None = 0, B1 = 1, B2 = 2, Any = 3 */
+ }
+ gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID);
+
+ /*
+ * Progress IE
+ */
+ Q931InitIEProgInd(&Progress);
+ Progress.CodStand = Q931_CODING_ITU; /* 0 = ITU */
+ Progress.Location = 0; /* 0 = User, 1 = Private Network */
+ Progress.ProgDesc = 3; /* 1 = Not end-to-end ISDN */
+ gen->ProgInd = Q931AppendIE((L3UCHAR *)gen, (L3UCHAR *)&Progress);
+
+ /*
+ * Display IE
+ */
+ if (!(isdn_data->opts & ZAP_ISDN_OPT_OMIT_DISPLAY_IE)) {
+ Q931InitIEDisplay(&Display);
+ Display.Size = Display.Size + (unsigned char)strlen(zchan->caller_data.cid_name);
+ gen->Display = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &Display);
+ ptrDisplay = Q931GetIEPtr(gen->Display, gen->buf);
+ zap_copy_string((char *)ptrDisplay->Display, zchan->caller_data.cid_name, strlen(zchan->caller_data.cid_name)+1);
+ }
+
+ /*
+ * CallingNum IE
+ */
+ Q931InitIECallingNum(&CallingNum);
+ CallingNum.TypNum = zchan->caller_data.ani.type;
+ CallingNum.NumPlanID = Q931_NUMPLAN_E164;
+ CallingNum.PresInd = Q931_PRES_ALLOWED;
+ CallingNum.ScreenInd = Q931_SCREEN_USER_NOT_SCREENED;
+ CallingNum.Size = CallingNum.Size + (unsigned char)strlen(zchan->caller_data.cid_num.digits);
+ gen->CallingNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CallingNum);
+ ptrCallingNum = Q931GetIEPtr(gen->CallingNum, gen->buf);
+ zap_copy_string((char *)ptrCallingNum->Digit, zchan->caller_data.cid_num.digits, strlen(zchan->caller_data.cid_num.digits)+1);
+
+ /*
+ * CalledNum IE
+ */
+ Q931InitIECalledNum(&CalledNum);
+ CalledNum.TypNum = Q931_TON_UNKNOWN;
+ CalledNum.NumPlanID = Q931_NUMPLAN_E164;
+ CalledNum.Size = CalledNum.Size + (unsigned char)strlen(zchan->caller_data.ani.digits);
+ gen->CalledNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CalledNum);
+ ptrCalledNum = Q931GetIEPtr(gen->CalledNum, gen->buf);
+ zap_copy_string((char *)ptrCalledNum->Digit, zchan->caller_data.ani.digits, strlen(zchan->caller_data.ani.digits)+1);
+
+ /*
+ * High-Layer Compatibility IE (Note: Required for AVM FritzBox)
+ */
+ Q931InitIEHLComp(&HLComp);
+ HLComp.CodStand = Q931_CODING_ITU; /* ITU */
+ HLComp.Interpret = 4; /* only possible value */
+ HLComp.PresMeth = 1; /* High-layer protocol profile */
+ HLComp.HLCharID = Q931_HLCHAR_TELEPHONY; /* Telephony = 1, Fax G2+3 = 4, Fax G4 = 65 (Class I)/ 68 (Class II or III) */ /* TODO: make accessible from user layer */
+ gen->HLComp = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &HLComp);
+
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+ isdn_data->channels_local_crv[gen->CRV] = zchan;
+ }
+ break;
+ case ZAP_CHANNEL_STATE_HANGUP_COMPLETE:
+ {
+ /* reply RELEASE with RELEASE_COMPLETE message */
+ if(zchan->last_state == ZAP_CHANNEL_STATE_HANGUP) {
+ gen->MesType = Q931mes_RELEASE_COMPLETE;
+
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+ }
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ }
+ break;
+ case ZAP_CHANNEL_STATE_HANGUP:
+ {
+ Q931ie_Cause cause;
+
+ zap_log(ZAP_LOG_DEBUG, "Hangup: Direction %s\n", zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND) ? "Outbound" : "Inbound");
+
+ gen->CRVFlag = zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND) ? 0 : 1;
+
+ cause.IEId = Q931ie_CAUSE;
+ cause.Size = sizeof(Q931ie_Cause);
+ cause.CodStand = Q931_CODING_ITU; /* ITU */
+ cause.Location = 1; /* private network */
+ cause.Recom = 1; /* */
+
+ /*
+ * BRI PTMP needs special handling here...
+ * TODO: cleanup / refine (see above)
+ */
+ if (zchan->last_state == ZAP_CHANNEL_STATE_RING) {
+ /*
+ * inbound call [was: number unknown (= not found in routing state)]
+ * (in Q.931 spec terms: Reject request)
+ */
+ gen->MesType = Q931mes_RELEASE_COMPLETE;
+
+ //cause.Value = (unsigned char) ZAP_CAUSE_UNALLOCATED;
+ cause.Value = (unsigned char) zchan->caller_data.hangup_cause;
+ *cause.Diag = '\0';
+ gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+
+ /* we're done, release channel */
+ //zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP_COMPLETE);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ }
+ else if (zchan->last_state <= ZAP_CHANNEL_STATE_PROGRESS) {
+ /*
+ * just release all unanswered calls [was: inbound call, remote side hung up before we answered]
+ */
+ gen->MesType = Q931mes_RELEASE;
+
+ cause.Value = (unsigned char) zchan->caller_data.hangup_cause;
+ *cause.Diag = '\0';
+ gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+ Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size);
+
+ /* this will be triggered by the RELEASE_COMPLETE reply */
+ /* zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP_COMPLETE); */
+ }
+ else {
+ /*
+ * call connected, hangup
+ */
+ gen->MesType = Q931mes_DISCONNECT;
+
+ cause.Value = (unsigned char) zchan->caller_data.hangup_cause;
+ *cause.Diag = '\0';
+ gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+ Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_TERMINATING:
+ {
+ zap_log(ZAP_LOG_DEBUG, "Terminating: Direction %s\n", zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND) ? "Outbound" : "Inbound");
+
+ sig.event_id = ZAP_SIGEVENT_STOP;
+ status = zap_span_send_signal(zchan->span, &sig);
+ gen->MesType = Q931mes_RELEASE;
+ gen->CRVFlag = zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND) ? 0 : 1;
+ Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size);
+ }
+ default:
+ break;
+ }
+}
+
+/**
+ * \brief Checks current state on a span
+ * \param span Span to check status on
+ */
+static __inline__ void check_state(zap_span_t *span)
+{
+ if (zap_test_flag(span, ZAP_SPAN_STATE_CHANGE)) {
+ uint32_t j;
+ zap_clear_flag_locked(span, ZAP_SPAN_STATE_CHANGE);
+ for(j = 1; j <= span->chan_count; j++) {
+ if (zap_test_flag((span->channels[j]), ZAP_CHANNEL_STATE_CHANGE)) {
+ zap_mutex_lock(span->channels[j]->mutex);
+ zap_clear_flag((span->channels[j]), ZAP_CHANNEL_STATE_CHANGE);
+ state_advance(span->channels[j]);
+ zap_channel_complete_state(span->channels[j]);
+ zap_mutex_unlock(span->channels[j]->mutex);
+ }
+ }
+ }
+}
+
+/**
+ * \brief Processes Openzap event on a span
+ * \param span Span to process event on
+ * \param event Event to process
+ * \return Success or failure
+ */
+static __inline__ zap_status_t process_event(zap_span_t *span, zap_event_t *event)
+{
+ zap_log(ZAP_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n",
+ zap_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, zap_channel_state2str(event->channel->state));
+
+ switch(event->enum_id) {
+ case ZAP_OOB_ALARM_TRAP:
+ {
+ if (event->channel->state != ZAP_CHANNEL_STATE_DOWN) {
+ if (event->channel->type == ZAP_CHAN_TYPE_B) {
+ zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_RESTART);
+ }
+ }
+
+
+ zap_set_flag(event->channel, ZAP_CHANNEL_SUSPENDED);
+
+
+ zap_channel_get_alarms(event->channel);
+ zap_log(ZAP_LOG_WARNING, "channel %d:%d (%d:%d) has alarms! [%s]\n",
+ event->channel->span_id, event->channel->chan_id,
+ event->channel->physical_span_id, event->channel->physical_chan_id,
+ event->channel->last_error);
+ }
+ break;
+ case ZAP_OOB_ALARM_CLEAR:
+ {
+
+ zap_log(ZAP_LOG_WARNING, "channel %d:%d (%d:%d) alarms Cleared!\n", event->channel->span_id, event->channel->chan_id,
+ event->channel->physical_span_id, event->channel->physical_chan_id);
+
+ zap_clear_flag(event->channel, ZAP_CHANNEL_SUSPENDED);
+ zap_channel_get_alarms(event->channel);
+ }
+ break;
+ }
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Checks for events on a span
+ * \param span Span to check for events
+ */
+static __inline__ void check_events(zap_span_t *span)
+{
+ zap_status_t status;
+
+ status = zap_span_poll_event(span, 5);
+
+ switch(status) {
+ case ZAP_SUCCESS:
+ {
+ zap_event_t *event;
+ while (zap_span_next_event(span, &event) == ZAP_SUCCESS) {
+ if (event->enum_id == ZAP_OOB_NOOP) {
+ continue;
+ }
+ if (process_event(span, event) != ZAP_SUCCESS) {
+ break;
+ }
+ }
+ }
+ break;
+ case ZAP_FAIL:
+ {
+ zap_log(ZAP_LOG_DEBUG, "Event Failure! %d\n", zap_running());
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * \brief Retrieves tone generation output to be sent
+ * \param ts Teletone generator
+ * \param map Tone map
+ * \return -1 on error, 0 on success
+ */
+static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+ zap_buffer_t *dt_buffer = ts->user_data;
+ int wrote;
+
+ if (!dt_buffer) {
+ return -1;
+ }
+ wrote = teletone_mux_tones(ts, map);
+ zap_buffer_write(dt_buffer, ts->buffer, wrote * 2);
+ return 0;
+}
+
+/**
+ * \brief Main thread function for tone generation on a span
+ * \param me Current thread
+ * \param obj Span to generate tones on
+ */
+static void *zap_isdn_tones_run(zap_thread_t *me, void *obj)
+{
+ zap_span_t *span = (zap_span_t *) obj;
+ zap_isdn_data_t *isdn_data = span->signal_data;
+ zap_buffer_t *dt_buffer = NULL;
+ teletone_generation_session_t ts = {{{{0}}}};
+ unsigned char frame[1024];
+ uint32_t x;
+ int interval = 0;
+ int offset = 0;
+
+ zap_log(ZAP_LOG_DEBUG, "ISDN tones thread starting.\n");
+ zap_set_flag(isdn_data, ZAP_ISDN_TONES_RUNNING);
+
+ if (zap_buffer_create(&dt_buffer, 1024, 1024, 0) != ZAP_SUCCESS) {
+ snprintf(isdn_data->dchan->last_error, sizeof(isdn_data->dchan->last_error), "memory error!");
+ zap_log(ZAP_LOG_ERROR, "MEM ERROR\n");
+ goto done;
+ }
+ zap_buffer_set_loops(dt_buffer, -1);
+
+ /* get a tone generation friendly interval to avoid distortions */
+ for (x = 1; x <= span->chan_count; x++) {
+ if (span->channels[x]->type != ZAP_CHAN_TYPE_DQ921) {
+ zap_channel_command(span->channels[x], ZAP_COMMAND_GET_INTERVAL, &interval);
+ break;
+ }
+ }
+ if (!interval) {
+ interval = 20;
+ }
+ zap_log(ZAP_LOG_NOTICE, "Tone generating interval %d\n", interval);
+
+ /* init teletone */
+ teletone_init_session(&ts, 0, teletone_handler, dt_buffer);
+ ts.rate = 8000;
+ ts.duration = ts.rate;
+
+ /* main loop */
+ while(zap_running() && zap_test_flag(isdn_data, ZAP_ISDN_TONES_RUNNING) && !zap_test_flag(isdn_data, ZAP_ISDN_STOP)) {
+ zap_wait_flag_t flags;
+ zap_status_t status;
+ int last_chan_state = 0;
+ int gated = 0;
+ L2ULONG now = zap_time_now();
+
+ /*
+ * check b-channel states and generate & send tones if neccessary
+ */
+ for (x = 1; x <= span->chan_count; x++) {
+ zap_channel_t *zchan = span->channels[x];
+ zap_size_t len = sizeof(frame), rlen;
+
+ if (zchan->type == ZAP_CHAN_TYPE_DQ921) {
+ continue;
+ }
+
+ /*
+ * Generate tones based on current bchan state
+ * (Recycle buffer content if succeeding channels share the
+ * same state, this saves some cpu cycles)
+ */
+ switch (zchan->state) {
+ case ZAP_CHANNEL_STATE_DIALTONE:
+ {
+ zap_isdn_bchan_data_t *data = (zap_isdn_bchan_data_t *)zchan->mod_data;
+
+ /* check overlap dial timeout first before generating tone */
+ if (data && data->digit_timeout && data->digit_timeout <= now) {
+ if (strlen(zchan->caller_data.dnis.digits) > 0) {
+ zap_log(ZAP_LOG_DEBUG, "Overlap dial timeout, advancing to RING state\n");
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RING);
+ } else {
+ /* no digits received, hangup */
+ zap_log(ZAP_LOG_DEBUG, "Overlap dial timeout, no digits received, going to HANGUP state\n");
+ zchan->caller_data.hangup_cause = ZAP_CAUSE_RECOVERY_ON_TIMER_EXPIRE; /* TODO: probably wrong cause value */
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ data->digit_timeout = 0;
+ continue;
+ }
+
+ if (last_chan_state != zchan->state) {
+ zap_buffer_zero(dt_buffer);
+ teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_DIAL]);
+ last_chan_state = zchan->state;
+ }
+ }
+ break;
+
+ case ZAP_CHANNEL_STATE_RING:
+ {
+ if (last_chan_state != zchan->state) {
+ zap_buffer_zero(dt_buffer);
+ teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_RING]);
+ last_chan_state = zchan->state;
+ }
+ }
+ break;
+
+ default: /* Not in a tone generating state, go to next round */
+ continue;
+ }
+
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) {
+ if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ continue;
+ }
+ zap_log(ZAP_LOG_NOTICE, "Successfully opened channel %d:%d\n", zchan->span_id, zchan->chan_id);
+ }
+
+ flags = ZAP_READ;
+
+ status = zap_channel_wait(zchan, &flags, (gated) ? 0 : interval);
+ switch(status) {
+ case ZAP_FAIL:
+ continue;
+
+ case ZAP_TIMEOUT:
+ gated = 1;
+ continue;
+
+ default:
+ if (!(flags & ZAP_READ)) {
+ continue;
+ }
+ }
+ gated = 1;
+
+ status = zap_channel_read(zchan, frame, &len);
+ if (status != ZAP_SUCCESS || len <= 0) {
+ continue;
+ }
+
+ if (zchan->effective_codec != ZAP_CODEC_SLIN) {
+ len *= 2;
+ }
+
+ /* seek to current offset */
+ zap_buffer_seek(dt_buffer, offset);
+
+ rlen = zap_buffer_read_loop(dt_buffer, frame, len);
+
+ if (zchan->effective_codec != ZAP_CODEC_SLIN) {
+ zio_codec_t codec_func = NULL;
+
+ if (zchan->native_codec == ZAP_CODEC_ULAW) {
+ codec_func = zio_slin2ulaw;
+ } else if (zchan->native_codec == ZAP_CODEC_ALAW) {
+ codec_func = zio_slin2alaw;
+ }
+
+ if (codec_func) {
+ status = codec_func(frame, sizeof(frame), &rlen);
+ } else {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "codec error!");
+ goto done;
+ }
+ }
+ zap_channel_write(zchan, frame, sizeof(frame), &rlen);
+ }
+
+ /*
+ * sleep a bit if there was nothing to do
+ */
+ if (!gated) {
+ zap_sleep(interval);
+ }
+
+ offset += (ts.rate / (1000 / interval)) << 1;
+ if (offset >= ts.rate) {
+ offset = 0;
+ }
+ }
+
+done:
+ if (ts.buffer) {
+ teletone_destroy_session(&ts);
+ }
+
+ if (dt_buffer) {
+ zap_buffer_destroy(&dt_buffer);
+ }
+
+ zap_log(ZAP_LOG_DEBUG, "ISDN tone thread ended.\n");
+ zap_clear_flag(isdn_data, ZAP_ISDN_TONES_RUNNING);
+
+ return NULL;
+}
+
+/**
+ * \brief Main thread function for an ISDN span
+ * \param me Current thread
+ * \param obj Span to monitor
+ */
+static void *zap_isdn_run(zap_thread_t *me, void *obj)
+{
+ zap_span_t *span = (zap_span_t *) obj;
+ zap_isdn_data_t *isdn_data = span->signal_data;
+ unsigned char frame[1024];
+ zap_size_t len = sizeof(frame);
+ int errs = 0;
+
+#ifdef WIN32
+ timeBeginPeriod(1);
+#endif
+
+ zap_log(ZAP_LOG_DEBUG, "ISDN thread starting.\n");
+ zap_set_flag(isdn_data, ZAP_ISDN_RUNNING);
+
+ Q921Start(&isdn_data->q921);
+
+ while(zap_running() && zap_test_flag(isdn_data, ZAP_ISDN_RUNNING) && !zap_test_flag(isdn_data, ZAP_ISDN_STOP)) {
+ zap_wait_flag_t flags = ZAP_READ;
+ zap_status_t status = zap_channel_wait(isdn_data->dchan, &flags, 100);
+
+ Q921TimerTick(&isdn_data->q921);
+ Q931TimerTick(&isdn_data->q931);
+ check_state(span);
+ check_events(span);
+
+ /*
+ *
+ */
+ switch(status) {
+ case ZAP_FAIL:
+ {
+ zap_log(ZAP_LOG_ERROR, "D-Chan Read Error!\n");
+ snprintf(span->last_error, sizeof(span->last_error), "D-Chan Read Error!");
+ if (++errs == 10) {
+ isdn_data->dchan->state = ZAP_CHANNEL_STATE_UP;
+ goto done;
+ }
+ }
+ break;
+ case ZAP_TIMEOUT:
+ {
+ errs = 0;
+ }
+ break;
+ default:
+ {
+ errs = 0;
+ if (flags & ZAP_READ) {
+
+ if (zap_test_flag(isdn_data->dchan, ZAP_CHANNEL_SUSPENDED)) {
+ zap_clear_flag_all(span, ZAP_CHANNEL_SUSPENDED);
+ }
+ len = sizeof(frame);
+ if (zap_channel_read(isdn_data->dchan, frame, &len) == ZAP_SUCCESS) {
+#ifdef IODEBUG
+ char bb[4096] = "";
+ print_hex_bytes(frame, len, bb, sizeof(bb));
+
+ print_bits(frame, (int)len, bb, sizeof(bb), ZAP_ENDIAN_LITTLE, 0);
+ zap_log(ZAP_LOG_DEBUG, "READ %d\n%s\n%s\n\n", (int)len, LINE, bb);
+#endif
+
+ Q921QueueHDLCFrame(&isdn_data->q921, frame, (int)len);
+ Q921Rx12(&isdn_data->q921);
+ }
+ } else {
+ zap_log(ZAP_LOG_DEBUG, "No Read FLAG!\n");
+ }
+ }
+ break;
+ }
+ }
+
+ done:
+ zap_channel_close(&isdn_data->dchans[0]);
+ zap_channel_close(&isdn_data->dchans[1]);
+ zap_clear_flag(isdn_data, ZAP_ISDN_RUNNING);
+
+#ifdef WIN32
+ timeEndPeriod(1);
+#endif
+
+ zap_log(ZAP_LOG_DEBUG, "ISDN thread ended.\n");
+ return NULL;
+}
+
+/**
+ * \brief Openzap ISDN signaling module initialisation
+ * \return Success
+ */
+static ZIO_SIG_LOAD_FUNCTION(zap_isdn_init)
+{
+ Q931Initialize();
+
+ Q921SetGetTimeCB(zap_time_now);
+ Q931SetGetTimeCB(zap_time_now);
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Receives a Q931 indication message
+ * \param pvt Span were message is coming from
+ * \param ind Q931 indication
+ * \param tei Terminal Endpoint Identifier
+ * \param msg Message string
+ * \param mlen Message string length
+ * \return 0 on success
+ */
+static int q931_rx_32(void *pvt, Q921DLMsg_t ind, L3UCHAR tei, L3UCHAR *msg, L3INT mlen)
+{
+ int offset = 4;
+ char bb[4096] = "";
+
+ switch(ind) {
+ case Q921_DL_UNIT_DATA:
+ offset = 3;
+
+ case Q921_DL_DATA:
+ print_hex_bytes(msg + offset, mlen - offset, bb, sizeof(bb));
+#ifdef HAVE_LIBPCAP
+ /*Q931ToPcap*/
+ if(do_q931ToPcap==1){
+ zap_span_t *span = (zap_span_t *) pvt;
+ if(writeQ931PacketToPcap(msg + offset, mlen - offset, span->span_id, 0) != ZAP_SUCCESS){
+ zap_log(ZAP_LOG_WARNING, "Couldn't write Q931 buffer to pcap file!\n");
+ }
+ }
+ /*Q931ToPcap done*/
+#endif
+ zap_log(ZAP_LOG_DEBUG, "WRITE %d\n%s\n%s\n\n", (int)mlen - offset, LINE, bb);
+ break;
+
+ default:
+ break;
+ }
+
+ return Q921Rx32(pvt, ind, tei, msg, mlen);
+}
+
+/**
+ * \brief Logs Q921 message
+ * \param pvt Span were message is coming from
+ * \param level Q921 log level
+ * \param msg Message string
+ * \param size Message string length
+ * \return 0
+ */
+static int zap_isdn_q921_log(void *pvt, Q921LogLevel_t level, char *msg, L2INT size)
+{
+ zap_span_t *span = (zap_span_t *) pvt;
+
+ zap_log("Span", "Q.921", span->span_id, (int)level, "%s", msg);
+ return 0;
+}
+
+/**
+ * \brief Logs Q931 message
+ * \param pvt Span were message is coming from
+ * \param level Q931 log level
+ * \param msg Message string
+ * \param size Message string length
+ * \return 0
+ */
+static L3INT zap_isdn_q931_log(void *pvt, Q931LogLevel_t level, char *msg, L3INT size)
+{
+ zap_span_t *span = (zap_span_t *) pvt;
+
+ zap_log("Span", "Q.931", span->span_id, (int)level, "%s", msg);
+ return 0;
+}
+/**
+ * \brief ISDN state map
+ */
+static zap_state_map_t isdn_state_map = {
+ {
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_ANY_STATE},
+ {ZAP_CHANNEL_STATE_RESTART, ZAP_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_RESTART, ZAP_END},
+ {ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+ {ZAP_CHANNEL_STATE_DIALING, ZAP_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_DIALING, ZAP_END},
+ {ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_UP, ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_PROGRESS, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_UP, ZAP_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_END},
+ {ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_UP, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END}
+ },
+
+ /****************************************/
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_ANY_STATE},
+ {ZAP_CHANNEL_STATE_RESTART, ZAP_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_RESTART, ZAP_END},
+ {ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+ {ZAP_CHANNEL_STATE_DIALTONE, ZAP_CHANNEL_STATE_RING, ZAP_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_DIALTONE, ZAP_END},
+ {ZAP_CHANNEL_STATE_RING, ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_RING, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_UP, ZAP_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_END},
+ {ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_PROGRESS_MEDIA,
+ ZAP_CHANNEL_STATE_CANCEL, ZAP_CHANNEL_STATE_UP, ZAP_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_UP, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+ },
+
+
+ }
+};
+
+/**
+ * \brief Stops an ISDN span
+ * \param span Span to halt
+ * \return Success
+ *
+ * Sets a stop flag and waits for the threads to end
+ */
+static zap_status_t zap_isdn_stop(zap_span_t *span)
+{
+ zap_isdn_data_t *isdn_data = span->signal_data;
+
+ if (!zap_test_flag(isdn_data, ZAP_ISDN_RUNNING)) {
+ return ZAP_FAIL;
+ }
+
+ zap_set_flag(isdn_data, ZAP_ISDN_STOP);
+
+ while(zap_test_flag(isdn_data, ZAP_ISDN_RUNNING)) {
+ zap_sleep(100);
+ }
+
+ while(zap_test_flag(isdn_data, ZAP_ISDN_TONES_RUNNING)) {
+ zap_sleep(100);
+ }
+
+ return ZAP_SUCCESS;
+
+}
+
+/**
+ * \brief Starts an ISDN span
+ * \param span Span to halt
+ * \return Success or failure
+ *
+ * Launches a thread to monitor the span and a thread to generate tones on the span
+ */
+static zap_status_t zap_isdn_start(zap_span_t *span)
+{
+ zap_status_t ret;
+ zap_isdn_data_t *isdn_data = span->signal_data;
+
+ if (zap_test_flag(isdn_data, ZAP_ISDN_RUNNING)) {
+ return ZAP_FAIL;
+ }
+
+ zap_clear_flag(isdn_data, ZAP_ISDN_STOP);
+ ret = zap_thread_create_detached(zap_isdn_run, span);
+
+ if (ret != ZAP_SUCCESS) {
+ return ret;
+ }
+
+ if (ZAP_SPAN_IS_NT(span) && !(isdn_data->opts & ZAP_ISDN_OPT_DISABLE_TONES)) {
+ ret = zap_thread_create_detached(zap_isdn_tones_run, span);
+ }
+ return ret;
+}
+
+/**
+ * \brief Parses an option string to flags
+ * \param in String to parse for configuration options
+ * \return Flags
+ */
+static uint32_t parse_opts(const char *in)
+{
+ uint32_t flags = 0;
+
+ if (!in) {
+ return 0;
+ }
+
+ if (strstr(in, "suggest_channel")) {
+ flags |= ZAP_ISDN_OPT_SUGGEST_CHANNEL;
+ }
+
+ if (strstr(in, "omit_display")) {
+ flags |= ZAP_ISDN_OPT_OMIT_DISPLAY_IE;
+ }
+
+ if (strstr(in, "disable_tones")) {
+ flags |= ZAP_ISDN_OPT_DISABLE_TONES;
+ }
+
+ return flags;
+}
+
+/**
+ * \brief Initialises an ISDN span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static ZIO_SIG_CONFIGURE_FUNCTION(zap_isdn_configure_span)
+{
+ uint32_t i, x = 0;
+ zap_channel_t *dchans[2] = {0};
+ zap_isdn_data_t *isdn_data;
+ const char *tonemap = "us";
+ char *var, *val;
+ Q931Dialect_t dialect = Q931_Dialect_National;
+ int32_t digit_timeout = 0;
+ int q921loglevel = -1;
+ int q931loglevel = -1;
+#ifdef HAVE_LIBPCAP
+ int q931topcap = -1; /*Q931ToPcap*/
+ int openPcap = 0; /*Flag: open Pcap file please*/
+#endif
+
+ if (span->signal_type) {
+#ifdef HAVE_LIBPCAP
+ /*Q931ToPcap: Get the content of the q931topcap and pcapfilename args given by mod_openzap */
+ while((var = va_arg(ap, char *))) {
+ if (!strcasecmp(var, "q931topcap")) {
+ q931topcap = va_arg(ap, int);
+ if(q931topcap==1) {
+ /*PCAP on*/;
+ openPcap=1;
+ } else if (q931topcap==0) {
+ /*PCAP off*/
+ if (closePcapFile() != ZAP_SUCCESS) return ZAP_FAIL;
+ do_q931ToPcap=0;
+ return ZAP_SUCCESS;
+ }
+ }
+ if (!strcasecmp(var, "pcapfilename")) {
+ /*Put filename into global var*/
+ pcapfn = va_arg(ap, char*);
+ }
+ }
+ /*We know now, that user wants to enable Q931ToPcap and what file name he wants, so open it please*/
+ if(openPcap==1){
+ if(openPcapFile() != ZAP_SUCCESS) return ZAP_FAIL;
+ do_q931ToPcap=1;
+ return ZAP_SUCCESS;
+ }
+ /*Q931ToPcap done*/
+#endif
+ snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling [%d].", span->signal_type);
+ return ZAP_FAIL;
+ }
+
+ if (span->trunk_type >= ZAP_TRUNK_NONE) {
+ zap_log(ZAP_LOG_WARNING, "Invalid trunk type '%s' defaulting to T1.\n", zap_trunk_type2str(span->trunk_type));
+ span->trunk_type = ZAP_TRUNK_T1;
+ }
+
+ for(i = 1; i <= span->chan_count; i++) {
+ if (span->channels[i]->type == ZAP_CHAN_TYPE_DQ921) {
+ if (x > 1) {
+ snprintf(span->last_error, sizeof(span->last_error), "Span has more than 2 D-Channels!");
+ return ZAP_FAIL;
+ } else {
+ if (zap_channel_open(span->span_id, i, &dchans[x]) == ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_DEBUG, "opening d-channel #%d %d:%d\n", x, dchans[x]->span_id, dchans[x]->chan_id);
+ dchans[x]->state = ZAP_CHANNEL_STATE_UP;
+ x++;
+ }
+ }
+ }
+ }
+
+ if (!x) {
+ snprintf(span->last_error, sizeof(span->last_error), "Span has no D-Channels!");
+ return ZAP_FAIL;
+ }
+
+ isdn_data = malloc(sizeof(*isdn_data));
+ assert(isdn_data != NULL);
+ memset(isdn_data, 0, sizeof(*isdn_data));
+
+ isdn_data->mode = Q931_TE;
+ dialect = Q931_Dialect_National;
+
+ while((var = va_arg(ap, char *))) {
+ if (!strcasecmp(var, "mode")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ isdn_data->mode = strcasecmp(val, "net") ? Q931_TE : Q931_NT;
+ } else if (!strcasecmp(var, "dialect")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ dialect = q931_str2Q931Dialect_type(val);
+ if (dialect == Q931_Dialect_Count) {
+ return ZAP_FAIL;
+ }
+ } else if (!strcasecmp(var, "opts")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ isdn_data->opts = parse_opts(val);
+ } else if (!strcasecmp(var, "tonemap")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ tonemap = (const char *)val;
+ } else if (!strcasecmp(var, "digit_timeout")) {
+ int *optp;
+ if (!(optp = va_arg(ap, int *))) {
+ break;
+ }
+ digit_timeout = *optp;
+ } else if (!strcasecmp(var, "q921loglevel")) {
+ q921loglevel = va_arg(ap, int);
+ if (q921loglevel < Q921_LOG_NONE) {
+ q921loglevel = Q921_LOG_NONE;
+ } else if (q921loglevel > Q921_LOG_DEBUG) {
+ q921loglevel = Q921_LOG_DEBUG;
+ }
+ } else if (!strcasecmp(var, "q931loglevel")) {
+ q931loglevel = va_arg(ap, int);
+ if (q931loglevel < Q931_LOG_NONE) {
+ q931loglevel = Q931_LOG_NONE;
+ } else if (q931loglevel > Q931_LOG_DEBUG) {
+ q931loglevel = Q931_LOG_DEBUG;
+ }
+ } else {
+ snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+ return ZAP_FAIL;
+ }
+ }
+
+
+ if (!digit_timeout) {
+ digit_timeout = DEFAULT_DIGIT_TIMEOUT;
+ }
+ else if (digit_timeout < 3000 || digit_timeout > 30000) {
+ zap_log(ZAP_LOG_WARNING, "Digit timeout %d ms outside of range (3000 - 30000 ms), using default (10000 ms)\n", digit_timeout);
+ digit_timeout = DEFAULT_DIGIT_TIMEOUT;
+ }
+
+ /* allocate per b-chan data */
+ if (isdn_data->mode == Q931_NT) {
+ zap_isdn_bchan_data_t *data;
+
+ data = malloc((span->chan_count - 1) * sizeof(zap_isdn_bchan_data_t));
+ if (!data) {
+ return ZAP_FAIL;
+ }
+
+ for (i = 1; i <= span->chan_count; i++, data++) {
+ if (span->channels[i]->type == ZAP_CHAN_TYPE_B) {
+ span->channels[i]->mod_data = data;
+ memset(data, 0, sizeof(zap_isdn_bchan_data_t));
+ }
+ }
+ }
+
+ span->start = zap_isdn_start;
+ span->stop = zap_isdn_stop;
+ span->signal_cb = sig_cb;
+ isdn_data->dchans[0] = dchans[0];
+ isdn_data->dchans[1] = dchans[1];
+ isdn_data->dchan = isdn_data->dchans[0];
+ isdn_data->digit_timeout = digit_timeout;
+
+ Q921_InitTrunk(&isdn_data->q921,
+ 0,
+ 0,
+ isdn_data->mode,
+ span->trunk_type == ZAP_TRUNK_BRI_PTMP ? Q921_PTMP : Q921_PTP,
+ 0,
+ zap_isdn_921_21,
+ (Q921Tx23CB_t)zap_isdn_921_23,
+ span,
+ &isdn_data->q931);
+
+ Q921SetLogCB(&isdn_data->q921, &zap_isdn_q921_log, isdn_data);
+ Q921SetLogLevel(&isdn_data->q921, (Q921LogLevel_t)q921loglevel);
+
+ Q931Api_InitTrunk(&isdn_data->q931,
+ dialect,
+ isdn_data->mode,
+ span->trunk_type,
+ zap_isdn_931_34,
+ (Q931Tx32CB_t)q931_rx_32,
+ zap_isdn_931_err,
+ &isdn_data->q921,
+ span);
+
+ Q931SetLogCB(&isdn_data->q931, &zap_isdn_q931_log, isdn_data);
+ Q931SetLogLevel(&isdn_data->q931, (Q931LogLevel_t)q931loglevel);
+
+ isdn_data->q931.autoRestartAck = 1;
+ isdn_data->q931.autoConnectAck = 0;
+ isdn_data->q931.autoServiceAck = 1;
+ span->signal_data = isdn_data;
+ span->signal_type = ZAP_SIGTYPE_ISDN;
+ span->outgoing_call = isdn_outgoing_call;
+
+ if ((isdn_data->opts & ZAP_ISDN_OPT_SUGGEST_CHANNEL)) {
+ span->channel_request = isdn_channel_request;
+ span->suggest_chan_id = 1;
+ }
+ span->state_map = &isdn_state_map;
+
+ zap_span_load_tones(span, tonemap);
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Openzap ISDN signaling module definition
+ */
+EX_DECLARE_DATA zap_module_t zap_module = {
+ "isdn",
+ NULL,
+ close_pcap,
+ zap_isdn_init,
+ zap_isdn_configure_span,
+ NULL
+};
+
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/zap_isdn.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/zap_isdn.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/zap_isdn.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#ifndef ZAP_ISDN_H
+#define ZAP_ISDN_H
+#include "openzap.h"
+
+#define DEFAULT_DIGIT_TIMEOUT 10000 /* default overlap timeout: 10 seconds */
+
+
+typedef enum {
+ ZAP_ISDN_OPT_NONE = 0,
+ ZAP_ISDN_OPT_SUGGEST_CHANNEL = (1 << 0),
+ ZAP_ISDN_OPT_OMIT_DISPLAY_IE = (1 << 1), /*!< Do not send Caller name in outgoing SETUP message (= Display IE) */
+ ZAP_ISDN_OPT_DISABLE_TONES = (1 << 2), /*!< Disable tone generating thread (NT mode) */
+
+ ZAP_ISDN_OPT_MAX = (2 << 0)
+} zap_isdn_opts_t;
+
+typedef enum {
+ ZAP_ISDN_RUNNING = (1 << 0),
+ ZAP_ISDN_TONES_RUNNING = (1 << 1),
+ ZAP_ISDN_STOP = (1 << 2)
+} zap_isdn_flag_t;
+
+
+struct zap_isdn_data {
+ Q921Data_t q921;
+ Q931_TrunkInfo_t q931;
+ zap_channel_t *dchan;
+ zap_channel_t *dchans[2];
+ struct zap_sigmsg sigmsg;
+ uint32_t flags;
+ int32_t mode;
+ int32_t digit_timeout;
+ zap_isdn_opts_t opts;
+ zap_caller_data_t *outbound_crv[32768];
+ zap_channel_t *channels_local_crv[32768];
+ zap_channel_t *channels_remote_crv[32768];
+};
+
+typedef struct zap_isdn_data zap_isdn_data_t;
+
+
+/* b-channel private data */
+struct zap_isdn_bchan_data
+{
+ L2ULONG digit_timeout;
+};
+
+typedef struct zap_isdn_bchan_data zap_isdn_bchan_data_t;
+
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2009, Anthony Minessale II
+ * 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.
+ */
+
+//#define IODEBUG
+
+#include "openzap.h"
+#include "lpwrap_pri.h"
+#ifndef HAVE_GETTIMEOFDAY
+
+#ifdef WIN32
+#include <mmsystem.h>
+
+static __inline int gettimeofday(struct timeval *tp, void *nothing)
+{
+#ifdef WITHOUT_MM_LIB
+ SYSTEMTIME st;
+ time_t tt;
+ struct tm tmtm;
+ /* mktime converts local to UTC */
+ GetLocalTime (&st);
+ tmtm.tm_sec = st.wSecond;
+ tmtm.tm_min = st.wMinute;
+ tmtm.tm_hour = st.wHour;
+ tmtm.tm_mday = st.wDay;
+ tmtm.tm_mon = st.wMonth - 1;
+ tmtm.tm_year = st.wYear - 1900; tmtm.tm_isdst = -1;
+ tt = mktime (&tmtm);
+ tp->tv_sec = tt;
+ tp->tv_usec = st.wMilliseconds * 1000;
+#else
+ /**
+ ** The earlier time calculations using GetLocalTime
+ ** had a time resolution of 10ms.The timeGetTime, part
+ ** of multimedia apis offer a better time resolution
+ ** of 1ms.Need to link against winmm.lib for this
+ **/
+ unsigned long Ticks = 0;
+ unsigned long Sec =0;
+ unsigned long Usec = 0;
+ Ticks = timeGetTime();
+
+ Sec = Ticks/1000;
+ Usec = (Ticks - (Sec*1000))*1000;
+ tp->tv_sec = Sec;
+ tp->tv_usec = Usec;
+#endif /* WITHOUT_MM_LIB */
+ (void)nothing;
+ return 0;
+}
+#endif /* WIN32 */
+#endif /* HAVE_GETTIMEOFDAY */
+
+static struct lpwrap_pri_event_list LPWRAP_PRI_EVENT_LIST[] = {
+ {0, LPWRAP_PRI_EVENT_ANY, "ANY"},
+ {1, LPWRAP_PRI_EVENT_DCHAN_UP, "DCHAN_UP"},
+ {2, LPWRAP_PRI_EVENT_DCHAN_DOWN, "DCHAN_DOWN"},
+ {3, LPWRAP_PRI_EVENT_RESTART, "RESTART"},
+ {4, LPWRAP_PRI_EVENT_CONFIG_ERR, "CONFIG_ERR"},
+ {5, LPWRAP_PRI_EVENT_RING, "RING"},
+ {6, LPWRAP_PRI_EVENT_HANGUP, "HANGUP"},
+ {7, LPWRAP_PRI_EVENT_RINGING, "RINGING"},
+ {8, LPWRAP_PRI_EVENT_ANSWER, "ANSWER"},
+ {9, LPWRAP_PRI_EVENT_HANGUP_ACK, "HANGUP_ACK"},
+ {10, LPWRAP_PRI_EVENT_RESTART_ACK, "RESTART_ACK"},
+ {11, LPWRAP_PRI_EVENT_FACNAME, "FACNAME"},
+ {12, LPWRAP_PRI_EVENT_INFO_RECEIVED, "INFO_RECEIVED"},
+ {13, LPWRAP_PRI_EVENT_PROCEEDING, "PROCEEDING"},
+ {14, LPWRAP_PRI_EVENT_SETUP_ACK, "SETUP_ACK"},
+ {15, LPWRAP_PRI_EVENT_HANGUP_REQ, "HANGUP_REQ"},
+ {16, LPWRAP_PRI_EVENT_NOTIFY, "NOTIFY"},
+ {17, LPWRAP_PRI_EVENT_PROGRESS, "PROGRESS"},
+ {18, LPWRAP_PRI_EVENT_KEYPAD_DIGIT, "KEYPAD_DIGIT"},
+ {19, LPWRAP_PRI_EVENT_IO_FAIL, "IO_FAIL"},
+};
+
+#define LINE "--------------------------------------------------------------------------------"
+
+const char *lpwrap_pri_event_str(lpwrap_pri_event_t event_id)
+{
+ return LPWRAP_PRI_EVENT_LIST[event_id].name;
+}
+
+static int __pri_lpwrap_read(struct pri *pri, void *buf, int buflen)
+{
+ struct lpwrap_pri *spri = (struct lpwrap_pri *) pri_get_userdata(pri);
+ zap_size_t len = buflen;
+ int res;
+ zap_status_t zst;
+
+ if ((zst = zap_channel_read(spri->dchan, buf, &len)) != ZAP_SUCCESS) {
+ if (zst == ZAP_FAIL) {
+ zap_log(ZAP_LOG_CRIT, "span %d D-READ FAIL! [%s]\n", spri->span->span_id, spri->dchan->last_error);
+ spri->errs++;
+ } else {
+ zap_log(ZAP_LOG_CRIT, "span %d D-READ TIMEOUT\n", spri->span->span_id);
+ }
+
+ zap_clear_flag(spri, LPWRAP_PRI_READY);
+ return -1;
+ }
+ spri->errs = 0;
+ res = (int)len;
+ memset(&((unsigned char*)buf)[res],0,2);
+ res+=2;
+
+#ifdef IODEBUG
+ {
+ char bb[2048] = { 0 };
+
+ print_hex_bytes(buf, res - 2, bb, sizeof(bb));
+ zap_log(ZAP_LOG_DEBUG, "READ %d\n", res-2);
+ }
+#endif
+
+ return res;
+}
+
+static int __pri_lpwrap_write(struct pri *pri, void *buf, int buflen)
+{
+ struct lpwrap_pri *spri = (struct lpwrap_pri *) pri_get_userdata(pri);
+ zap_size_t len = buflen -2;
+
+ if (zap_channel_write(spri->dchan, buf, buflen, &len) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_CRIT, "span %d D-WRITE FAIL! [%s]\n", spri->span->span_id, spri->dchan->last_error);
+ zap_clear_flag(spri, LPWRAP_PRI_READY);
+ return -1;
+ }
+
+#ifdef IODEBUG
+ {
+ char bb[2048] = { 0 };
+
+ print_hex_bytes(buf, buflen - 2, bb, sizeof(bb));
+ zap_log(ZAP_LOG_DEBUG, "WRITE %d\n", (int)buflen-2);
+ }
+#endif
+
+ return (int) buflen;
+}
+
+int lpwrap_init_pri(struct lpwrap_pri *spri, zap_span_t *span, zap_channel_t *dchan, int swtype, int node, int debug)
+{
+ int ret = -1;
+
+ memset(spri, 0, sizeof(struct lpwrap_pri));
+
+ spri->dchan = dchan;
+ spri->span = span;
+
+ if ((spri->pri = pri_new_cb(spri->dchan->sockfd, node, swtype, __pri_lpwrap_read, __pri_lpwrap_write, spri))){
+ unsigned char buf[4] = { 0 };
+ size_t buflen = sizeof(buf), len = 0;
+ pri_set_debug(spri->pri, debug);
+ ret = 0;
+ zap_set_flag(spri, LPWRAP_PRI_READY);
+ zap_channel_write(spri->dchan, buf, buflen, &len);
+ } else {
+ fprintf(stderr, "Unable to create PRI\n");
+ }
+
+ return ret;
+}
+
+
+int lpwrap_one_loop(struct lpwrap_pri *spri)
+{
+ fd_set rfds, efds;
+ struct timeval now = {0,0}, *next;
+ pri_event *event;
+ event_handler handler;
+ int sel;
+
+ if (spri->on_loop) {
+ if ((sel = spri->on_loop(spri)) < 0) {
+ return sel;
+ }
+ }
+
+ if (spri->errs >= 2) {
+ spri->errs = 0;
+ return -1;
+ }
+
+ FD_ZERO(&rfds);
+ FD_ZERO(&efds);
+
+#ifdef _MSC_VER
+ //Windows macro for FD_SET includes a warning C4127: conditional expression is constant
+#pragma warning(push)
+#pragma warning(disable:4127)
+#endif
+
+ FD_SET(pri_fd(spri->pri), &rfds);
+ FD_SET(pri_fd(spri->pri), &efds);
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+ now.tv_sec = 0;
+ now.tv_usec = 100000;
+
+ sel = select(pri_fd(spri->pri) + 1, &rfds, NULL, &efds, &now);
+
+ event = NULL;
+
+ if (!sel) {
+ if ((next = pri_schedule_next(spri->pri))) {
+ gettimeofday(&now, NULL);
+ if (now.tv_sec >= next->tv_sec && (now.tv_usec >= next->tv_usec || next->tv_usec <= 100000)) {
+ //zap_log(ZAP_LOG_DEBUG, "Check event\n");
+ event = pri_schedule_run(spri->pri);
+ }
+ }
+ } else if (sel > 0) {
+ event = pri_check_event(spri->pri);
+ }
+
+ if (event) {
+ /* 0 is catchall event handler */
+ if ((handler = spri->eventmap[event->e] ? spri->eventmap[event->e] : spri->eventmap[0] ? spri->eventmap[0] : NULL)) {
+ handler(spri, event->e, event);
+ } else {
+ zap_log(ZAP_LOG_CRIT, "No event handler found for event %d.\n", event->e);
+ }
+ }
+
+
+ return sel;
+
+
+ if ((handler = spri->eventmap[LPWRAP_PRI_EVENT_IO_FAIL] ? spri->eventmap[LPWRAP_PRI_EVENT_IO_FAIL] : spri->eventmap[0] ? spri->eventmap[0] : NULL)) {
+ handler(spri, LPWRAP_PRI_EVENT_IO_FAIL, NULL);
+ }
+
+ return -1;
+}
+
+int lpwrap_run_pri(struct lpwrap_pri *spri)
+{
+ int ret = 0;
+
+ for (;;){
+ ret = lpwrap_one_loop(spri);
+
+ if (ret < 0) {
+
+#ifndef WIN32 //This needs to be adressed fror WIN32 still
+ if (errno == EINTR){
+ /* Igonore an interrupted system call */
+ continue;
+ }
+#endif
+ zap_log(ZAP_LOG_CRIT, "Error = %i [%s]\n", ret, strerror(errno));
+ break;
+ }
+ }
+
+ return ret;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2009, Anthony Minessale II
+ * 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.
+ */
+
+#ifndef _LPWRAP_PRI_H
+#define _LPWRAP_PRI_H
+#include <libpri.h>
+#include <openzap.h>
+
+
+#define LPWRAP_MAX_CHAN_PER_SPAN 32
+
+typedef enum {
+ LPWRAP_PRI_EVENT_ANY = 0,
+ LPWRAP_PRI_EVENT_DCHAN_UP = PRI_EVENT_DCHAN_UP,
+ LPWRAP_PRI_EVENT_DCHAN_DOWN = PRI_EVENT_DCHAN_DOWN,
+ LPWRAP_PRI_EVENT_RESTART = PRI_EVENT_RESTART,
+ LPWRAP_PRI_EVENT_CONFIG_ERR = PRI_EVENT_CONFIG_ERR,
+ LPWRAP_PRI_EVENT_RING = PRI_EVENT_RING,
+ LPWRAP_PRI_EVENT_HANGUP = PRI_EVENT_HANGUP,
+ LPWRAP_PRI_EVENT_RINGING = PRI_EVENT_RINGING,
+ LPWRAP_PRI_EVENT_ANSWER = PRI_EVENT_ANSWER,
+ LPWRAP_PRI_EVENT_HANGUP_ACK = PRI_EVENT_HANGUP_ACK,
+ LPWRAP_PRI_EVENT_RESTART_ACK = PRI_EVENT_RESTART_ACK,
+ LPWRAP_PRI_EVENT_FACNAME = PRI_EVENT_FACNAME,
+ LPWRAP_PRI_EVENT_INFO_RECEIVED = PRI_EVENT_INFO_RECEIVED,
+ LPWRAP_PRI_EVENT_PROCEEDING = PRI_EVENT_PROCEEDING,
+ LPWRAP_PRI_EVENT_SETUP_ACK = PRI_EVENT_SETUP_ACK,
+ LPWRAP_PRI_EVENT_HANGUP_REQ = PRI_EVENT_HANGUP_REQ,
+ LPWRAP_PRI_EVENT_NOTIFY = PRI_EVENT_NOTIFY,
+ LPWRAP_PRI_EVENT_PROGRESS = PRI_EVENT_PROGRESS,
+ LPWRAP_PRI_EVENT_KEYPAD_DIGIT = PRI_EVENT_KEYPAD_DIGIT,
+ LPWRAP_PRI_EVENT_IO_FAIL = 19,
+
+ /* don't touch */
+ LPWRAP_PRI_EVENT_MAX
+} lpwrap_pri_event_t;
+
+typedef enum {
+ LPWRAP_PRI_NETWORK = PRI_NETWORK,
+ LPWRAP_PRI_CPE = PRI_CPE
+} lpwrap_pri_node_t;
+
+typedef enum {
+ LPWRAP_PRI_SWITCH_UNKNOWN = PRI_SWITCH_UNKNOWN,
+ LPWRAP_PRI_SWITCH_NI2 = PRI_SWITCH_NI2,
+ LPWRAP_PRI_SWITCH_DMS100 = PRI_SWITCH_DMS100,
+ LPWRAP_PRI_SWITCH_LUCENT5E = PRI_SWITCH_LUCENT5E,
+ LPWRAP_PRI_SWITCH_ATT4ESS = PRI_SWITCH_ATT4ESS,
+ LPWRAP_PRI_SWITCH_EUROISDN_E1 = PRI_SWITCH_EUROISDN_E1,
+ LPWRAP_PRI_SWITCH_EUROISDN_T1 = PRI_SWITCH_EUROISDN_T1,
+ LPWRAP_PRI_SWITCH_NI1 = PRI_SWITCH_NI1,
+ LPWRAP_PRI_SWITCH_GR303_EOC = PRI_SWITCH_GR303_EOC,
+ LPWRAP_PRI_SWITCH_GR303_TMC = PRI_SWITCH_GR303_TMC,
+ LPWRAP_PRI_SWITCH_QSIG = PRI_SWITCH_QSIG,
+
+ /* don't touch */
+ LPWRAP_PRI_SWITCH_MAX
+} lpwrap_pri_switch_t;
+
+typedef enum {
+ LPWRAP_PRI_READY = (1 << 0)
+} lpwrap_pri_flag_t;
+
+struct lpwrap_pri;
+typedef int (*event_handler)(struct lpwrap_pri *, lpwrap_pri_event_t, pri_event *);
+typedef int (*loop_handler)(struct lpwrap_pri *);
+
+struct lpwrap_pri {
+ struct pri *pri;
+ zap_span_t *span;
+ zap_channel_t *dchan;
+ unsigned int flags;
+ void *private_info;
+ event_handler eventmap[LPWRAP_PRI_EVENT_MAX];
+ loop_handler on_loop;
+ int errs;
+};
+
+typedef struct lpwrap_pri lpwrap_pri_t;
+
+struct lpwrap_pri_event_list {
+ int event_id;
+ int pri_event;
+ const char *name;
+};
+
+
+
+#define LPWRAP_MAP_PRI_EVENT(spri, event, func) spri.eventmap[event] = func;
+
+const char *lpwrap_pri_event_str(lpwrap_pri_event_t event_id);
+int lpwrap_one_loop(struct lpwrap_pri *spri);
+int lpwrap_init_pri(struct lpwrap_pri *spri, zap_span_t *span, zap_channel_t *dchan, int swtype, int node, int debug);
+int lpwrap_run_pri(struct lpwrap_pri *spri);
+
+#endif
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1363 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#include "openzap.h"
+#include "ozmod_libpri.h"
+
+/**
+ * \brief Unloads libpri IO module
+ * \return Success
+ */
+static ZIO_IO_UNLOAD_FUNCTION(zap_libpri_unload)
+{
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Starts a libpri channel (outgoing call)
+ * \param zchan Channel to initiate call on
+ * \return Success or failure
+ */
+static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(isdn_outgoing_call)
+{
+ zap_status_t status = ZAP_SUCCESS;
+ zap_set_flag(zchan, ZAP_CHANNEL_OUTBOUND);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DIALING);
+ return status;
+}
+
+/**
+ * \brief Requests an libpri channel on a span (outgoing call)
+ * \param span Span where to get a channel (unused)
+ * \param chan_id Specific channel to get (0 for any) (unused)
+ * \param direction Call direction (unused)
+ * \param caller_data Caller information (unused)
+ * \param zchan Channel to initialise (unused)
+ * \return Failure
+ */
+static ZIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request)
+{
+ return ZAP_FAIL;
+}
+
+#ifdef WIN32
+/**
+ * \brief Logs a libpri error
+ * \param s Error string
+ */
+static void s_pri_error(char *s)
+#else
+/**
+ * \brief Logs a libpri error
+ * \param pri libpri structure (unused)
+ * \param s Error string
+ */
+static void s_pri_error(struct pri *pri, char *s)
+#endif
+{
+ zap_log(ZAP_LOG_ERROR, "%s", s);
+}
+
+#ifdef WIN32
+/**
+ * \brief Logs a libpri message
+ * \param s Message string
+ */
+static void s_pri_message(char *s)
+#else
+/**
+ * \brief Logs a libpri message
+ * \param pri libpri structure (unused)
+ * \param s Message string
+ */
+static void s_pri_message(struct pri *pri, char *s)
+#endif
+{
+ zap_log(ZAP_LOG_DEBUG, "%s", s);
+}
+
+/**
+ * \brief Parses an option string to flags
+ * \param in String to parse for configuration options
+ * \return Flags
+ */
+static uint32_t parse_opts(const char *in)
+{
+ uint32_t flags = 0;
+
+ if (!in) {
+ return 0;
+ }
+
+ if (strstr(in, "suggest_channel")) {
+ flags |= OZMOD_LIBPRI_OPT_SUGGEST_CHANNEL;
+ }
+
+ if (strstr(in, "omit_display")) {
+ flags |= OZMOD_LIBPRI_OPT_OMIT_DISPLAY_IE;
+ }
+
+ if (strstr(in, "omit_redirecting_number")) {
+ flags |= OZMOD_LIBPRI_OPT_OMIT_REDIRECTING_NUMBER_IE;
+ }
+
+ return flags;
+}
+
+/**
+ * \brief Parses a debug string to flags
+ * \param in Debug string to parse for
+ * \return Flags
+ */
+static int parse_debug(const char *in)
+{
+ int flags = 0;
+
+ if (!in) {
+ return 0;
+ }
+
+ if (strstr(in, "q921_raw")) {
+ flags |= PRI_DEBUG_Q921_RAW;
+ }
+
+ if (strstr(in, "q921_dump")) {
+ flags |= PRI_DEBUG_Q921_DUMP;
+ }
+
+ if (strstr(in, "q921_state")) {
+ flags |= PRI_DEBUG_Q921_STATE;
+ }
+
+ if (strstr(in, "config")) {
+ flags |= PRI_DEBUG_CONFIG;
+ }
+
+ if (strstr(in, "q931_dump")) {
+ flags |= PRI_DEBUG_Q931_DUMP;
+ }
+
+ if (strstr(in, "q931_state")) {
+ flags |= PRI_DEBUG_Q931_STATE;
+ }
+
+ if (strstr(in, "q931_anomaly")) {
+ flags |= PRI_DEBUG_Q931_ANOMALY;
+ }
+
+ if (strstr(in, "apdu")) {
+ flags |= PRI_DEBUG_APDU;
+ }
+
+ if (strstr(in, "aoc")) {
+ flags |= PRI_DEBUG_AOC;
+ }
+
+ if (strstr(in, "all")) {
+ flags |= PRI_DEBUG_ALL;
+ }
+
+ if (strstr(in, "none")) {
+ flags = 0;
+ }
+
+ return flags;
+}
+
+static zap_io_interface_t zap_libpri_interface;
+
+static zap_status_t zap_libpri_start(zap_span_t *span);
+
+/**
+ * \brief API function to kill or debug a libpri span
+ * \param stream API stream handler
+ * \param data String containing argurments
+ * \return Flags
+ */
+static ZIO_API_FUNCTION(zap_libpri_api)
+{
+ char *mycmd = NULL, *argv[10] = { 0 };
+ int argc = 0;
+
+ if (data) {
+ mycmd = strdup(data);
+ argc = zap_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+ }
+
+ if (argc == 2) {
+ if (!strcasecmp(argv[0], "kill")) {
+ int span_id = atoi(argv[1]);
+ zap_span_t *span = NULL;
+
+ if (zap_span_find_by_name(argv[1], &span) == ZAP_SUCCESS || zap_span_find(span_id, &span) == ZAP_SUCCESS) {
+ zap_libpri_data_t *isdn_data = span->signal_data;
+
+ if (span->start != zap_libpri_start) {
+ stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
+ goto done;
+ }
+
+ zap_clear_flag((&isdn_data->spri), LPWRAP_PRI_READY);
+ stream->write_function(stream, "%s: +OK killed.\n", __FILE__);
+ goto done;
+ } else {
+ stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
+ goto done;
+ }
+ }
+ }
+
+ if (argc > 2) {
+ if (!strcasecmp(argv[0], "debug")) {
+ zap_span_t *span = NULL;
+
+ if (zap_span_find_by_name(argv[1], &span) == ZAP_SUCCESS) {
+ zap_libpri_data_t *isdn_data = span->signal_data;
+ if (span->start != zap_libpri_start) {
+ stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
+ goto done;
+ }
+
+ pri_set_debug(isdn_data->spri.pri, parse_debug(argv[2]));
+ stream->write_function(stream, "%s: +OK debug set.\n", __FILE__);
+ goto done;
+ } else {
+ stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
+ goto done;
+ }
+ }
+
+ }
+
+ stream->write_function(stream, "%s: -ERR invalid command.\n", __FILE__);
+
+ done:
+
+ zap_safe_free(mycmd);
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Loads libpri IO module
+ * \param zio Openzap IO interface
+ * \return Success
+ */
+static ZIO_IO_LOAD_FUNCTION(zap_libpri_io_init)
+{
+ assert(zio != NULL);
+ memset(&zap_libpri_interface, 0, sizeof(zap_libpri_interface));
+
+ zap_libpri_interface.name = "libpri";
+ zap_libpri_interface.api = zap_libpri_api;
+
+ *zio = &zap_libpri_interface;
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Loads libpri signaling module
+ * \param zio Openzap IO interface
+ * \return Success
+ */
+static ZIO_SIG_LOAD_FUNCTION(zap_libpri_init)
+{
+ pri_set_error(s_pri_error);
+ pri_set_message(s_pri_message);
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief libpri state map
+ */
+static zap_state_map_t isdn_state_map = {
+ {
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_ANY_STATE},
+ {ZAP_CHANNEL_STATE_RESTART, ZAP_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_RESTART, ZAP_END},
+ {ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+ {ZAP_CHANNEL_STATE_DIALING, ZAP_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_DIALING, ZAP_END},
+ {ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_UP, ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_PROGRESS, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_UP, ZAP_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_END},
+ {ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_UP, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END}
+ },
+
+ /****************************************/
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_ANY_STATE},
+ {ZAP_CHANNEL_STATE_RESTART, ZAP_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_RESTART, ZAP_END},
+ {ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+ {ZAP_CHANNEL_STATE_DIALTONE, ZAP_CHANNEL_STATE_RING, ZAP_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_DIALTONE, ZAP_END},
+ {ZAP_CHANNEL_STATE_RING, ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_RING, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_UP, ZAP_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_END},
+ {ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_PROGRESS_MEDIA,
+ ZAP_CHANNEL_STATE_CANCEL, ZAP_CHANNEL_STATE_UP, ZAP_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_UP, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+ },
+
+
+ }
+};
+
+/**
+ * \brief Handler for channel state change
+ * \param zchan Channel to handle
+ */
+static __inline__ void state_advance(zap_channel_t *zchan)
+{
+ //Q931mes_Generic *gen = (Q931mes_Generic *) zchan->caller_data.raw_data;
+ zap_libpri_data_t *isdn_data = zchan->span->signal_data;
+ zap_status_t status;
+ zap_sigmsg_t sig;
+ q931_call *call = (q931_call *) zchan->call_data;
+
+
+ zap_log(ZAP_LOG_DEBUG, "%d:%d STATE [%s]\n",
+ zchan->span_id, zchan->chan_id, zap_channel_state2str(zchan->state));
+
+
+#if 0
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND) && !call) {
+ zap_log(ZAP_LOG_WARNING, "NO CALL!!!!\n");
+ }
+#endif
+
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = zchan->chan_id;
+ sig.span_id = zchan->span_id;
+ sig.channel = zchan;
+
+
+ switch (zchan->state) {
+ case ZAP_CHANNEL_STATE_DOWN:
+ {
+ zchan->call_data = NULL;
+ zap_channel_done(zchan);
+ }
+ break;
+ case ZAP_CHANNEL_STATE_PROGRESS:
+ {
+ if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ sig.event_id = ZAP_SIGEVENT_PROGRESS;
+ if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ } else if (call) {
+ pri_progress(isdn_data->spri.pri, call, zchan->chan_id, 1);
+ } else {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_PROGRESS_MEDIA:
+ {
+ if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ sig.event_id = ZAP_SIGEVENT_PROGRESS_MEDIA;
+ if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ } else if (call) {
+ pri_proceeding(isdn_data->spri.pri, call, zchan->chan_id, 1);
+ } else {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_RING:
+ {
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ if (call) {
+ pri_acknowledge(isdn_data->spri.pri, call, zchan->chan_id, 0);
+ sig.event_id = ZAP_SIGEVENT_START;
+ if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ } else {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+ }
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_RESTART:
+ {
+ zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_UNSPECIFIED;
+ sig.event_id = ZAP_SIGEVENT_RESTART;
+ status = zap_span_send_signal(zchan->span, &sig);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ }
+ break;
+ case ZAP_CHANNEL_STATE_UP:
+ {
+ if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ sig.event_id = ZAP_SIGEVENT_UP;
+ if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ } else if (call) {
+ pri_answer(isdn_data->spri.pri, call, 0, 1);
+ } else {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_DIALING:
+ if (isdn_data) {
+ struct pri_sr *sr;
+ int dp;
+
+ if (!(call = pri_new_call(isdn_data->spri.pri))) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+ return;
+ }
+
+
+ dp = zchan->caller_data.ani.type;
+ switch(dp) {
+ case ZAP_TON_NATIONAL:
+ dp = PRI_NATIONAL_ISDN;
+ break;
+ case ZAP_TON_INTERNATIONAL:
+ dp = PRI_INTERNATIONAL_ISDN;
+ break;
+ case ZAP_TON_SUBSCRIBER_NUMBER:
+ dp = PRI_LOCAL_ISDN;
+ break;
+ default:
+ dp = isdn_data->dp;
+ }
+
+ zchan->call_data = call;
+ sr = pri_sr_new();
+ assert(sr);
+ pri_sr_set_channel(sr, zchan->chan_id, 0, 0);
+ pri_sr_set_bearer(sr, 0, isdn_data->l1);
+ pri_sr_set_called(sr, zchan->caller_data.ani.digits, dp, 1);
+ pri_sr_set_caller(sr, zchan->caller_data.cid_num.digits, (isdn_data->opts & OZMOD_LIBPRI_OPT_OMIT_DISPLAY_IE ? NULL : zchan->caller_data.cid_name),
+ dp, (zchan->caller_data.pres != 1 ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_PROHIB_USER_NUMBER_NOT_SCREENED));
+
+ if (!(isdn_data->opts & OZMOD_LIBPRI_OPT_OMIT_REDIRECTING_NUMBER_IE)) {
+ pri_sr_set_redirecting(sr, zchan->caller_data.cid_num.digits, dp, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, PRI_REDIR_UNCONDITIONAL);
+ }
+
+ if (pri_setup(isdn_data->spri.pri, call, sr)) {
+ zchan->caller_data.hangup_cause = ZAP_CAUSE_DESTINATION_OUT_OF_ORDER;
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+
+ pri_sr_free(sr);
+ }
+
+ break;
+ case ZAP_CHANNEL_STATE_HANGUP:
+ {
+ if (call) {
+ pri_hangup(isdn_data->spri.pri, call, zchan->caller_data.hangup_cause);
+ pri_destroycall(isdn_data->spri.pri, call);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ } else {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_HANGUP_COMPLETE:
+ break;
+ case ZAP_CHANNEL_STATE_TERMINATING:
+ {
+ sig.event_id = ZAP_SIGEVENT_STOP;
+ status = zap_span_send_signal(zchan->span, &sig);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+
+ }
+ default:
+ break;
+ }
+
+
+
+ return;
+}
+
+/**
+ * \brief Checks current state on a span
+ * \param span Span to check status on
+ */
+static __inline__ void check_state(zap_span_t *span)
+{
+ if (zap_test_flag(span, ZAP_SPAN_STATE_CHANGE)) {
+ uint32_t j;
+ zap_clear_flag_locked(span, ZAP_SPAN_STATE_CHANGE);
+ for(j = 1; j <= span->chan_count; j++) {
+ if (zap_test_flag((span->channels[j]), ZAP_CHANNEL_STATE_CHANGE)) {
+ zap_mutex_lock(span->channels[j]->mutex);
+ zap_clear_flag((span->channels[j]), ZAP_CHANNEL_STATE_CHANGE);
+ state_advance(span->channels[j]);
+ zap_channel_complete_state(span->channels[j]);
+ zap_mutex_unlock(span->channels[j]->mutex);
+ }
+ }
+ }
+}
+
+/**
+ * \brief Handler for libpri information event (incoming call?)
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_info(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+
+ zap_log(ZAP_LOG_DEBUG, "number is: %s\n", pevent->ring.callednum);
+ if (strlen(pevent->ring.callednum) > 3) {
+ zap_log(ZAP_LOG_DEBUG, "final number is: %s\n", pevent->ring.callednum);
+ pri_answer(spri->pri, pevent->ring.call, 0, 1);
+ }
+ return 0;
+}
+
+/**
+ * \brief Handler for libpri hangup event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_hangup(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+ zap_span_t *span = spri->private_info;
+ zap_channel_t *zchan = NULL;
+ q931_call *call = NULL;
+ zchan = span->channels[pevent->hangup.channel];
+
+ if (zchan) {
+ call = (q931_call *) zchan->call_data;
+ zap_log(ZAP_LOG_DEBUG, "-- Hangup on channel %d:%d\n", spri->span->span_id, pevent->hangup.channel);
+ zchan->caller_data.hangup_cause = pevent->hangup.cause;
+ pri_release(spri->pri, call, 0);
+ pri_destroycall(spri->pri, call);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_TERMINATING);
+ } else {
+ zap_log(ZAP_LOG_DEBUG, "-- Hangup on channel %d:%d %s but it's not in use?\n", spri->span->span_id,
+ pevent->hangup.channel, zchan->chan_id);
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Handler for libpri answer event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_answer(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+ zap_span_t *span = spri->private_info;
+ zap_channel_t *zchan = NULL;
+
+ zchan = span->channels[pevent->answer.channel];
+
+ if (zchan) {
+ zap_log(ZAP_LOG_DEBUG, "-- Answer on channel %d:%d\n", spri->span->span_id, pevent->answer.channel);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
+ } else {
+ zap_log(ZAP_LOG_DEBUG, "-- Answer on channel %d:%d %s but it's not in use?\n", spri->span->span_id, pevent->answer.channel, zchan->chan_id);
+
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Handler for libpri proceed event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_proceed(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+ zap_span_t *span = spri->private_info;
+ zap_channel_t *zchan = NULL;
+
+ zchan = span->channels[pevent->proceeding.channel];
+
+ if (zchan) {
+ zap_log(ZAP_LOG_DEBUG, "-- Proceeding on channel %d:%d\n", spri->span->span_id, pevent->proceeding.channel);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS_MEDIA);
+ } else {
+ zap_log(ZAP_LOG_DEBUG, "-- Proceeding on channel %d:%d %s but it's not in use?\n", spri->span->span_id,
+ pevent->proceeding.channel, zchan->chan_id);
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Handler for libpri ringing event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_ringing(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+ zap_span_t *span = spri->private_info;
+ zap_channel_t *zchan = NULL;
+
+ zchan = span->channels[pevent->ringing.channel];
+
+ if (zchan) {
+ zap_log(ZAP_LOG_DEBUG, "-- Ringing on channel %d:%d\n", spri->span->span_id, pevent->ringing.channel);
+ /* we may get on_ringing even when we're already in ZAP_CHANNEL_STATE_PROGRESS_MEDIA */
+ if (zchan->state == ZAP_CHANNEL_STATE_PROGRESS_MEDIA) {
+ /* dont try to move to STATE_PROGRESS to avoid annoying veto warning */
+ return 0;
+ }
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS);
+ } else {
+ zap_log(ZAP_LOG_DEBUG, "-- Ringing on channel %d:%d %s but it's not in use?\n", spri->span->span_id,
+ pevent->ringing.channel, zchan->chan_id);
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Handler for libpri ring event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0 on success
+ */
+static int on_ring(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+ zap_span_t *span = spri->private_info;
+ zap_channel_t *zchan = NULL;
+ int ret = 0;
+
+ //switch_mutex_lock(globals.channel_mutex);
+
+ zchan = span->channels[pevent->ring.channel];
+ if (!zchan || zchan->state != ZAP_CHANNEL_STATE_DOWN || zap_test_flag(zchan, ZAP_CHANNEL_INUSE)) {
+ zap_log(ZAP_LOG_WARNING, "--Duplicate Ring on channel %d:%d (ignored)\n", spri->span->span_id, pevent->ring.channel);
+ ret = 0;
+ goto done;
+ }
+
+ if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_WARNING, "--Failure opening channel %d:%d (ignored)\n", spri->span->span_id, pevent->ring.channel);
+ ret = 0;
+ goto done;
+ }
+
+
+ zap_log(ZAP_LOG_NOTICE, "-- Ring on channel %d:%d (from %s to %s)\n", spri->span->span_id, pevent->ring.channel,
+ pevent->ring.callingnum, pevent->ring.callednum);
+
+ memset(&zchan->caller_data, 0, sizeof(zchan->caller_data));
+
+ zap_set_string(zchan->caller_data.cid_num.digits, (char *)pevent->ring.callingnum);
+ if (!zap_strlen_zero((char *)pevent->ring.callingname)) {
+ zap_set_string(zchan->caller_data.cid_name, (char *)pevent->ring.callingname);
+ } else {
+ zap_set_string(zchan->caller_data.cid_name, (char *)pevent->ring.callingnum);
+ }
+ zap_set_string(zchan->caller_data.ani.digits, (char *)pevent->ring.callingani);
+ zap_set_string(zchan->caller_data.dnis.digits, (char *)pevent->ring.callednum);
+
+ if (pevent->ring.ani2 >= 0) {
+ snprintf(zchan->caller_data.aniII, 5, "%.2d", pevent->ring.ani2);
+ }
+
+ // scary to trust this pointer, you'd think they would give you a copy of the call data so you own it......
+ zchan->call_data = pevent->ring.call;
+
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RING);
+
+ done:
+ //switch_mutex_unlock(globals.channel_mutex);
+
+ return ret;
+}
+
+/**
+ * \brief Processes openzap event
+ * \param span Span on which the event was fired
+ * \param event Event to be treated
+ * \return Success or failure
+ */
+static __inline__ zap_status_t process_event(zap_span_t *span, zap_event_t *event)
+{
+ zap_log(ZAP_LOG_DEBUG, "EVENT [%s][%d][%d:%d] STATE [%s]\n",
+ zap_oob_event2str(event->enum_id), event->enum_id, event->channel->span_id, event->channel->chan_id, zap_channel_state2str(event->channel->state));
+
+ switch(event->enum_id) {
+ case ZAP_OOB_ALARM_TRAP:
+ {
+ if (event->channel->state != ZAP_CHANNEL_STATE_DOWN) {
+ if (event->channel->type == ZAP_CHAN_TYPE_B) {
+ zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_RESTART);
+ }
+ }
+
+
+ zap_set_flag(event->channel, ZAP_CHANNEL_SUSPENDED);
+
+
+ zap_channel_get_alarms(event->channel);
+ zap_log(ZAP_LOG_WARNING, "channel %d:%d (%d:%d) has alarms! [%s]\n",
+ event->channel->span_id, event->channel->chan_id,
+ event->channel->physical_span_id, event->channel->physical_chan_id,
+ event->channel->last_error);
+ }
+ break;
+ case ZAP_OOB_ALARM_CLEAR:
+ {
+ zap_log(ZAP_LOG_WARNING, "channel %d:%d (%d:%d) alarms Cleared!\n", event->channel->span_id, event->channel->chan_id,
+ event->channel->physical_span_id, event->channel->physical_chan_id);
+
+ zap_clear_flag(event->channel, ZAP_CHANNEL_SUSPENDED);
+ zap_channel_get_alarms(event->channel);
+ }
+ break;
+ }
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Checks for events on a span
+ * \param span Span to check for events
+ */
+static __inline__ void check_events(zap_span_t *span)
+{
+ zap_status_t status;
+
+ status = zap_span_poll_event(span, 5);
+
+ switch(status) {
+ case ZAP_SUCCESS:
+ {
+ zap_event_t *event;
+ while (zap_span_next_event(span, &event) == ZAP_SUCCESS) {
+ if (event->enum_id == ZAP_OOB_NOOP) {
+ continue;
+ }
+ if (process_event(span, event) != ZAP_SUCCESS) {
+ break;
+ }
+ }
+ }
+ break;
+ case ZAP_FAIL:
+ {
+ zap_log(ZAP_LOG_DEBUG, "Event Failure! %d\n", zap_running());
+ zap_sleep(2000);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * \brief Checks flags on a pri span
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \return 0 on success, -1 on error
+ */
+static int check_flags(lpwrap_pri_t *spri)
+{
+ zap_span_t *span = spri->private_info;
+
+ if (!zap_running() || zap_test_flag(span, ZAP_SPAN_STOP_THREAD)) {
+ return -1;
+ }
+
+ check_state(span);
+ check_events(span);
+
+
+ return 0;
+}
+
+/**
+ * \brief Handler for libpri restart event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_restart(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+ zap_span_t *span = spri->private_info;
+ zap_channel_t *zchan;
+
+ zap_log(ZAP_LOG_NOTICE, "-- Restarting %d:%d\n", spri->span->span_id, pevent->restart.channel);
+
+ zchan = span->channels[pevent->restart.channel];
+
+ if (!zchan) {
+ return 0;
+ }
+
+ if (pevent->restart.channel < 1) {
+ zap_set_state_all(zchan->span, ZAP_CHANNEL_STATE_RESTART);
+ } else {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Handler for libpri dchan up event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_dchan_up(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+
+ if (!zap_test_flag(spri, LPWRAP_PRI_READY)) {
+ zap_log(ZAP_LOG_INFO, "Span %d D-Chan UP!\n", spri->span->span_id);
+ zap_set_flag(spri, LPWRAP_PRI_READY);
+ zap_set_state_all(spri->span, ZAP_CHANNEL_STATE_RESTART);
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Handler for libpri dchan down event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_dchan_down(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+
+ if (zap_test_flag(spri, LPWRAP_PRI_READY)) {
+ zap_log(ZAP_LOG_INFO, "Span %d D-Chan DOWN!\n", spri->span->span_id);
+ zap_clear_flag(spri, LPWRAP_PRI_READY);
+ zap_set_state_all(spri->span, ZAP_CHANNEL_STATE_RESTART);
+
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Handler for any libpri event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_anything(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+
+ zap_log(ZAP_LOG_DEBUG, "Caught Event span %d %u (%s)\n", spri->span->span_id, event_type, lpwrap_pri_event_str(event_type));
+ return 0;
+}
+
+/**
+ * \brief Handler for libpri io fail event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_io_fail(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+
+ zap_log(ZAP_LOG_DEBUG, "Caught Event span %d %u (%s)\n", spri->span->span_id, event_type, lpwrap_pri_event_str(event_type));
+ return 0;
+}
+
+/**
+ * \brief Main thread function for libpri span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *zap_libpri_run(zap_thread_t *me, void *obj)
+{
+ zap_span_t *span = (zap_span_t *) obj;
+ zap_libpri_data_t *isdn_data = span->signal_data;
+ int i, x = 0;
+ int down = 0;
+ int got_d = 0;
+
+ zap_set_flag(span, ZAP_SPAN_IN_THREAD);
+
+ while(zap_running() && !zap_test_flag(span, ZAP_SPAN_STOP_THREAD)) {
+ if (!got_d) {
+ for(i = 1; i <= span->chan_count; i++) {
+ if (span->channels[i]->type == ZAP_CHAN_TYPE_DQ921) {
+ if (zap_channel_open(span->span_id, i, &isdn_data->dchan) == ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_DEBUG, "opening d-channel #%d %d:%d\n", x, isdn_data->dchan->span_id, isdn_data->dchan->chan_id);
+ isdn_data->dchan->state = ZAP_CHANNEL_STATE_UP;
+ got_d = 1;
+ x++;
+ break;
+ }
+ }
+ }
+ }
+
+
+ if (lpwrap_init_pri(&isdn_data->spri,
+ span, // span
+ isdn_data->dchan, // dchan
+ isdn_data->pswitch,
+ isdn_data->node,
+ isdn_data->debug) < 0) {
+ snprintf(span->last_error, sizeof(span->last_error), "PRI init FAIL!");
+ } else {
+
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_ANY, on_anything);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RING, on_ring);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RINGING, on_ringing);
+ //LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_SETUP_ACK, on_proceed);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_PROCEEDING, on_proceed);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_ANSWER, on_answer);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_DCHAN_UP, on_dchan_up);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_DCHAN_DOWN, on_dchan_down);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_HANGUP_REQ, on_hangup);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_HANGUP, on_hangup);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_INFO_RECEIVED, on_info);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RESTART, on_restart);
+ LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_IO_FAIL, on_io_fail);
+
+ if (down) {
+ zap_log(ZAP_LOG_INFO, "PRI back up on span %d\n", isdn_data->spri.span->span_id);
+ zap_set_state_all(span, ZAP_CHANNEL_STATE_RESTART);
+ down = 0;
+ }
+
+ isdn_data->spri.on_loop = check_flags;
+ isdn_data->spri.private_info = span;
+ lpwrap_run_pri(&isdn_data->spri);
+
+ }
+
+ if (!zap_running() || zap_test_flag(span, ZAP_SPAN_STOP_THREAD)) {
+ break;
+ }
+
+ zap_log(ZAP_LOG_CRIT, "PRI down on span %d\n", isdn_data->spri.span->span_id);
+
+ if (!down) {
+ zap_set_state_all(span, ZAP_CHANNEL_STATE_RESTART);
+ check_state(span);
+ }
+
+ check_state(span);
+ check_events(span);
+
+ down++;
+ zap_sleep(5000);
+ }
+
+ zap_log(ZAP_LOG_DEBUG, "PRI thread ended on span %d\n", isdn_data->spri.span->span_id);
+
+ zap_clear_flag(span, ZAP_SPAN_IN_THREAD);
+ zap_clear_flag(isdn_data, OZMOD_LIBPRI_RUNNING);
+
+ return NULL;
+}
+
+/**
+ * \brief Stops a libpri span
+ * \param span Span to halt
+ * \return Success
+ *
+ * Sets a stop flag and waits for the thread to end
+ */
+static zap_status_t zap_libpri_stop(zap_span_t *span)
+{
+ zap_libpri_data_t *isdn_data = span->signal_data;
+
+ if (!zap_test_flag(isdn_data, OZMOD_LIBPRI_RUNNING)) {
+ return ZAP_FAIL;
+ }
+
+ zap_set_state_all(span, ZAP_CHANNEL_STATE_RESTART);
+ check_state(span);
+ zap_set_flag(span, ZAP_SPAN_STOP_THREAD);
+ while(zap_test_flag(span, ZAP_SPAN_IN_THREAD)) {
+ zap_sleep(100);
+ }
+ check_state(span);
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Starts a libpri span
+ * \param span Span to halt
+ * \return Success or failure
+ *
+ * Launches a thread to monitor the span
+ */
+static zap_status_t zap_libpri_start(zap_span_t *span)
+{
+ zap_status_t ret;
+ zap_libpri_data_t *isdn_data = span->signal_data;
+
+ if (zap_test_flag(isdn_data, OZMOD_LIBPRI_RUNNING)) {
+ return ZAP_FAIL;
+ }
+
+ zap_clear_flag(span, ZAP_SPAN_STOP_THREAD);
+ zap_clear_flag(span, ZAP_SPAN_IN_THREAD);
+
+ zap_set_flag(isdn_data, OZMOD_LIBPRI_RUNNING);
+ ret = zap_thread_create_detached(zap_libpri_run, span);
+
+ if (ret != ZAP_SUCCESS) {
+ return ret;
+ }
+
+ return ret;
+}
+
+/**
+ * \brief Converts a node string to node value
+ * \param node Node string to convert
+ * \return -1 on failure, node value on success
+ */
+static int str2node(char *node)
+{
+ if (!strcasecmp(node, "cpe") || !strcasecmp(node, "user"))
+ return PRI_CPE;
+ if (!strcasecmp(node, "network") || !strcasecmp(node, "net"))
+ return PRI_NETWORK;
+ return -1;
+}
+
+/**
+ * \brief Converts a switch string to switch value
+ * \param swtype Swtype string to convert
+ * \return Switch value
+ */
+static int str2switch(char *swtype)
+{
+ if (!strcasecmp(swtype, "ni1"))
+ return PRI_SWITCH_NI1;
+ if (!strcasecmp(swtype, "ni2"))
+ return PRI_SWITCH_NI2;
+ if (!strcasecmp(swtype, "dms100"))
+ return PRI_SWITCH_DMS100;
+ if (!strcasecmp(swtype, "lucent5e") || !strcasecmp(swtype, "5ess"))
+ return PRI_SWITCH_LUCENT5E;
+ if (!strcasecmp(swtype, "att4ess") || !strcasecmp(swtype, "4ess"))
+ return PRI_SWITCH_ATT4ESS;
+ if (!strcasecmp(swtype, "euroisdn"))
+ return PRI_SWITCH_EUROISDN_E1;
+ if (!strcasecmp(swtype, "gr303eoc"))
+ return PRI_SWITCH_GR303_EOC;
+ if (!strcasecmp(swtype, "gr303tmc"))
+ return PRI_SWITCH_GR303_TMC;
+ return PRI_SWITCH_DMS100;
+}
+
+/**
+ * \brief Converts a L1 string to L1 value
+ * \param l1 L1 string to convert
+ * \return L1 value
+ */
+static int str2l1(char *l1)
+{
+ if (!strcasecmp(l1, "alaw"))
+ return PRI_LAYER_1_ALAW;
+
+ return PRI_LAYER_1_ULAW;
+}
+
+/**
+ * \brief Converts a DP string to DP value
+ * \param dp DP string to convert
+ * \return DP value
+ */
+static int str2dp(char *dp)
+{
+ if (!strcasecmp(dp, "international"))
+ return PRI_INTERNATIONAL_ISDN;
+ if (!strcasecmp(dp, "national"))
+ return PRI_NATIONAL_ISDN;
+ if (!strcasecmp(dp, "local"))
+ return PRI_LOCAL_ISDN;
+ if (!strcasecmp(dp, "private"))
+ return PRI_PRIVATE;
+ if (!strcasecmp(dp, "unknown"))
+ return PRI_UNKNOWN;
+
+ return PRI_UNKNOWN;
+}
+
+/**
+ * \brief Initialises a libpri span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static ZIO_SIG_CONFIGURE_FUNCTION(zap_libpri_configure_span)
+{
+ uint32_t i, x = 0;
+ //zap_channel_t *dchans[2] = {0};
+ zap_libpri_data_t *isdn_data;
+ char *var, *val;
+ char *debug = NULL;
+
+ if (span->trunk_type >= ZAP_TRUNK_NONE) {
+ zap_log(ZAP_LOG_WARNING, "Invalid trunk type '%s' defaulting to T1.\n", zap_trunk_type2str(span->trunk_type));
+ span->trunk_type = ZAP_TRUNK_T1;
+ }
+
+ for(i = 1; i <= span->chan_count; i++) {
+ if (span->channels[i]->type == ZAP_CHAN_TYPE_DQ921) {
+ if (x > 1) {
+ snprintf(span->last_error, sizeof(span->last_error), "Span has more than 2 D-Channels!");
+ return ZAP_FAIL;
+ } else {
+#if 0
+ if (zap_channel_open(span->span_id, i, &dchans[x]) == ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_DEBUG, "opening d-channel #%d %d:%d\n", x, dchans[x]->span_id, dchans[x]->chan_id);
+ dchans[x]->state = ZAP_CHANNEL_STATE_UP;
+ x++;
+ }
+#endif
+ }
+ }
+ }
+
+#if 0
+ if (!x) {
+ snprintf(span->last_error, sizeof(span->last_error), "Span has no D-Channels!");
+ return ZAP_FAIL;
+ }
+#endif
+
+ isdn_data = malloc(sizeof(*isdn_data));
+ assert(isdn_data != NULL);
+ memset(isdn_data, 0, sizeof(*isdn_data));
+
+ if (span->trunk_type == ZAP_TRUNK_E1) {
+ zap_log(ZAP_LOG_NOTICE, "Setting default Layer 1 to ALAW since this is an E1 trunk\n");
+ isdn_data->l1 = PRI_LAYER_1_ALAW;
+ } else if (span->trunk_type == ZAP_TRUNK_T1) {
+ zap_log(ZAP_LOG_NOTICE, "Setting default Layer 1 to ULAW since this is a T1 trunk\n");
+ isdn_data->l1 = PRI_LAYER_1_ULAW;
+ }
+
+ while((var = va_arg(ap, char *))) {
+ if (!strcasecmp(var, "node")) {
+ int node;
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ node = str2node(val);
+ if (-1 == node) {
+ zap_log(ZAP_LOG_ERROR, "Unknown node type %s, defaulting to CPE mode\n", val);
+ node = PRI_CPE;
+ }
+ isdn_data->node = node;
+ } else if (!strcasecmp(var, "switch")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ isdn_data->pswitch = str2switch(val);
+ } else if (!strcasecmp(var, "opts")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ isdn_data->opts = parse_opts(val);
+ } else if (!strcasecmp(var, "dp")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ isdn_data->dp = str2dp(val);
+ } else if (!strcasecmp(var, "l1")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ isdn_data->l1 = str2l1(val);
+ } else if (!strcasecmp(var, "debug")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ debug = val;
+ } else {
+ snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+ return ZAP_FAIL;
+ }
+ }
+
+ span->start = zap_libpri_start;
+ span->stop = zap_libpri_stop;
+ span->signal_cb = sig_cb;
+ //isdn_data->dchans[0] = dchans[0];
+ //isdn_data->dchans[1] = dchans[1];
+ //isdn_data->dchan = isdn_data->dchans[0];
+
+ isdn_data->debug = parse_debug(debug);
+
+
+ span->signal_data = isdn_data;
+ span->signal_type = ZAP_SIGTYPE_ISDN;
+ span->outgoing_call = isdn_outgoing_call;
+
+ if ((isdn_data->opts & OZMOD_LIBPRI_OPT_SUGGEST_CHANNEL)) {
+ span->channel_request = isdn_channel_request;
+ span->suggest_chan_id = 1;
+ }
+
+ span->state_map = &isdn_state_map;
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Openzap libpri signaling and IO module definition
+ */
+zap_module_t zap_module = {
+ "libpri",
+ zap_libpri_io_init,
+ zap_libpri_unload,
+ zap_libpri_init,
+ zap_libpri_configure_span,
+ NULL
+};
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2009, Anthony Minessale II
+ * 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.
+ */
+
+
+#ifndef OZMOD_LIBPRI_H
+#define OZMOD_LIBPRI_H
+#include "openzap.h"
+#include "lpwrap_pri.h"
+
+typedef enum {
+ OZMOD_LIBPRI_OPT_NONE = 0,
+ OZMOD_LIBPRI_OPT_SUGGEST_CHANNEL = (1 << 0),
+ OZMOD_LIBPRI_OPT_OMIT_DISPLAY_IE = (1 << 1),
+ OZMOD_LIBPRI_OPT_OMIT_REDIRECTING_NUMBER_IE = (1 << 2),
+
+ OZMOD_LIBPRI_OPT_MAX = (1 << 3)
+} zap_isdn_opts_t;
+
+typedef enum {
+ OZMOD_LIBPRI_RUNNING = (1 << 0)
+} zap_isdn_flag_t;
+
+
+struct zap_libpri_data {
+ zap_channel_t *dchan;
+ zap_channel_t *dchans[2];
+ struct zap_sigmsg sigmsg;
+ uint32_t flags;
+ int32_t mode;
+ zap_isdn_opts_t opts;
+
+ int node;
+ int pswitch;
+ char *dialplan;
+ unsigned int l1;
+ unsigned int dp;
+
+ int debug;
+
+ lpwrap_pri_t spri;
+};
+
+typedef struct zap_libpri_data zap_libpri_data_t;
+
+
+/* b-channel private data */
+struct zap_isdn_bchan_data
+{
+ int32_t digit_timeout;
+};
+
+typedef struct zap_isdn_bchan_data zap_isdn_bchan_data_t;
+
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.2005.vcproj (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.2005.vcproj (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.2005.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ozmod_pika"
+ ProjectGUID="{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}"
+ RootNamespace="ozmod_pika"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_PIKA_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="pikahmpapi.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="..\..\..\pika\aoh\lib"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_PIKA_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="pikahmpapi.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="..\..\..\pika\aoh\lib"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\ozmod_pika.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\zap_pika.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="ozmod_pika"
+ ProjectGUID="{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}"
+ RootNamespace="ozmod_pika"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_PIKA_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="pikahmpapi.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="..\..\..\pika\aoh\lib"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_PIKA_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="pikahmpapi.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="..\..\..\pika\aoh\lib"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\ozmod_pika.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\zap_pika.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1469 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+
+#include "openzap.h"
+#include "zap_pika.h"
+
+
+#define MAX_NUMBER_OF_TRUNKS 64
+#define PIKA_BLOCK_SIZE 160
+#define PIKA_BLOCK_LEN 20
+#define PIKA_NUM_BUFFERS 8
+#define TRY_OR_DIE(__code, __status, __label) if ((status = __code ) != __status) goto __label
+#define pk_atof(__a) (PK_FLOAT) atof(__a)
+
+PK_VOID PK_CALLBACK media_out_callback(PKH_TPikaEvent *event);
+
+ZAP_ENUM_NAMES(PIKA_SPAN_NAMES, PIKA_SPAN_STRINGS)
+PIKA_STR2ENUM(pika_str2span, pika_span2str, PIKA_TSpanFraming, PIKA_SPAN_NAMES, PIKA_SPAN_INVALID)
+
+ZAP_ENUM_NAMES(PIKA_SPAN_ENCODING_NAMES, PIKA_SPAN_ENCODING_STRINGS)
+PIKA_STR2ENUM(pika_str2span_encoding, pika_span_encoding2str, PIKA_TSpanEncoding, PIKA_SPAN_ENCODING_NAMES, PIKA_SPAN_ENCODING_INVALID)
+
+ZAP_ENUM_NAMES(PIKA_LL_NAMES, PIKA_LL_STRINGS)
+PIKA_STR2ENUM(pika_str2loop_length, pika_loop_length2str, PIKA_TSpanLoopLength, PIKA_LL_NAMES, PIKA_SPAN_LOOP_INVALID)
+
+ZAP_ENUM_NAMES(PIKA_LBO_NAMES, PIKA_LBO_STRINGS)
+PIKA_STR2ENUM(pika_str2lbo, pika_lbo2str, PIKA_TSpanBuildOut, PIKA_LBO_NAMES, PIKA_SPAN_LBO_INVALID)
+
+ZAP_ENUM_NAMES(PIKA_SPAN_COMPAND_MODE_NAMES, PIKA_SPAN_COMPAND_MODE_STRINGS)
+PIKA_STR2ENUM(pika_str2compand_mode, pika_compand_mode2str, PIKA_TSpanCompandMode, PIKA_SPAN_COMPAND_MODE_NAMES, PIKA_SPAN_COMPAND_MODE_INVALID)
+
+
+typedef enum {
+ PK_FLAG_READY = (1 << 0),
+ PK_FLAG_LOCKED = (1 << 1)
+} pk_flag_t;
+
+struct general_config {
+ uint32_t region;
+};
+typedef struct general_config general_config_t;
+
+struct pika_channel_profile {
+ char name[80];
+ PKH_TRecordConfig record_config;
+ PKH_TPlayConfig play_config;
+ int ec_enabled;
+ PKH_TECConfig ec_config;
+ PKH_TSpanConfig span_config;
+ general_config_t general_config;
+ int cust_span;
+};
+typedef struct pika_channel_profile pika_channel_profile_t;
+
+static struct {
+ PKH_TSystemDeviceList board_list;
+ TPikaHandle open_boards[MAX_NUMBER_OF_TRUNKS];
+ TPikaHandle system_handle;
+ PKH_TSystemConfig system_config;
+ PKH_TRecordConfig record_config;
+ PKH_TPlayConfig play_config;
+ PKH_TECConfig ec_config;
+ PKH_TSpanConfig t1_span_config;
+ PKH_TSpanConfig e1_span_config;
+ zap_hash_t *profile_hash;
+ general_config_t general_config;
+} globals;
+
+
+struct pika_span_data {
+ TPikaHandle event_queue;
+ PKH_TPikaEvent last_oob_event;
+ uint32_t boardno;
+ PKH_TSpanConfig span_config;
+ TPikaHandle handle;
+ uint32_t flags;
+};
+typedef struct pika_span_data pika_span_data_t;
+
+struct pika_chan_data {
+ TPikaHandle handle;
+ TPikaHandle media_in;
+ TPikaHandle media_out;
+ TPikaHandle media_in_queue;
+ TPikaHandle media_out_queue;
+ PKH_TPikaEvent last_media_event;
+ PKH_TPikaEvent last_oob_event;
+ PKH_TRecordConfig record_config;
+ PKH_TPlayConfig play_config;
+ int ec_enabled;
+ PKH_TECConfig ec_config;
+ PKH_THDLCConfig hdlc_config;
+ zap_buffer_t *digit_buffer;
+ zap_mutex_t *digit_mutex;
+ zap_size_t dtmf_len;
+ uint32_t flags;
+ uint32_t hdlc_bytes;
+};
+typedef struct pika_chan_data pika_chan_data_t;
+
+static const char *pika_board_type_string(PK_UINT type)
+{
+ if (type == PKH_BOARD_TYPE_DIGITAL_GATEWAY) {
+ return "digital_gateway";
+ }
+
+ if (type == PKH_BOARD_TYPE_ANALOG_GATEWAY) {
+ return "analog_gateway";
+ }
+
+ return "unknown";
+}
+
+/**
+ * \brief Process configuration variable for a pika profile
+ * \param category Pika profile name
+ * \param var Variable name
+ * \param val Variable value
+ * \param lineno Line number from configuration file (unused)
+ * \return Success
+ */
+static ZIO_CONFIGURE_FUNCTION(pika_configure)
+{
+ pika_channel_profile_t *profile = NULL;
+ int ok = 1;
+
+ if (!(profile = (pika_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)category))) {
+ profile = malloc(sizeof(*profile));
+ memset(profile, 0, sizeof(*profile));
+ zap_set_string(profile->name, category);
+ profile->ec_config = globals.ec_config;
+ profile->record_config = globals.record_config;
+ profile->play_config = globals.play_config;
+ hashtable_insert(globals.profile_hash, (void *)profile->name, profile, HASHTABLE_FLAG_NONE);
+ zap_log(ZAP_LOG_INFO, "creating profile [%s]\n", category);
+ }
+
+ if (!strcasecmp(var, "rx-gain")) {
+ profile->record_config.gain = pk_atof(val);
+ } else if (!strcasecmp(var, "rx-agc-enabled")) {
+ profile->record_config.AGC.enabled = zap_true(val);
+ } else if (!strcasecmp(var, "rx-agc-targetPower")) {
+ profile->record_config.AGC.targetPower = pk_atof(val);
+ } else if (!strcasecmp(var, "rx-agc-minGain")) {
+ profile->record_config.AGC.minGain = pk_atof(val);
+ } else if (!strcasecmp(var, "rx-agc-maxGain")) {
+ profile->record_config.AGC.maxGain = pk_atof(val);
+ } else if (!strcasecmp(var, "rx-agc-attackRate")) {
+ profile->record_config.AGC.attackRate = atoi(val);
+ } else if (!strcasecmp(var, "rx-agc-decayRate")) {
+ profile->record_config.AGC.decayRate = atoi(val);
+ } else if (!strcasecmp(var, "rx-agc-speechThreshold")) {
+ profile->record_config.AGC.speechThreshold = pk_atof(val);
+ } else if (!strcasecmp(var, "rx-vad-enabled")) {
+ profile->record_config.VAD.enabled = zap_true(val);
+ } else if (!strcasecmp(var, "rx-vad-activationThreshold")) {
+ profile->record_config.VAD.activationThreshold = pk_atof(val);
+ } else if (!strcasecmp(var, "rx-vad-activationDebounceTime")) {
+ profile->record_config.VAD.activationDebounceTime = atoi(val);
+ } else if (!strcasecmp(var, "rx-vad-deactivationThreshold")) {
+ profile->record_config.VAD.deactivationThreshold = pk_atof(val);
+ } else if (!strcasecmp(var, "rx-vad-deactivationDebounceTime")) {
+ profile->record_config.VAD.deactivationDebounceTime = atoi(val);
+ } else if (!strcasecmp(var, "rx-vad-preSpeechBufferSize")) {
+ profile->record_config.VAD.preSpeechBufferSize = atoi(val);
+ } else if (!strcasecmp(var, "tx-gain")) {
+ profile->play_config.gain = pk_atof(val);
+ } else if (!strcasecmp(var, "tx-agc-enabled")) {
+ profile->play_config.AGC.enabled = zap_true(val);
+ } else if (!strcasecmp(var, "tx-agc-targetPower")) {
+ profile->play_config.AGC.targetPower = pk_atof(val);
+ } else if (!strcasecmp(var, "tx-agc-minGain")) {
+ profile->play_config.AGC.minGain = pk_atof(val);
+ } else if (!strcasecmp(var, "tx-agc-maxGain")) {
+ profile->play_config.AGC.maxGain = pk_atof(val);
+ } else if (!strcasecmp(var, "tx-agc-attackRate")) {
+ profile->play_config.AGC.attackRate = atoi(val);
+ } else if (!strcasecmp(var, "tx-agc-decayRate")) {
+ profile->play_config.AGC.decayRate = atoi(val);
+ } else if (!strcasecmp(var, "tx-agc-speechThreshold")) {
+ profile->play_config.AGC.speechThreshold = pk_atof(val);
+ } else if (!strcasecmp(var, "ec-enabled")) {
+ profile->ec_enabled = zap_true(val);
+ } else if (!strcasecmp(var, "ec-doubleTalkerThreshold")) {
+ profile->ec_config.doubleTalkerThreshold = pk_atof(val);
+ } else if (!strcasecmp(var, "ec-speechPresentThreshold")) {
+ profile->ec_config.speechPresentThreshold = pk_atof(val);
+ } else if (!strcasecmp(var, "ec-echoSuppressionThreshold")) {
+ profile->ec_config.echoSuppressionThreshold = pk_atof(val);
+ } else if (!strcasecmp(var, "ec-echoSuppressionEnabled")) {
+ profile->ec_config.echoSuppressionEnabled = zap_true(val);
+ } else if (!strcasecmp(var, "ec-comfortNoiseEnabled")) {
+ profile->ec_config.comfortNoiseEnabled = zap_true(val);
+ } else if (!strcasecmp(var, "ec-adaptationModeEnabled")) {
+ profile->ec_config.adaptationModeEnabled = zap_true(val);
+ } else if (!strcasecmp(var, "framing")) {
+ profile->span_config.framing = pika_str2span(val);
+ profile->cust_span++;
+ } else if (!strcasecmp(var, "encoding")) {
+ profile->span_config.encoding = pika_str2span_encoding(val);
+ profile->cust_span++;
+ } else if (!strcasecmp(var, "loopLength")) {
+ profile->span_config.loopLength = pika_str2loop_length(val);
+ profile->cust_span++;
+ } else if (!strcasecmp(var, "buildOut")) {
+ profile->span_config.buildOut = pika_str2lbo(val);
+ profile->cust_span++;
+ } else if (!strcasecmp(var, "compandMode")) {
+ profile->span_config.compandMode = pika_str2compand_mode(val);
+ profile->cust_span++;
+ } else if (!strcasecmp(var, "region")) {
+ if (!strcasecmp(val, "eu")) {
+ profile->general_config.region = PKH_TRUNK_EU;
+ } else {
+ profile->general_config.region = PKH_TRUNK_NA;
+ }
+ } else {
+ ok = 0;
+ }
+
+ if (ok) {
+ zap_log(ZAP_LOG_INFO, "setting param [%s]=[%s] for profile [%s]\n", var, val, category);
+ } else {
+ zap_log(ZAP_LOG_ERROR, "unknown param [%s]\n", var);
+ }
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Pika event handler
+ * \param event Pika event
+ */
+PK_VOID PK_CALLBACK media_out_callback(PKH_TPikaEvent *event)
+{
+ PK_STATUS pk_status;
+ zap_channel_t *zchan = event->userData;
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+
+ //PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+ //PKH_EVENT_GetText(event->id, event_text, sizeof(event_text));
+ //zap_log(ZAP_LOG_DEBUG, "Event: %s\n", event_text);
+
+ switch (event->id) {
+ case PKH_EVENT_PLAY_IDLE:
+ {
+ while (zap_buffer_inuse(chan_data->digit_buffer)) {
+ char dtmf[128] = "";
+ zap_mutex_lock(chan_data->digit_mutex);
+ chan_data->dtmf_len = zap_buffer_read(chan_data->digit_buffer, dtmf, sizeof(dtmf));
+ pk_status = PKH_TG_PlayDTMF(chan_data->media_out, dtmf);
+ zap_mutex_unlock(chan_data->digit_mutex);
+ }
+ }
+ break;
+ case PKH_EVENT_TG_TONE_PLAYED:
+ {
+
+ if (!event->p1) {
+ zap_mutex_lock(chan_data->digit_mutex);
+ PKH_PLAY_Start(chan_data->media_out);
+ chan_data->dtmf_len = 0;
+ zap_mutex_unlock(chan_data->digit_mutex);
+ }
+
+
+ }
+ break;
+ default:
+ break;
+ }
+
+}
+
+/**
+ * \brief Initialises a range of pika channels
+ * \param span Openzap span
+ * \param boardno Pika board number
+ * \param spanno Pika span number
+ * \param start Initial pika channel number
+ * \param end Final pika channel number
+ * \param type Openzap channel type
+ * \param name Openzap span name
+ * \param number Openzap span number
+ * \param profile Pika channel profile
+ * \return number of spans configured
+ */
+static unsigned pika_open_range(zap_span_t *span, unsigned boardno, unsigned spanno, unsigned start, unsigned end,
+ zap_chan_type_t type, char *name, char *number, pika_channel_profile_t *profile)
+{
+ unsigned configured = 0, x;
+ PK_STATUS status;
+ PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
+ pika_span_data_t *span_data;
+
+ if (boardno >= globals.board_list.numberOfBoards) {
+ zap_log(ZAP_LOG_ERROR, "Board %u is not present!\n", boardno);
+ return 0;
+ }
+
+ if (!globals.open_boards[boardno]) {
+ status = PKH_BOARD_Open(globals.board_list.board[boardno].id,
+ NULL,
+ &globals.open_boards[boardno]);
+ if(status != PK_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error: PKH_BOARD_Open %d failed(%s)!\n", boardno,
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+ return 0;
+ }
+
+ zap_log(ZAP_LOG_DEBUG, "Open board %u\n", boardno);
+
+ //PKH_BOARD_SetDebugTrace(globals.open_boards[boardno], 1, 0);
+
+ }
+
+ if (span->mod_data) {
+ span_data = span->mod_data;
+ } else {
+ span_data = malloc(sizeof(*span_data));
+ assert(span_data != NULL);
+ memset(span_data, 0, sizeof(*span_data));
+ span_data->boardno = boardno;
+
+ status = PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &span_data->event_queue);
+
+ if (status != PK_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error: PKH_QUEUE_Create failed(%s)!\n",
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+ free(span_data);
+ return 0;
+ }
+
+ //PKH_QUEUE_Attach(span_data->event_queue, globals.open_boards[boardno], NULL);
+
+ span->mod_data = span_data;
+ }
+
+ if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO) {
+ start--;
+ end--;
+ }
+
+ for(x = start; x < end; x++) {
+ zap_channel_t *chan;
+ pika_chan_data_t *chan_data = NULL;
+
+ chan_data = malloc(sizeof *chan_data);
+ assert(chan_data);
+ memset(chan_data, 0, sizeof(*chan_data));
+ zap_span_add_channel(span, 0, type, &chan);
+ chan->mod_data = chan_data;
+
+ if ((type == ZAP_CHAN_TYPE_B || type == ZAP_CHAN_TYPE_DQ921) && !span_data->handle) {
+ PKH_TBoardConfig boardConfig;
+
+ TRY_OR_DIE(PKH_BOARD_GetConfig(globals.open_boards[boardno], &boardConfig), PK_SUCCESS, error);
+ if ((profile && profile->general_config.region == PKH_TRUNK_EU) || zap_test_flag(span_data, PK_FLAG_LOCKED)) {
+ if (span->trunk_type == ZAP_TRUNK_T1) {
+ zap_log(ZAP_LOG_WARNING, "Changing trunk type to E1 based on previous config.\n");
+ }
+ span->trunk_type = ZAP_TRUNK_E1;
+ }
+
+ if (span->trunk_type == ZAP_TRUNK_T1) {
+ if (zap_test_flag(span_data, PK_FLAG_LOCKED)) {
+ zap_log(ZAP_LOG_WARNING, "Already locked into E1 mode!\n");
+ }
+ } else if (span->trunk_type == ZAP_TRUNK_E1) {
+ boardConfig.specific.DigitalGateway.interfaceType = PKH_BOARD_INTERFACE_TYPE_E1;
+ if ((status = PKH_BOARD_SetConfig(globals.open_boards[boardno], &boardConfig)) != PK_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error: [%s]\n",
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+ }
+ zap_set_flag(span_data, PK_FLAG_LOCKED);
+ }
+
+ TRY_OR_DIE(PKH_SPAN_Open(globals.open_boards[boardno], spanno, NULL, &span_data->handle), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_SPAN_GetConfig(span_data->handle, &span_data->span_config), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, span_data->handle, (PK_VOID*) span), PK_SUCCESS, error);
+ }
+
+ if (type == ZAP_CHAN_TYPE_FXO) {
+ PKH_TTrunkConfig trunkConfig;
+
+ TRY_OR_DIE(PKH_TRUNK_Open(globals.open_boards[boardno], x, &chan_data->handle), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_TRUNK_Seize(chan_data->handle), PK_SUCCESS, error);
+
+ if (profile && profile->general_config.region == PKH_TRUNK_EU) {
+ TRY_OR_DIE(PKH_TRUNK_GetConfig(chan_data->handle, &trunkConfig), PK_SUCCESS, error);
+ trunkConfig.internationalControl = PKH_PHONE_INTERNATIONAL_CONTROL_EU;
+ trunkConfig.audioFormat = PKH_AUDIO_ALAW;
+ trunkConfig.compandMode = PKH_PHONE_AUDIO_ALAW;
+ chan->native_codec = chan->effective_codec = ZAP_CODEC_ALAW;
+ TRY_OR_DIE(PKH_TRUNK_SetConfig(chan_data->handle, &trunkConfig), PK_SUCCESS, error);
+ } else {
+ chan->native_codec = chan->effective_codec = ZAP_CODEC_ULAW;
+ }
+
+
+ TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_TRUNK_GetMediaStreams(chan_data->handle, &chan_data->media_in, &chan_data->media_out), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->media_in, (PK_VOID*) chan), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_CALLBACK, &chan_data->media_out_queue), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_SetEventHandler(chan_data->media_out_queue, media_out_callback), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_out_queue, chan_data->media_out, (PK_VOID*) chan), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_TRUNK_Start(chan_data->handle), PK_SUCCESS, error);
+ } else if (type == ZAP_CHAN_TYPE_FXS) {
+ PKH_TPhoneConfig phoneConfig;
+
+ if (profile && profile->general_config.region == PKH_TRUNK_EU) {
+ TRY_OR_DIE(PKH_PHONE_GetConfig(chan_data->handle, &phoneConfig), PK_SUCCESS, error);
+ phoneConfig.internationalControl = PKH_PHONE_INTERNATIONAL_CONTROL_EU;
+ phoneConfig.compandMode = PKH_PHONE_AUDIO_ALAW;
+ chan->native_codec = chan->effective_codec = ZAP_CODEC_ALAW;
+ TRY_OR_DIE(PKH_PHONE_SetConfig(chan_data->handle, &phoneConfig), PK_SUCCESS, error);
+ } else {
+ chan->native_codec = chan->effective_codec = ZAP_CODEC_ULAW;
+ }
+
+ TRY_OR_DIE(PKH_PHONE_Open(globals.open_boards[boardno], x, &chan_data->handle), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_PHONE_Seize(chan_data->handle), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_PHONE_GetMediaStreams(chan_data->handle, &chan_data->media_in, &chan_data->media_out), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->media_in, (PK_VOID*) chan), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_CALLBACK, &chan_data->media_out_queue), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_SetEventHandler(chan_data->media_out_queue, media_out_callback), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_out_queue, chan_data->media_out, (PK_VOID*) chan), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_PHONE_Start(chan_data->handle), PK_SUCCESS, error);
+ } else if (type == ZAP_CHAN_TYPE_B) {
+ TRY_OR_DIE(PKH_SPAN_SeizeChannel(span_data->handle, x), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_SPAN_GetMediaStreams(span_data->handle, x, &chan_data->media_in, &chan_data->media_out), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->media_in, (PK_VOID*) chan), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_CALLBACK, &chan_data->media_out_queue), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_SetEventHandler(chan_data->media_out_queue, media_out_callback), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_out_queue, chan_data->media_out, (PK_VOID*) chan), PK_SUCCESS, error);
+ } else if (type == ZAP_CHAN_TYPE_DQ921) {
+ TRY_OR_DIE(PKH_SPAN_HDLC_Open(span_data->handle, PKH_SPAN_HDLC_MODE_NORMAL, &chan_data->handle), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_SPAN_HDLC_GetConfig(chan_data->handle, &chan_data->hdlc_config), PK_SUCCESS, error);
+ chan_data->hdlc_config.channelId = x;
+ TRY_OR_DIE(PKH_SPAN_HDLC_SetConfig(chan_data->handle, &chan_data->hdlc_config), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
+ TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
+
+ if (profile) {
+ if (profile->cust_span) {
+ span_data->span_config.framing = profile->span_config.framing;
+ span_data->span_config.encoding = profile->span_config.encoding;
+ span_data->span_config.loopLength = profile->span_config.loopLength;
+ span_data->span_config.buildOut = profile->span_config.buildOut;
+ span_data->span_config.compandMode = profile->span_config.compandMode;
+ } else {
+ if (profile->general_config.region == PKH_TRUNK_EU) {
+ span_data->span_config = globals.e1_span_config;
+ } else {
+ span_data->span_config = globals.t1_span_config;
+ }
+ }
+ } else {
+ if (span->trunk_type == ZAP_TRUNK_E1) {
+ span_data->span_config = globals.e1_span_config;
+ } else {
+ span_data->span_config = globals.t1_span_config;
+ }
+ }
+
+ PKH_SPAN_SetConfig(span_data->handle, &span_data->span_config);
+ TRY_OR_DIE(PKH_SPAN_Start(span_data->handle), PK_SUCCESS, error);
+ }
+
+ goto ok;
+
+ error:
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text));
+ zap_log(ZAP_LOG_ERROR, "failure configuring device b%ds%dc%d [%s]\n", boardno, spanno, x, error_text);
+ continue;
+ ok:
+ zap_set_flag(chan_data, PK_FLAG_READY);
+ status = PKH_RECORD_GetConfig(chan_data->media_in, &chan_data->record_config);
+ chan_data->record_config.encoding = PKH_RECORD_ENCODING_MU_LAW;
+ chan_data->record_config.samplingRate = PKH_RECORD_SAMPLING_RATE_8KHZ;
+ chan_data->record_config.bufferSize = PIKA_BLOCK_SIZE;
+ chan_data->record_config.numberOfBuffers = PIKA_NUM_BUFFERS;
+ chan_data->record_config.VAD.enabled = PK_FALSE;
+ //chan_data->record_config.speechSegmentEventsEnabled = PK_FALSE;
+ //chan_data->record_config.gain = rxgain;
+
+ status = PKH_PLAY_GetConfig(chan_data->media_out, &chan_data->play_config);
+ chan_data->play_config.encoding = PKH_RECORD_ENCODING_MU_LAW;
+ chan_data->play_config.samplingRate = PKH_RECORD_SAMPLING_RATE_8KHZ;
+ chan_data->play_config.AGC.enabled = PK_FALSE;
+ zap_log(ZAP_LOG_INFO, "configuring device b%ds%dc%d as OpenZAP device %d:%d\n", boardno, spanno, x, chan->span_id, chan->chan_id);
+
+ if (profile) {
+ zap_log(ZAP_LOG_INFO, "applying config profile %s to device %d:%d\n", profile->name, chan->span_id, chan->chan_id);
+ chan_data->record_config.gain = profile->record_config.gain;
+ chan_data->record_config.AGC = profile->record_config.AGC;
+ chan_data->record_config.VAD = profile->record_config.VAD;
+ chan_data->play_config.gain = profile->play_config.gain;
+ chan_data->play_config.AGC = profile->play_config.AGC;
+ chan_data->ec_enabled = profile->ec_enabled;
+ chan_data->ec_config = profile->ec_config;
+ }
+
+ if (type == ZAP_CHAN_TYPE_B) {
+ if (span_data->span_config.compandMode == PKH_SPAN_COMPAND_MODE_A_LAW) {
+ chan->native_codec = chan->effective_codec = ZAP_CODEC_ALAW;
+ } else {
+ chan->native_codec = chan->effective_codec = ZAP_CODEC_ULAW;
+ }
+ }
+
+ status = PKH_RECORD_SetConfig(chan_data->media_in, &chan_data->record_config);
+ status = PKH_PLAY_SetConfig(chan_data->media_out, &chan_data->play_config);
+
+ chan->physical_span_id = spanno;
+ chan->physical_chan_id = x;
+
+ chan->rate = 8000;
+ chan->packet_len = (uint32_t)chan_data->record_config.bufferSize;
+ chan->effective_interval = chan->native_interval = chan->packet_len / 8;
+
+ PKH_RECORD_Start(chan_data->media_in);
+ PKH_PLAY_Start(chan_data->media_out);
+ if (chan_data->ec_enabled) {
+ PKH_EC_SetConfig(chan_data->media_in, &chan_data->ec_config);
+ PKH_EC_Start(chan_data->media_in, chan_data->media_in, chan_data->media_out);
+ }
+
+ if (!zap_strlen_zero(name)) {
+ zap_copy_string(chan->chan_name, name, sizeof(chan->chan_name));
+ }
+
+ if (!zap_strlen_zero(number)) {
+ zap_copy_string(chan->chan_number, number, sizeof(chan->chan_number));
+ }
+
+ zap_channel_set_feature(chan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE);
+ zap_buffer_create(&chan_data->digit_buffer, 128, 128, 0);
+ zap_mutex_create(&chan_data->digit_mutex);
+
+ configured++;
+ }
+
+
+ return configured;
+}
+
+/**
+ * \brief Initialises an openzap pika span from a configuration string
+ * \param span Openzap span
+ * \param str Configuration string
+ * \param type Openzap span type
+ * \param name Openzap span name
+ * \param number Openzap span number
+ * \return Success or failure
+ */
+static ZIO_CONFIGURE_SPAN_FUNCTION(pika_configure_span)
+{
+ int items, i;
+ char *mydata, *item_list[10];
+ char *bd, *sp, *ch = NULL, *mx;
+ int boardno;
+ int channo;
+ int spanno;
+ int top = 0;
+ unsigned configured = 0;
+ char *profile_name = NULL;
+ pika_channel_profile_t *profile = NULL;
+
+ assert(str != NULL);
+
+ mydata = strdup(str);
+ assert(mydata != NULL);
+
+ if ((profile_name = strchr(mydata, '@'))) {
+ *profile_name++ = '\0';
+ if (!zap_strlen_zero(profile_name)) {
+ profile = (pika_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)profile_name);
+ }
+ }
+
+ items = zap_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
+
+ for(i = 0; i < items; i++) {
+ bd = item_list[i];
+ if ((sp = strchr(bd, ':'))) {
+ *sp++ = '\0';
+ if ((ch = strchr(sp, ':'))) {
+ *ch++ = '\0';
+ }
+ }
+
+ if (!(bd && sp && ch)) {
+ zap_log(ZAP_LOG_ERROR, "Invalid input\n");
+ continue;
+ }
+
+ boardno = atoi(bd);
+ channo = atoi(ch);
+ spanno = atoi(sp);
+
+
+ if (boardno < 0) {
+ zap_log(ZAP_LOG_ERROR, "Invalid board number %d\n", boardno);
+ continue;
+ }
+
+ if (channo < 0) {
+ zap_log(ZAP_LOG_ERROR, "Invalid channel number %d\n", channo);
+ continue;
+ }
+
+ if (spanno < 0) {
+ zap_log(ZAP_LOG_ERROR, "Invalid span number %d\n", channo);
+ continue;
+ }
+
+ if ((mx = strchr(ch, '-'))) {
+ mx++;
+ top = atoi(mx) + 1;
+ } else {
+ top = channo + 1;
+ }
+
+
+ if (top < 0) {
+ zap_log(ZAP_LOG_ERROR, "Invalid range number %d\n", top);
+ continue;
+ }
+
+ configured += pika_open_range(span, boardno, spanno, channo, top, type, name, number, profile);
+
+ }
+
+ free(mydata);
+
+ return configured;
+}
+
+/**
+ * \brief Opens Pika channel
+ * \param zchan Channel to open
+ * \return Success or failure
+ */
+static ZIO_OPEN_FUNCTION(pika_open)
+{
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+
+ if (!chan_data && !zap_test_flag(chan_data, PK_FLAG_READY)) {
+ return ZAP_FAIL;
+ }
+
+ if (chan_data->media_in_queue) {
+ PKH_QUEUE_Flush(chan_data->media_in_queue);
+ }
+
+ if (zchan->type == ZAP_CHAN_TYPE_FXS || zchan->type == ZAP_CHAN_TYPE_FXO || zchan->type == ZAP_CHAN_TYPE_B) {
+ PKH_PLAY_Start(chan_data->media_out);
+ }
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Closes Pika channel
+ * \param zchan Channel to close
+ * \return Success
+ */
+static ZIO_CLOSE_FUNCTION(pika_close)
+{
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Waits for an event on a Pika channel
+ * \param zchan Channel to open
+ * \param flags Type of event to wait for
+ * \param to Time to wait (in ms)
+ * \return Success, failure or timeout
+ */
+static ZIO_WAIT_FUNCTION(pika_wait)
+{
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+ PK_STATUS status;
+ zap_wait_flag_t myflags = *flags;
+ PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+
+ *flags = ZAP_NO_FLAGS;
+
+ if (myflags & ZAP_READ) {
+ if (chan_data->hdlc_bytes) {
+ *flags |= ZAP_READ;
+ return ZAP_SUCCESS;
+ }
+ status = PKH_QUEUE_WaitOnEvent(chan_data->media_in_queue, to, &chan_data->last_media_event);
+
+ if (status == PK_SUCCESS) {
+ if (chan_data->last_media_event.id == PKH_EVENT_QUEUE_TIMEOUT || chan_data->last_media_event.id == PKH_EVENT_RECORD_BUFFER_OVERFLOW) {
+ return ZAP_TIMEOUT;
+ }
+
+ *flags |= ZAP_READ;
+ return ZAP_SUCCESS;
+ }
+
+ PKH_EVENT_GetText(chan_data->last_media_event.id, event_text, sizeof(event_text));
+ zap_log(ZAP_LOG_DEBUG, "Event: %s\n", event_text);
+ }
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Reads data from a Pika channel
+ * \param zchan Channel to read from
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success or failure
+ */
+static ZIO_READ_FUNCTION(pika_read)
+{
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+ PK_STATUS status;
+ PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+ uint32_t len;
+
+ if (zchan->type == ZAP_CHAN_TYPE_DQ921) {
+ if ((status = PKH_SPAN_HDLC_GetMessage(chan_data->handle, data, *datalen)) == PK_SUCCESS) {
+ *datalen = chan_data->hdlc_bytes;
+ chan_data->hdlc_bytes = 0;
+ return ZAP_SUCCESS;
+ }
+ return ZAP_FAIL;
+ }
+
+ if (!(len = chan_data->last_media_event.p0)) {
+ len = zchan->packet_len;
+ }
+
+ if (len < *datalen) {
+ *datalen = len;
+ }
+
+ if ((status = PKH_RECORD_GetData(chan_data->media_in, data, *datalen)) == PK_SUCCESS) {
+ return ZAP_SUCCESS;
+ }
+
+
+ PKH_ERROR_GetText(status, event_text, sizeof(event_text));
+ zap_log(ZAP_LOG_DEBUG, "ERR: %s\n", event_text);
+ return ZAP_FAIL;
+}
+
+/**
+ * \brief Writes data to a Pika channel
+ * \param zchan Channel to write to
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success or failure
+ */
+static ZIO_WRITE_FUNCTION(pika_write)
+{
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+ PK_STATUS status;
+
+ if (zchan->type == ZAP_CHAN_TYPE_DQ921) {
+ if ((status = PKH_SPAN_HDLC_SendMessage(chan_data->handle, data, *datalen)) == PK_SUCCESS) {
+ return ZAP_SUCCESS;
+ }
+ return ZAP_FAIL;
+ }
+
+ if (PKH_PLAY_AddData(chan_data->media_out, 0, data, *datalen) == PK_SUCCESS) {
+ return ZAP_SUCCESS;
+ }
+
+ return ZAP_FAIL;
+}
+
+/**
+ * \brief Executes an Openzap command on a Pika channel
+ * \param zchan Channel to execute command on
+ * \param command Openzap command to execute
+ * \param obj Object (unused)
+ * \return Success or failure
+ */
+static ZIO_COMMAND_FUNCTION(pika_command)
+{
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+ //pika_span_data_t *span_data = (pika_span_data_t *) zchan->span->mod_data;
+ PK_STATUS pk_status;
+ zap_status_t status = ZAP_SUCCESS;
+
+ switch(command) {
+ case ZAP_COMMAND_OFFHOOK:
+ {
+ if ((pk_status = PKH_TRUNK_SetHookSwitch(chan_data->handle, PKH_TRUNK_OFFHOOK)) != PK_SUCCESS) {
+ PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
+ GOTO_STATUS(done, ZAP_FAIL);
+ } else {
+ zap_set_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
+ }
+ }
+ break;
+ case ZAP_COMMAND_ONHOOK:
+ {
+ if ((pk_status = PKH_TRUNK_SetHookSwitch(chan_data->handle, PKH_TRUNK_ONHOOK)) != PK_SUCCESS) {
+ PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
+ GOTO_STATUS(done, ZAP_FAIL);
+ } else {
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
+ }
+ }
+ break;
+ case ZAP_COMMAND_GENERATE_RING_ON:
+ {
+ if ((pk_status = PKH_PHONE_RingStart(chan_data->handle, 0, 0)) != PK_SUCCESS) {
+ PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
+ GOTO_STATUS(done, ZAP_FAIL);
+ } else {
+ zap_set_flag_locked(zchan, ZAP_CHANNEL_RINGING);
+ }
+ }
+ break;
+ case ZAP_COMMAND_GENERATE_RING_OFF:
+ {
+ if ((pk_status = PKH_PHONE_RingStop(chan_data->handle)) != PK_SUCCESS) {
+ PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
+ GOTO_STATUS(done, ZAP_FAIL);
+ } else {
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_RINGING);
+ }
+ }
+ break;
+ case ZAP_COMMAND_GET_INTERVAL:
+ {
+
+ ZAP_COMMAND_OBJ_INT = zchan->native_interval;
+
+ }
+ break;
+ case ZAP_COMMAND_SET_INTERVAL:
+ {
+ int interval = ZAP_COMMAND_OBJ_INT;
+ int len = interval * 8;
+ chan_data->record_config.bufferSize = len;
+ chan_data->record_config.numberOfBuffers = (PK_UINT)chan_data->record_config.bufferSize;
+ zchan->packet_len = (uint32_t)chan_data->record_config.bufferSize;
+ zchan->effective_interval = zchan->native_interval = zchan->packet_len / 8;
+ PKH_RECORD_SetConfig(chan_data->media_in, &chan_data->record_config);
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ break;
+ case ZAP_COMMAND_GET_DTMF_ON_PERIOD:
+ {
+
+ ZAP_COMMAND_OBJ_INT = zchan->dtmf_on;
+ GOTO_STATUS(done, ZAP_SUCCESS);
+
+ }
+ break;
+ case ZAP_COMMAND_GET_DTMF_OFF_PERIOD:
+ {
+ ZAP_COMMAND_OBJ_INT = zchan->dtmf_on;
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ break;
+ case ZAP_COMMAND_SET_DTMF_ON_PERIOD:
+ {
+ int val = ZAP_COMMAND_OBJ_INT;
+ if (val > 10 && val < 1000) {
+ zchan->dtmf_on = val;
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ } else {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid value %d range 10-1000", val);
+ GOTO_STATUS(done, ZAP_FAIL);
+ }
+ }
+ break;
+ case ZAP_COMMAND_SET_DTMF_OFF_PERIOD:
+ {
+ int val = ZAP_COMMAND_OBJ_INT;
+ if (val > 10 && val < 1000) {
+ zchan->dtmf_off = val;
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ } else {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid value %d range 10-1000", val);
+ GOTO_STATUS(done, ZAP_FAIL);
+ }
+ }
+ break;
+ case ZAP_COMMAND_SEND_DTMF:
+ {
+ char *digits = ZAP_COMMAND_OBJ_CHAR_P;
+ zap_log(ZAP_LOG_DEBUG, "Adding DTMF SEQ [%s]\n", digits);
+ zap_mutex_lock(chan_data->digit_mutex);
+ zap_buffer_write(chan_data->digit_buffer, digits, strlen(digits));
+ zap_mutex_unlock(chan_data->digit_mutex);
+ pk_status = PKH_PLAY_Stop(chan_data->media_out);
+
+ if (pk_status != PK_SUCCESS) {
+ PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
+ GOTO_STATUS(done, ZAP_FAIL);
+ }
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ break;
+ default:
+ break;
+ };
+
+ done:
+ return status;
+}
+
+/**
+ * \brief Checks for events on a Pika span
+ * \param span Span to check for events
+ * \param ms Time to wait for event
+ * \return Success if event is waiting or failure if not
+ */
+static ZIO_SPAN_POLL_EVENT_FUNCTION(pika_poll_event)
+{
+ pika_span_data_t *span_data = (pika_span_data_t *) span->mod_data;
+ PK_STATUS status;
+ PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+
+ status = PKH_QUEUE_WaitOnEvent(span_data->event_queue, ms, &span_data->last_oob_event);
+
+ if (status == PK_SUCCESS) {
+ zap_channel_t *zchan = NULL;
+ uint32_t *data = (uint32_t *) span_data->last_oob_event.userData;
+ zap_data_type_t data_type = ZAP_TYPE_NONE;
+
+ if (span_data->last_oob_event.id == PKH_EVENT_QUEUE_TIMEOUT) {
+ return ZAP_TIMEOUT;
+ }
+
+ if (data) {
+ data_type = *data;
+ }
+
+ if (data_type == ZAP_TYPE_CHANNEL) {
+ zchan = span_data->last_oob_event.userData;
+ } else if (data_type == ZAP_TYPE_SPAN) {
+ zap_time_t last_event_time = zap_current_time_in_ms();
+ uint32_t event_id = 0;
+
+ switch (span_data->last_oob_event.id) {
+ case PKH_EVENT_SPAN_ALARM_T1_RED:
+ case PKH_EVENT_SPAN_ALARM_T1_YELLOW:
+ case PKH_EVENT_SPAN_ALARM_T1_AIS:
+ case PKH_EVENT_SPAN_ALARM_E1_RED:
+ case PKH_EVENT_SPAN_ALARM_E1_RAI:
+ case PKH_EVENT_SPAN_ALARM_E1_AIS:
+ case PKH_EVENT_SPAN_ALARM_E1_RMAI:
+ case PKH_EVENT_SPAN_ALARM_E1_TS16AIS:
+ case PKH_EVENT_SPAN_ALARM_E1_TS16LOS:
+ case PKH_EVENT_SPAN_OUT_OF_SYNC:
+ case PKH_EVENT_SPAN_FRAMING_ERROR:
+ case PKH_EVENT_SPAN_LOSS_OF_SIGNAL:
+ case PKH_EVENT_SPAN_OUT_OF_CRC_MF_SYNC:
+ case PKH_EVENT_SPAN_OUT_OF_CAS_MF_SYNC:
+ event_id = ZAP_OOB_ALARM_TRAP;
+ break;
+ case PKH_EVENT_SPAN_ALARM_T1_RED_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_T1_YELLOW_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_T1_AIS_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_E1_RED_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_E1_RAI_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_E1_AIS_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_E1_RMAI_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_E1_TS16AIS_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_E1_TS16LOS_CLEAR:
+ case PKH_EVENT_SPAN_IN_SYNC:
+ case PKH_EVENT_SPAN_LOSS_OF_SIGNAL_CLEAR:
+ case PKH_EVENT_SPAN_IN_CRC_MF_SYNC:
+ case PKH_EVENT_SPAN_IN_CAS_MF_SYNC:
+ event_id = ZAP_OOB_ALARM_CLEAR;
+ break;
+ case PKH_EVENT_SPAN_MESSAGE:
+ case PKH_EVENT_SPAN_ABCD_SIGNAL_CHANGE:
+ break;
+ }
+
+ if (event_id) {
+ uint32_t x = 0;
+ zap_channel_t *zchan;
+ pika_chan_data_t *chan_data;
+ for(x = 1; x <= span->chan_count; x++) {
+ zchan = span->channels[x];
+ assert(zchan != NULL);
+ chan_data = (pika_chan_data_t *) zchan->mod_data;
+ assert(chan_data != NULL);
+
+
+ zap_set_flag(zchan, ZAP_CHANNEL_EVENT);
+ zchan->last_event_time = last_event_time;
+ chan_data->last_oob_event = span_data->last_oob_event;
+ }
+
+ }
+
+ }
+
+ PKH_EVENT_GetText(span_data->last_oob_event.id, event_text, sizeof(event_text));
+ //zap_log(ZAP_LOG_DEBUG, "Event: %s\n", event_text);
+
+ if (zchan) {
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+
+ assert(chan_data != NULL);
+ zap_set_flag(zchan, ZAP_CHANNEL_EVENT);
+ zchan->last_event_time = zap_current_time_in_ms();
+ chan_data->last_oob_event = span_data->last_oob_event;
+ }
+
+ return ZAP_SUCCESS;
+ }
+
+ return ZAP_FAIL;
+}
+
+/**
+ * \brief Retrieves an event from a Pika span
+ * \param span Span to retrieve event from
+ * \param event Openzap event to return
+ * \return Success or failure
+ */
+static ZIO_SPAN_NEXT_EVENT_FUNCTION(pika_next_event)
+{
+ uint32_t i, event_id = 0;
+
+ for(i = 1; i <= span->chan_count; i++) {
+ if (zap_test_flag(span->channels[i], ZAP_CHANNEL_EVENT)) {
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) span->channels[i]->mod_data;
+ PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+
+ zap_clear_flag(span->channels[i], ZAP_CHANNEL_EVENT);
+
+ PKH_EVENT_GetText(chan_data->last_oob_event.id, event_text, sizeof(event_text));
+
+ switch(chan_data->last_oob_event.id) {
+ case PKH_EVENT_HDLC_MESSAGE:
+ chan_data->hdlc_bytes = chan_data->last_oob_event.p2;
+ continue;
+ case PKH_EVENT_TRUNK_HOOKFLASH:
+ event_id = ZAP_OOB_FLASH;
+ break;
+ case PKH_EVENT_TRUNK_RING_OFF:
+ event_id = ZAP_OOB_RING_STOP;
+ break;
+ case PKH_EVENT_TRUNK_RING_ON:
+ event_id = ZAP_OOB_RING_START;
+ break;
+
+ case PKH_EVENT_PHONE_OFFHOOK:
+ zap_set_flag_locked(span->channels[i], ZAP_CHANNEL_OFFHOOK);
+ event_id = ZAP_OOB_OFFHOOK;
+ break;
+
+ case PKH_EVENT_TRUNK_BELOW_THRESHOLD:
+ case PKH_EVENT_TRUNK_ABOVE_THRESHOLD:
+ case PKH_EVENT_PHONE_ONHOOK:
+ zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_OFFHOOK);
+ event_id = ZAP_OOB_ONHOOK;
+ break;
+
+
+
+ case PKH_EVENT_SPAN_ALARM_T1_RED:
+ zap_set_alarm_flag(span->channels[i], ZAP_ALARM_RED);
+ snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "RED ALARM");
+ event_id = ZAP_OOB_ALARM_TRAP;
+ break;
+ case PKH_EVENT_SPAN_ALARM_T1_YELLOW:
+ zap_set_alarm_flag(span->channels[i], ZAP_ALARM_YELLOW);
+ snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "YELLOW ALARM");
+ event_id = ZAP_OOB_ALARM_TRAP;
+ break;
+ case PKH_EVENT_SPAN_ALARM_T1_AIS:
+ zap_set_alarm_flag(span->channels[i], ZAP_ALARM_AIS);
+ snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "AIS ALARM");
+ event_id = ZAP_OOB_ALARM_TRAP;
+ break;
+ case PKH_EVENT_SPAN_ALARM_E1_RED:
+ zap_set_alarm_flag(span->channels[i], ZAP_ALARM_RED);
+ snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "RED ALARM");
+ event_id = ZAP_OOB_ALARM_TRAP;
+ break;
+ case PKH_EVENT_SPAN_ALARM_E1_RAI:
+ zap_set_alarm_flag(span->channels[i], ZAP_ALARM_RAI);
+ snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "RAI ALARM");
+ event_id = ZAP_OOB_ALARM_TRAP;
+ break;
+ case PKH_EVENT_SPAN_ALARM_E1_AIS:
+ zap_set_alarm_flag(span->channels[i], ZAP_ALARM_AIS);
+ snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "AIS ALARM");
+ event_id = ZAP_OOB_ALARM_TRAP;
+ break;
+ case PKH_EVENT_SPAN_ALARM_E1_RMAI:
+ case PKH_EVENT_SPAN_ALARM_E1_TS16AIS:
+ case PKH_EVENT_SPAN_ALARM_E1_TS16LOS:
+ case PKH_EVENT_SPAN_OUT_OF_SYNC:
+ case PKH_EVENT_SPAN_FRAMING_ERROR:
+ case PKH_EVENT_SPAN_LOSS_OF_SIGNAL:
+ case PKH_EVENT_SPAN_OUT_OF_CRC_MF_SYNC:
+ case PKH_EVENT_SPAN_OUT_OF_CAS_MF_SYNC:
+ zap_set_alarm_flag(span->channels[i], ZAP_ALARM_GENERAL);
+ snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "GENERAL ALARM");
+ event_id = ZAP_OOB_ALARM_TRAP;
+ break;
+ case PKH_EVENT_SPAN_ALARM_T1_RED_CLEAR:
+ zap_set_alarm_flag(span->channels[i], ZAP_ALARM_RED);
+ case PKH_EVENT_SPAN_ALARM_T1_YELLOW_CLEAR:
+ zap_set_alarm_flag(span->channels[i], ZAP_ALARM_YELLOW);
+ case PKH_EVENT_SPAN_ALARM_T1_AIS_CLEAR:
+ zap_set_alarm_flag(span->channels[i], ZAP_ALARM_AIS);
+ case PKH_EVENT_SPAN_ALARM_E1_RED_CLEAR:
+ zap_set_alarm_flag(span->channels[i], ZAP_ALARM_RED);
+ case PKH_EVENT_SPAN_ALARM_E1_RAI_CLEAR:
+ zap_set_alarm_flag(span->channels[i], ZAP_ALARM_RAI);
+ case PKH_EVENT_SPAN_ALARM_E1_AIS_CLEAR:
+ zap_set_alarm_flag(span->channels[i], ZAP_ALARM_AIS);
+ case PKH_EVENT_SPAN_ALARM_E1_RMAI_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_E1_TS16AIS_CLEAR:
+ case PKH_EVENT_SPAN_ALARM_E1_TS16LOS_CLEAR:
+ case PKH_EVENT_SPAN_IN_SYNC:
+ case PKH_EVENT_SPAN_LOSS_OF_SIGNAL_CLEAR:
+ case PKH_EVENT_SPAN_IN_CRC_MF_SYNC:
+ case PKH_EVENT_SPAN_IN_CAS_MF_SYNC:
+ zap_clear_alarm_flag(span->channels[i], ZAP_ALARM_GENERAL);
+ event_id = ZAP_OOB_ALARM_CLEAR;
+ break;
+ case PKH_EVENT_SPAN_MESSAGE:
+ case PKH_EVENT_SPAN_ABCD_SIGNAL_CHANGE:
+ break;
+
+
+
+
+ case PKH_EVENT_TRUNK_ONHOOK:
+ case PKH_EVENT_TRUNK_OFFHOOK:
+ case PKH_EVENT_TRUNK_DIALED :
+ case PKH_EVENT_TRUNK_REVERSAL:
+ case PKH_EVENT_TRUNK_LCSO:
+ case PKH_EVENT_TRUNK_DROPOUT:
+ case PKH_EVENT_TRUNK_LOF:
+ case PKH_EVENT_TRUNK_RX_OVERLOAD:
+ default:
+ zap_log(ZAP_LOG_DEBUG, "Unhandled event %d on channel %d [%s]\n", chan_data->last_oob_event.id, i, event_text);
+ event_id = ZAP_OOB_INVALID;
+ break;
+ }
+
+ span->channels[i]->last_event_time = 0;
+ span->event_header.e_type = ZAP_EVENT_OOB;
+ span->event_header.enum_id = event_id;
+ span->event_header.channel = span->channels[i];
+ *event = &span->event_header;
+ return ZAP_SUCCESS;
+ }
+ }
+
+ return ZAP_FAIL;
+}
+
+/**
+ * \brief Destroys a Pika Span
+ * \param span Span to destroy
+ * \return Success
+ */
+static ZIO_SPAN_DESTROY_FUNCTION(pika_span_destroy)
+{
+ pika_span_data_t *span_data = (pika_span_data_t *) span->mod_data;
+
+ if (span_data) {
+ PKH_QUEUE_Destroy(span_data->event_queue);
+ free(span_data);
+ }
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Destroys a Pika Channel
+ * \param zchan Channel to destroy
+ * \return Success or failure
+ */
+static ZIO_CHANNEL_DESTROY_FUNCTION(pika_channel_destroy)
+{
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+ pika_span_data_t *span_data = (pika_span_data_t *) zchan->span->mod_data;
+
+ if (!chan_data) {
+ return ZAP_FAIL;
+ }
+
+ if (!zap_test_flag(chan_data, PK_FLAG_READY)) {
+ goto end;
+ }
+
+ PKH_RECORD_Stop(chan_data->media_in);
+ PKH_PLAY_Stop(chan_data->media_out);
+ PKH_QUEUE_Destroy(chan_data->media_in_queue);
+ PKH_QUEUE_Destroy(chan_data->media_out_queue);
+
+ switch(zchan->type) {
+ case ZAP_CHAN_TYPE_FXS:
+ PKH_QUEUE_Detach(span_data->event_queue, chan_data->handle);
+ PKH_PHONE_Close(chan_data->handle);
+ break;
+ case ZAP_CHAN_TYPE_FXO:
+ PKH_QUEUE_Detach(span_data->event_queue, chan_data->handle);
+ PKH_TRUNK_Close(chan_data->handle);
+ break;
+ case ZAP_CHAN_TYPE_DQ921:
+ PKH_SPAN_Stop(span_data->handle);
+ break;
+ default:
+ break;
+ }
+
+
+ zap_mutex_destroy(&chan_data->digit_mutex);
+ zap_buffer_destroy(&chan_data->digit_buffer);
+
+ end:
+ zap_safe_free(chan_data);
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Gets alarms from a Pika Channel (does nothing)
+ * \param zchan Channel to get alarms from
+ * \return Failure
+ */
+static ZIO_GET_ALARMS_FUNCTION(pika_get_alarms)
+{
+ return ZAP_FAIL;
+}
+
+static zap_io_interface_t pika_interface;
+
+/**
+ * \brief Loads Pika IO module
+ * \param zio Openzap IO interface
+ * \return Success or failure
+ */
+static ZIO_IO_LOAD_FUNCTION(pika_init)
+{
+
+ PK_STATUS status;
+ PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
+ uint32_t i;
+ int ok = 0;
+ PKH_TLogMasks m;
+ TPikaHandle tmpHandle;
+
+ assert(zio != NULL);
+ memset(&pika_interface, 0, sizeof(pika_interface));
+ memset(&globals, 0, sizeof(globals));
+ globals.general_config.region = PKH_TRUNK_NA;
+
+ globals.profile_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys);
+
+ // Open the system object, to enumerate boards configured for this system
+ if ((status = PKH_SYSTEM_Open(&globals.system_handle)) != PK_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error: PKH_SYSTEM_Open failed(%s)!\n",
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+ return ZAP_FAIL;
+ }
+
+ // Retrieves a list of all boards in this system, existing,
+ // or listed in pika.cfg
+ if ((status = PKH_SYSTEM_Detect(globals.system_handle, &globals.board_list)) != PK_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error: PKH_SYSTEM_Detect failed(%s)!\n",
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+ return ZAP_FAIL;
+ }
+
+ PKH_SYSTEM_GetConfig(globals.system_handle, &globals.system_config);
+ globals.system_config.maxAudioProcessBlockSize = PIKA_BLOCK_LEN;
+ globals.system_config.playBufferSize = PIKA_BLOCK_SIZE;
+ globals.system_config.recordBufferSize = PIKA_BLOCK_SIZE;
+ globals.system_config.recordNumberOfBuffers = PIKA_NUM_BUFFERS;
+ PKH_SYSTEM_SetConfig(globals.system_handle, &globals.system_config);
+
+ status = PKH_MEDIA_STREAM_Create(&tmpHandle);
+ status = PKH_RECORD_GetConfig(tmpHandle, &globals.record_config);
+ status = PKH_PLAY_GetConfig(tmpHandle, &globals.play_config);
+ status = PKH_EC_GetConfig(tmpHandle, &globals.ec_config);
+ status = PKH_MEDIA_STREAM_Destroy(tmpHandle);
+
+
+
+ zap_log(ZAP_LOG_DEBUG, "Found %u board%s\n", globals.board_list.numberOfBoards, globals.board_list.numberOfBoards == 1 ? "" : "s");
+ for(i = 0; i < globals.board_list.numberOfBoards; ++i) {
+ zap_log(ZAP_LOG_INFO, "Found PIKA board type:[%s] id:[%u] serno:[%u]\n",
+ pika_board_type_string(globals.board_list.board[i].type), globals.board_list.board[i].id, (uint32_t)
+ globals.board_list.board[i].serialNumber);
+
+ if (globals.board_list.board[i].type == PKH_BOARD_TYPE_DIGITAL_GATEWAY) {
+ TPikaHandle board_handle, span_handle;
+ PKH_TBoardConfig boardConfig;
+ PKH_BOARD_GetConfig(board_handle, &boardConfig);
+ PKH_BOARD_Open(globals.board_list.board[i].id, NULL, &board_handle);
+ PKH_SPAN_Open(board_handle, 0, NULL, &span_handle);
+ PKH_SPAN_GetConfig(span_handle, &globals.t1_span_config);
+ PKH_SPAN_Close(span_handle);
+ boardConfig.specific.DigitalGateway.interfaceType = PKH_BOARD_INTERFACE_TYPE_E1;
+ PKH_BOARD_SetConfig(board_handle, &boardConfig);
+ PKH_SPAN_Open(board_handle, 0, NULL, &span_handle);
+ PKH_SPAN_GetConfig(span_handle, &globals.e1_span_config);
+ PKH_SPAN_Close(span_handle);
+ boardConfig.specific.DigitalGateway.interfaceType = PKH_BOARD_INTERFACE_TYPE_T1;
+ PKH_BOARD_SetConfig(board_handle, &boardConfig);
+ PKH_BOARD_Close(board_handle);
+ }
+ ok++;
+
+ }
+
+ if (!ok) {
+ return ZAP_FAIL;
+ }
+
+ pika_interface.name = "pika";
+ pika_interface.configure = pika_configure;
+ pika_interface.configure_span = pika_configure_span;
+ pika_interface.open = pika_open;
+ pika_interface.close = pika_close;
+ pika_interface.wait = pika_wait;
+ pika_interface.read = pika_read;
+ pika_interface.write = pika_write;
+ pika_interface.command = pika_command;
+ pika_interface.poll_event = pika_poll_event;
+ pika_interface.next_event = pika_next_event;
+ pika_interface.channel_destroy = pika_channel_destroy;
+ pika_interface.span_destroy = pika_span_destroy;
+ pika_interface.get_alarms = pika_get_alarms;
+ *zio = &pika_interface;
+
+
+ zap_log(ZAP_LOG_INFO, "Dumping Default configs:\n");
+ zap_log(ZAP_LOG_INFO, "rx-gain => %0.2f\n", (float)globals.record_config.gain);
+ zap_log(ZAP_LOG_INFO, "rx-agc-enabled => %s\n", globals.record_config.AGC.enabled ? "true" : "false");
+ zap_log(ZAP_LOG_INFO, "rx-agc-targetPower => %0.2f\n", (float)globals.record_config.AGC.targetPower);
+ zap_log(ZAP_LOG_INFO, "rx-agc-minGain => %0.2f\n", (float)globals.record_config.AGC.minGain);
+ zap_log(ZAP_LOG_INFO, "rx-agc-maxGain => %0.2f\n", (float)globals.record_config.AGC.maxGain);
+ zap_log(ZAP_LOG_INFO, "rx-agc-attackRate => %d\n", (int)globals.record_config.AGC.attackRate);
+ zap_log(ZAP_LOG_INFO, "rx-agc-decayRate => %d\n", (int)globals.record_config.AGC.decayRate);
+ zap_log(ZAP_LOG_INFO, "rx-agc-speechThreshold => %0.2f\n", (float)globals.record_config.AGC.speechThreshold);
+ zap_log(ZAP_LOG_INFO, "rx-vad-enabled => %s\n", globals.record_config.VAD.enabled ? "true" : "false");
+ zap_log(ZAP_LOG_INFO, "rx-vad-activationThreshold => %0.2f\n", (float)globals.record_config.VAD.activationThreshold);
+ zap_log(ZAP_LOG_INFO, "rx-vad-activationDebounceTime => %d\n", (int)globals.record_config.VAD.activationDebounceTime);
+ zap_log(ZAP_LOG_INFO, "rx-vad-deactivationThreshold => %0.2f\n", (float)globals.record_config.VAD.deactivationThreshold);
+ zap_log(ZAP_LOG_INFO, "rx-vad-deactivationDebounceTime => %d\n", (int)globals.record_config.VAD.deactivationDebounceTime);
+ zap_log(ZAP_LOG_INFO, "rx-vad-preSpeechBufferSize => %d\n", (int)globals.record_config.VAD.preSpeechBufferSize);
+ zap_log(ZAP_LOG_INFO, "tx-gain => %0.2f\n", (float)globals.play_config.gain);
+ zap_log(ZAP_LOG_INFO, "tx-agc-enabled => %s\n", globals.play_config.AGC.enabled ? "true" : "false");
+ zap_log(ZAP_LOG_INFO, "tx-agc-targetPower => %0.2f\n", (float)globals.play_config.AGC.targetPower);
+ zap_log(ZAP_LOG_INFO, "tx-agc-minGain => %0.2f\n", (float)globals.play_config.AGC.minGain);
+ zap_log(ZAP_LOG_INFO, "tx-agc-maxGain => %0.2f\n", (float)globals.play_config.AGC.maxGain);
+ zap_log(ZAP_LOG_INFO, "tx-agc-attackRate => %d\n", (int)globals.play_config.AGC.attackRate);
+ zap_log(ZAP_LOG_INFO, "tx-agc-decayRate => %d\n", (int)globals.play_config.AGC.decayRate);
+ zap_log(ZAP_LOG_INFO, "tx-agc-speechThreshold => %0.2f\n", (float)globals.play_config.AGC.speechThreshold);
+ zap_log(ZAP_LOG_INFO, "ec-doubleTalkerThreshold => %0.2f\n", (float)globals.ec_config.doubleTalkerThreshold);
+ zap_log(ZAP_LOG_INFO, "ec-speechPresentThreshold => %0.2f\n", (float)globals.ec_config.speechPresentThreshold);
+ zap_log(ZAP_LOG_INFO, "ec-echoSuppressionThreshold => %0.2f\n", (float)globals.ec_config.echoSuppressionThreshold);
+ zap_log(ZAP_LOG_INFO, "ec-echoSuppressionEnabled => %s\n", globals.ec_config.echoSuppressionEnabled ? "true" : "false");
+ zap_log(ZAP_LOG_INFO, "ec-comfortNoiseEnabled => %s\n", globals.ec_config.comfortNoiseEnabled ? "true" : "false");
+ zap_log(ZAP_LOG_INFO, "ec-adaptationModeEnabled => %s\n", globals.ec_config.adaptationModeEnabled ? "true" : "false");
+
+
+
+ memset(&m, 0, sizeof(m));
+ //m.apiMask = 0xffffffff;
+ //PKH_LOG_SetMasks(&m);
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Unloads Pika IO module
+ * \return Success
+ */
+static ZIO_IO_UNLOAD_FUNCTION(pika_destroy)
+{
+ uint32_t x;
+ PK_STATUS status;
+ PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
+
+ for (x = 0; x < MAX_NUMBER_OF_TRUNKS; x++) {
+ if (globals.open_boards[x]) {
+ zap_log(ZAP_LOG_INFO, "Closing board %u\n", x);
+ PKH_BOARD_Close(globals.open_boards[x]);
+ }
+ }
+
+ // The system can now be closed.
+ if ((status = PKH_SYSTEM_Close(globals.system_handle)) != PK_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error: PKH_SYSTEM_Close failed(%s)!\n",
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+ } else {
+ zap_log(ZAP_LOG_INFO, "Closing system handle\n");
+ }
+
+ hashtable_destroy(globals.profile_hash);
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Pika IO module definition
+ */
+EX_DECLARE_DATA zap_module_t zap_module = {
+ "pika",
+ pika_init,
+ pika_destroy,
+};
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/zap_pika.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/zap_pika.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/zap_pika.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#ifndef ZAP_PIKA_H
+#define ZAP_PIKA_H
+#include "openzap.h"
+#include "pikahmpapi.h"
+
+
+
+#define PIKA_STR2ENUM_P(_FUNC1, _FUNC2, _TYPE) _TYPE _FUNC1 (const char *name); const char * _FUNC2 (_TYPE type);
+#define PIKA_STR2ENUM(_FUNC1, _FUNC2, _TYPE, _STRINGS, _MAX) \
+ _TYPE _FUNC1 (const char *name) \
+ { \
+ int i; \
+ _TYPE t = _MAX ; \
+ \
+ for (i = 0; i < _MAX ; i++) { \
+ if (!strcasecmp(name, _STRINGS[i])) { \
+ t = (_TYPE) i; \
+ break; \
+ } \
+ } \
+ \
+ return t; \
+ } \
+ const char * _FUNC2 (_TYPE type) \
+ { \
+ if (type > _MAX) { \
+ type = _MAX; \
+ } \
+ return _STRINGS[(int)type]; \
+ }
+
+
+typedef enum {
+ PIKA_SPAN_FRAMING_T1_D4,
+ PIKA_SPAN_FRAMING_T1_ESF,
+ PIKA_SPAN_FRAMING_E1_BASIC,
+ PIKA_SPAN_FRAMING_E1_CRC4,
+ PIKA_SPAN_INVALID
+} PIKA_TSpanFraming;
+#define PIKA_SPAN_STRINGS "T1_D4", "T1_ESF", "E1_BASIC", "E1_CRC4"
+PIKA_STR2ENUM_P(pika_str2span, pika_span2str, PIKA_TSpanFraming)
+
+typedef enum {
+ PIKA_SPAN_ENCODING_T1_AMI_ZS_NONE,
+ PIKA_SPAN_ENCODING_T1_AMI_ZS_GTE,
+ PIKA_SPAN_ENCODING_T1_AMI_ZS_BELL,
+ PIKA_SPAN_ENCODING_T1_AMI_ZS_JAM8,
+ PIKA_SPAN_ENCODING_T1_B8ZS,
+ PIKA_SPAN_ENCODING_E1_AMI,
+ PIKA_SPAN_ENCODING_E1_HDB3,
+ PIKA_SPAN_ENCODING_INVALID
+} PIKA_TSpanEncoding;
+#define PIKA_SPAN_ENCODING_STRINGS "T1_AMI_ZS_NONE", "T1_AMI_ZS_GTE", "T1_AMI_ZS_BELL", "T1_AMI_ZS_JAM8", "T1_B8ZS", "E1_AMI", "E1_HDB3"
+PIKA_STR2ENUM_P(pika_str2span_encoding, pika_span_encoding2str, PIKA_TSpanEncoding)
+
+typedef enum {
+ PIKA_SPAN_LOOP_LENGTH_SHORT_HAUL,
+ PIKA_SPAN_LOOP_LENGTH_LONG_HAUL,
+ PIKA_SPAN_LOOP_INVALID
+} PIKA_TSpanLoopLength;
+#define PIKA_LL_STRINGS "SHORT_HAUL", "LONG_HAUL"
+PIKA_STR2ENUM_P(pika_str2loop_length, pika_loop_length2str, PIKA_TSpanLoopLength)
+
+typedef enum {
+ PIKA_SPAN_LBO_T1_LONG_0_DB,
+ PIKA_SPAN_LBO_T1_LONG_7_DB,
+ PIKA_SPAN_LBO_T1_LONG_15_DB,
+ PIKA_SPAN_LBO_T1_LONG_22_DB,
+ PIKA_SPAN_LBO_T1_SHORT_133_FT,
+ PIKA_SPAN_LBO_T1_SHORT_266_FT,
+ PIKA_SPAN_LBO_T1_SHORT_399_FT,
+ PIKA_SPAN_LBO_T1_SHORT_533_FT,
+ PIKA_SPAN_LBO_T1_SHORT_655_FT,
+ PIKA_SPAN_LBO_E1_WAVEFORM_120_OHM,
+ PIKA_SPAN_LBO_INVALID
+} PIKA_TSpanBuildOut;
+#define PIKA_LBO_STRINGS "T1_LONG_0_DB", "T1_LONG_7_DB", "T1_LONG_15_DB", "T1_LONG_22_DB", "T1_SHORT_133_FT", "T1_SHORT_266_FT", "T1_SHORT_399_FT", "T1_SHORT_533_FT", "T1_SHORT_655_FT", "E1_WAVEFORM_120_OHM"
+PIKA_STR2ENUM_P(pika_str2lbo, pika_lbo2str, PIKA_TSpanBuildOut)
+
+typedef enum {
+ PIKA_SPAN_COMPAND_MODE_MU_LAW = 1,
+ PIKA_SPAN_COMPAND_MODE_A_LAW,
+ PIKA_SPAN_COMPAND_MODE_INVALID
+} PIKA_TSpanCompandMode;
+#define PIKA_SPAN_COMPAND_MODE_STRINGS "MU_LAW", "A_LAW"
+PIKA_STR2ENUM_P(pika_str2compand_mode, pika_compand_mode2str, PIKA_TSpanCompandMode)
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_r2/ozmod_r2.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_r2/ozmod_r2.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_r2/ozmod_r2.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1364 @@
+/*
+ * Copyright (c) 2009, Moises Silva <moy@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.
+ */
+
+#include <stdio.h>
+#include <pthread.h>
+#include <openr2.h>
+#include "openzap.h"
+
+/* debug thread count for r2 legs */
+static zap_mutex_t* g_thread_count_mutex;
+static int32_t g_thread_count = 0;
+
+/* when the users kills a span we clear this flag to kill the signaling thread */
+/* FIXME: what about the calls that are already up-and-running? */
+typedef enum {
+ ZAP_R2_RUNNING = (1 << 0),
+} zap_r2_flag_t;
+
+/* private call information stored in zchan->call_data void* ptr */
+#define R2CALL(zchan) ((zap_r2_call_t*)((zchan)->call_data))
+typedef struct zap_r2_call_t {
+ openr2_chan_t *r2chan;
+ int accepted:1;
+ int answer_pending:1;
+ int state_ack_pending:1;
+ int disconnect_rcvd:1;
+ int zap_started:1;
+ zap_channel_state_t chanstate;
+ zap_size_t dnis_index;
+ zap_size_t ani_index;
+ char name[10];
+} zap_r2_call_t;
+
+/* this is just used as place holder in the stack when configuring the span to avoid using bunch of locals */
+typedef struct oz_r2_conf_s {
+ /* openr2 types */
+ openr2_variant_t variant;
+ openr2_calling_party_category_t category;
+ openr2_log_level_t loglevel;
+
+ /* strings */
+ char *logdir;
+ char *advanced_protocol_file;
+
+ /* ints */
+ int32_t max_ani;
+ int32_t max_dnis;
+ int32_t mfback_timeout;
+ int32_t metering_pulse_timeout;
+
+ /* booleans */
+ int immediate_accept;
+ int skip_category;
+ int get_ani_first;
+ int call_files;
+ int double_answer;
+ int charge_calls;
+ int forced_release;
+ int allow_collect_calls;
+} oz_r2_conf_t;
+
+/* r2 configuration stored in span->signal_data */
+typedef struct zap_r2_data_s {
+ /* span flags */
+ zap_r2_flag_t flags;
+ /* openr2 handle for the R2 variant context */
+ openr2_context_t *r2context;
+ /* category to use when making calls */
+ openr2_calling_party_category_t category;
+ /* whether to use OR2_CALL_WITH_CHARGE or OR2_CALL_NO_CHARGE when accepting a call */
+ int charge_calls:1;
+ /* allow or reject collect calls */
+ int allow_collect_calls:1;
+ /* whether to use forced release when hanging up */
+ int forced_release:1;
+ /* whether accept the call when offered, or wait until the user decides to accept */
+ int accept_on_offer:1;
+} zap_r2_data_t;
+
+/* one element per span will be stored in g_mod_data_hash global var to keep track of them
+ and destroy them on module unload */
+typedef struct zap_r2_span_pvt_s {
+ openr2_context_t *r2context; /* r2 context allocated for this span */
+ zap_hash_t *r2calls; /* hash table of allocated call data per channel for this span */
+} zap_r2_span_pvt_t;
+
+/* span monitor thread */
+static void *zap_r2_run(zap_thread_t *me, void *obj);
+
+/* channel monitor thread */
+static void *zap_r2_channel_run(zap_thread_t *me, void *obj);
+
+/* hash of all the private span allocations
+ we need to keep track of them to destroy them when unloading the module
+ since openzap does not notify signaling modules when destroying a span
+ span -> zap_r2_mod_allocs_t */
+static zap_hash_t *g_mod_data_hash;
+
+/* IO interface for the command API */
+static zap_io_interface_t g_zap_r2_interface;
+
+static void oz_r2_clean_call(zap_r2_call_t *call)
+{
+ openr2_chan_t *r2chan = call->r2chan;
+ memset(call, 0, sizeof(*call));
+ call->r2chan = r2chan;
+}
+
+static void oz_r2_accept_call(zap_channel_t *zchan)
+{
+ openr2_chan_t *r2chan = R2CALL(zchan)->r2chan;
+ // FIXME: not always accept as no charge, let the user decide that
+ // also we should check the return code from openr2_chan_accept_call and handle error condition
+ // hanging up the call with protocol error as the reason, this openr2 API will fail only when there something
+ // wrong at the I/O layer or the library itself
+ openr2_chan_accept_call(r2chan, OR2_CALL_NO_CHARGE);
+ R2CALL(zchan)->accepted = 1;
+}
+
+static void oz_r2_answer_call(zap_channel_t *zchan)
+{
+ openr2_chan_t *r2chan = R2CALL(zchan)->r2chan;
+ // FIXME
+ // 1. check openr2_chan_answer_call return code
+ // 2. The openr2_chan_answer_call_with_mode should be used depending on user settings
+ // openr2_chan_answer_call_with_mode(r2chan, OR2_ANSWER_SIMPLE);
+ openr2_chan_answer_call(r2chan);
+ R2CALL(zchan)->answer_pending = 0;
+}
+
+static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
+{
+ zap_status_t status;
+ zap_mutex_lock(zchan->mutex);
+
+ /* the channel may be down but the thread not quite done */
+ zap_wait_for_flag_cleared(zchan, ZAP_CHANNEL_INTHREAD, 200);
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
+ zap_log(ZAP_LOG_ERROR, "%d:%d Yay! R2 outgoing call in channel that is already in thread.\n",
+ zchan->span_id, zchan->chan_id);
+ zap_mutex_unlock(zchan->mutex);
+ return ZAP_FAIL;
+ }
+
+ oz_r2_clean_call(zchan->call_data);
+ R2CALL(zchan)->chanstate = ZAP_CHANNEL_STATE_DOWN;
+ zap_channel_set_state(zchan, ZAP_CHANNEL_STATE_DIALING, 0);
+ zap_set_flag(zchan, ZAP_CHANNEL_OUTBOUND);
+ R2CALL(zchan)->zap_started = 1;
+ zap_mutex_unlock(zchan->mutex);
+
+ status = zap_thread_create_detached(zap_r2_channel_run, zchan);
+ if (status == ZAP_FAIL) {
+ zap_log(ZAP_LOG_ERROR, "%d:%d Cannot handle request to start call in channel, failed to create thread!\n",
+ zchan->span_id, zchan->chan_id);
+ zap_channel_done(zchan);
+ return ZAP_FAIL;
+ }
+
+ return ZAP_SUCCESS;
+}
+
+static zap_status_t zap_r2_start(zap_span_t *span)
+{
+ zap_r2_data_t *r2_data = span->signal_data;
+ zap_set_flag(r2_data, ZAP_R2_RUNNING);
+ return zap_thread_create_detached(zap_r2_run, span);
+}
+
+/* always called from the monitor thread */
+static void zap_r2_on_call_init(openr2_chan_t *r2chan)
+{
+ zap_channel_t *zchan = openr2_chan_get_client_data(r2chan);
+ zap_status_t status;
+ zap_log(ZAP_LOG_NOTICE, "Received request to start call on chan %d\n", openr2_chan_get_number(r2chan));
+
+ zap_mutex_lock(zchan->mutex);
+
+ if (zchan->state != ZAP_CHANNEL_STATE_DOWN) {
+ zap_log(ZAP_LOG_ERROR, "Cannot handle request to start call in channel %d, invalid state (%d)\n",
+ openr2_chan_get_number(r2chan), zchan->state);
+ zap_mutex_unlock(zchan->mutex);
+ return;
+ }
+
+ /* the channel may be down but the thread not quite done */
+ zap_wait_for_flag_cleared(zchan, ZAP_CHANNEL_INTHREAD, 200);
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
+ zap_log(ZAP_LOG_ERROR, "Cannot handle request to start call in channel %d, already in thread!\n",
+ openr2_chan_get_number(r2chan));
+ zap_mutex_unlock(zchan->mutex);
+ return;
+ }
+ oz_r2_clean_call(zchan->call_data);
+ R2CALL(zchan)->chanstate = ZAP_CHANNEL_STATE_DOWN;
+ zap_channel_set_state(zchan, ZAP_CHANNEL_STATE_COLLECT, 0);
+ zap_mutex_unlock(zchan->mutex);
+
+ status = zap_thread_create_detached(zap_r2_channel_run, zchan);
+ if (status == ZAP_FAIL) {
+ zap_log(ZAP_LOG_ERROR, "Cannot handle request to start call in channel %d, failed to create thread!\n",
+ openr2_chan_get_number(r2chan));
+ }
+}
+
+/* only called for incoming calls when the ANI, DNIS etc is complete and the user has to decide either to accept or reject the call */
+static void zap_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, openr2_calling_party_category_t category)
+{
+ zap_sigmsg_t sigev;
+ zap_channel_t *zchan = openr2_chan_get_client_data(r2chan);
+
+ zap_log(ZAP_LOG_NOTICE, "Call offered on chan %d, ANI = %s, DNIS = %s, Category = %s\n", openr2_chan_get_number(r2chan),
+ ani, dnis, openr2_proto_get_category_string(category));
+
+ /* notify the user about the new call */
+ memset(&sigev, 0, sizeof(sigev));
+ sigev.chan_id = zchan->chan_id;
+ sigev.span_id = zchan->span_id;
+ sigev.channel = zchan;
+ sigev.event_id = ZAP_SIGEVENT_START;
+
+ if (zap_span_send_signal(zchan->span, &sigev) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_NOTICE, "Failed to handle call offered on chan %d\n", openr2_chan_get_number(r2chan));
+ openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_CANCEL);
+ return;
+ }
+ zap_channel_use(zchan);
+ R2CALL(zchan)->zap_started = 1;
+}
+
+static void zap_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
+{
+ zap_channel_t *zchan = openr2_chan_get_client_data(r2chan);
+ zap_log(ZAP_LOG_NOTICE, "Call accepted on chan %d\n", openr2_chan_get_number(r2chan));
+ /* at this point the MF signaling has ended and there is no point on keep reading */
+ openr2_chan_disable_read(r2chan);
+ if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
+ R2CALL(zchan)->state_ack_pending = 1;
+ if (R2CALL(zchan)->answer_pending) {
+ zap_log(ZAP_LOG_DEBUG, "Answer was pending on chan %d, answering now.\n", openr2_chan_get_number(r2chan));
+ oz_r2_answer_call(zchan);
+ return;
+ }
+ } else {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS);
+ }
+}
+
+static void zap_r2_on_call_answered(openr2_chan_t *r2chan)
+{
+ zap_channel_t *zchan = openr2_chan_get_client_data(r2chan);
+ zap_log(ZAP_LOG_NOTICE, "Call answered on chan %d\n", openr2_chan_get_number(r2chan));
+ /* notify the upper layer of progress in the outbound call */
+ if (OR2_DIR_FORWARD == openr2_chan_get_direction(r2chan)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
+ }
+}
+
+/* may be called in the signaling or media thread depending on whether the hangup is product of MF or CAS signaling */
+static void zap_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disconnect_cause_t cause)
+{
+ zap_sigmsg_t sigev;
+ zap_r2_data_t *r2data;
+ zap_channel_t *zchan = openr2_chan_get_client_data(r2chan);
+ zap_log(ZAP_LOG_NOTICE, "Call disconnected on chan %d\n", openr2_chan_get_number(r2chan));
+
+ zap_log(ZAP_LOG_DEBUG, "Got openr2 disconnection, clearing call on channel %d\n", zchan->physical_chan_id);
+
+ R2CALL(zchan)->disconnect_rcvd = 1;
+
+ /* acknowledge the hangup, cause will be ignored. From here to -> HANGUP once the openzap side hangs up as well */
+ openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
+
+ /* if the call has not been started yet we must go to HANGUP right here */
+ if (!R2CALL(zchan)->zap_started) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ return;
+ }
+
+ /* FIXME: use the cause received from openr2 and map it to zap cause */
+ zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_CLEARING;
+
+ /* notify the user of the call terminating */
+ memset(&sigev, 0, sizeof(sigev));
+ sigev.chan_id = zchan->chan_id;
+ sigev.span_id = zchan->span_id;
+ sigev.channel = zchan;
+ sigev.event_id = ZAP_SIGEVENT_STOP;
+ r2data = zchan->span->signal_data;
+
+ zap_span_send_signal(zchan->span, &sigev);
+}
+
+static void zap_r2_on_call_end(openr2_chan_t *r2chan)
+{
+ zap_channel_t *zchan = openr2_chan_get_client_data(r2chan);
+ zap_log(ZAP_LOG_NOTICE, "Call finished on chan %d\n", openr2_chan_get_number(r2chan));
+ /* this means the openzap side disconnected the call, therefore we must move to DOWN here */
+ if (!R2CALL(zchan)->disconnect_rcvd) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ return;
+ }
+}
+
+static void zap_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen)
+{
+ zap_log(ZAP_LOG_NOTICE, "Call read data on chan %d\n", openr2_chan_get_number(r2chan));
+}
+
+static void zap_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
+{
+ zap_log(ZAP_LOG_NOTICE, "Alarm on chan %d (%d)\n", openr2_chan_get_number(r2chan), alarm);
+}
+
+static void zap_r2_on_os_error(openr2_chan_t *r2chan, int errorcode)
+{
+ zap_log(ZAP_LOG_ERROR, "OS error on chan %d: %s\n", openr2_chan_get_number(r2chan), strerror(errorcode));
+}
+
+static void zap_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_error_t reason)
+{
+ zap_sigmsg_t sigev;
+ zap_r2_data_t *r2data;
+ zap_channel_t *zchan = openr2_chan_get_client_data(r2chan);
+
+ zap_log(ZAP_LOG_ERROR, "Protocol error on chan %d\n", openr2_chan_get_number(r2chan));
+
+ R2CALL(zchan)->disconnect_rcvd = 1;
+
+ if (!R2CALL(zchan)->zap_started) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ return;
+ }
+
+ zchan->caller_data.hangup_cause = ZAP_CAUSE_PROTOCOL_ERROR;
+
+ /* notify the user of the call terminating */
+ memset(&sigev, 0, sizeof(sigev));
+ sigev.chan_id = zchan->chan_id;
+ sigev.span_id = zchan->span_id;
+ sigev.channel = zchan;
+ sigev.event_id = ZAP_SIGEVENT_STOP;
+ r2data = zchan->span->signal_data;
+
+ zap_span_send_signal(zchan->span, &sigev);
+}
+
+static void zap_r2_on_line_blocked(openr2_chan_t *r2chan)
+{
+ zap_log(ZAP_LOG_NOTICE, "Far end blocked on chan %d\n", openr2_chan_get_number(r2chan));
+}
+
+static void zap_r2_on_line_idle(openr2_chan_t *r2chan)
+{
+ zap_log(ZAP_LOG_NOTICE, "Far end unblocked on chan %d\n", openr2_chan_get_number(r2chan));
+}
+
+static void zap_r2_write_log(openr2_log_level_t level, const char *message)
+{
+ switch (level) {
+ case OR2_LOG_NOTICE:
+ zap_log(ZAP_LOG_NOTICE, "%s", message);
+ break;
+ case OR2_LOG_WARNING:
+ zap_log(ZAP_LOG_WARNING, "%s", message);
+ break;
+ case OR2_LOG_ERROR:
+ zap_log(ZAP_LOG_ERROR, "%s", message);
+ break;
+ case OR2_LOG_STACK_TRACE:
+ case OR2_LOG_MF_TRACE:
+ case OR2_LOG_CAS_TRACE:
+ case OR2_LOG_DEBUG:
+ case OR2_LOG_EX_DEBUG:
+ zap_log(ZAP_LOG_DEBUG, "%s", message);
+ break;
+ default:
+ zap_log(ZAP_LOG_WARNING, "We should handle logging level %d here.\n", level);
+ zap_log(ZAP_LOG_DEBUG, "%s", message);
+ break;
+ }
+}
+
+static void zap_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap)
+{
+#define CONTEXT_TAG "Context -"
+ char logmsg[256];
+ char completemsg[sizeof(logmsg) + sizeof(CONTEXT_TAG) - 1];
+ vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
+ snprintf(completemsg, sizeof(completemsg), CONTEXT_TAG "%s", logmsg);
+ zap_r2_write_log(level, completemsg);
+#undef CONTEXT_TAG
+}
+
+static void zap_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap)
+{
+#define CHAN_TAG "Chan "
+ char logmsg[256];
+ char completemsg[sizeof(logmsg) + sizeof(CHAN_TAG) - 1];
+ vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
+ snprintf(completemsg, sizeof(completemsg), CHAN_TAG "%d: %s", openr2_chan_get_number(r2chan), logmsg);
+ zap_r2_write_log(level, completemsg);
+#undef CHAN_TAG
+}
+
+static int zap_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit)
+{
+ zap_sigmsg_t sigev;
+ zap_r2_data_t *r2data;
+ zap_channel_t *zchan = openr2_chan_get_client_data(r2chan);
+ zap_size_t collected_len = R2CALL(zchan)->dnis_index;
+
+ zap_log(ZAP_LOG_DEBUG, "DNIS digit %d received chan %d\n", digit, openr2_chan_get_number(r2chan));
+
+ /* save the digit we just received */
+ zchan->caller_data.dnis.digits[collected_len] = digit;
+ collected_len++;
+ zchan->caller_data.dnis.digits[collected_len] = '\0';
+ R2CALL(zchan)->dnis_index = collected_len;
+
+ /* notify the user about the new digit and check if we should stop requesting more DNIS */
+ memset(&sigev, 0, sizeof(sigev));
+ sigev.chan_id = zchan->chan_id;
+ sigev.span_id = zchan->span_id;
+ sigev.channel = zchan;
+ sigev.event_id = ZAP_SIGEVENT_COLLECTED_DIGIT;
+ r2data = zchan->span->signal_data;
+ if (zap_span_send_signal(zchan->span, &sigev) == ZAP_BREAK) {
+ zap_log(ZAP_LOG_NOTICE, "Requested to stop getting DNIS. Current DNIS = %s on chan %d\n", zchan->caller_data.dnis.digits, openr2_chan_get_number(r2chan));
+ return OR2_STOP_DNIS_REQUEST;
+ }
+
+ /* the only other reason to stop requesting DNIS is that there is no more room to save it */
+ if (collected_len == (sizeof(zchan->caller_data.dnis.digits) - 1)) {
+ zap_log(ZAP_LOG_NOTICE, "No more room for DNIS. Current DNIS = %s on chan %d\n", zchan->caller_data.dnis.digits, openr2_chan_get_number(r2chan));
+ return OR2_STOP_DNIS_REQUEST;
+ }
+
+ return OR2_CONTINUE_DNIS_REQUEST;
+}
+
+static void zap_r2_on_ani_digit_received(openr2_chan_t *r2chan, char digit)
+{
+ zap_channel_t *zchan = openr2_chan_get_client_data(r2chan);
+ zap_size_t collected_len = R2CALL(zchan)->ani_index;
+
+ /* check if we should drop ANI */
+ if (collected_len == (sizeof(zchan->caller_data.ani.digits) - 1)) {
+ zap_log(ZAP_LOG_NOTICE, "No more room for ANI %c on chan %d, digit dropped.\n", digit, openr2_chan_get_number(r2chan));
+ return;
+ }
+ zap_log(ZAP_LOG_DEBUG, "ANI digit %c received chan %d\n", digit, openr2_chan_get_number(r2chan));
+
+ /* save the digit we just received */
+ zchan->caller_data.ani.digits[collected_len++] = digit;
+ zchan->caller_data.ani.digits[collected_len] = '\0';
+}
+
+static openr2_event_interface_t zap_r2_event_iface = {
+ .on_call_init = zap_r2_on_call_init,
+ .on_call_offered = zap_r2_on_call_offered,
+ .on_call_accepted = zap_r2_on_call_accepted,
+ .on_call_answered = zap_r2_on_call_answered,
+ .on_call_disconnect = zap_r2_on_call_disconnect,
+ .on_call_end = zap_r2_on_call_end,
+ .on_call_read = zap_r2_on_call_read,
+ .on_hardware_alarm = zap_r2_on_hardware_alarm,
+ .on_os_error = zap_r2_on_os_error,
+ .on_protocol_error = zap_r2_on_protocol_error,
+ .on_line_blocked = zap_r2_on_line_blocked,
+ .on_line_idle = zap_r2_on_line_idle,
+ /* cast seems to be needed to get rid of the annoying warning regarding format attribute */
+ .on_context_log = (openr2_handle_context_logging_func)zap_r2_on_context_log,
+ .on_dnis_digit_received = zap_r2_on_dnis_digit_received,
+ .on_ani_digit_received = zap_r2_on_ani_digit_received,
+ /* so far we do nothing with billing pulses */
+ .on_billing_pulse_received = NULL
+};
+
+static int zap_r2_io_set_cas(openr2_chan_t *r2chan, int cas)
+{
+ zap_channel_t *zap_chan = openr2_chan_get_fd(r2chan);
+ zap_status_t status = zap_channel_command(zap_chan, ZAP_COMMAND_SET_CAS_BITS, &cas);
+ if (ZAP_FAIL == status) {
+ return -1;
+ }
+ return 0;
+}
+
+static int zap_r2_io_get_cas(openr2_chan_t *r2chan, int *cas)
+{
+ zap_channel_t *zap_chan = openr2_chan_get_fd(r2chan);
+ zap_status_t status = zap_channel_command(zap_chan, ZAP_COMMAND_GET_CAS_BITS, cas);
+ if (ZAP_FAIL == status) {
+ return -1;
+ }
+ return 0;
+}
+
+static int zap_r2_io_flush_write_buffers(openr2_chan_t *r2chan)
+{
+ zap_channel_t *zap_chan = openr2_chan_get_fd(r2chan);
+ zap_status_t status = zap_channel_command(zap_chan, ZAP_COMMAND_FLUSH_TX_BUFFERS, NULL);
+ if (ZAP_FAIL == status) {
+ return -1;
+ }
+ return 0;
+}
+
+static int zap_r2_io_write(openr2_chan_t *r2chan, const void *buf, int size)
+{
+ zap_channel_t *zap_chan = openr2_chan_get_fd(r2chan);
+ zap_size_t outsize = size;
+ zap_status_t status = zap_channel_write(zap_chan, (void *)buf, size, &outsize);
+ if (ZAP_FAIL == status) {
+ return -1;
+ }
+ return outsize;
+}
+
+static int zap_r2_io_read(openr2_chan_t *r2chan, const void *buf, int size)
+{
+ zap_channel_t *zap_chan = openr2_chan_get_fd(r2chan);
+ zap_size_t outsize = size;
+ zap_status_t status = zap_channel_read(zap_chan, (void *)buf, &outsize);
+ if (ZAP_FAIL == status) {
+ return -1;
+ }
+ return outsize;
+}
+
+static int zap_r2_io_wait(openr2_chan_t *r2chan, int *flags, int block)
+{
+ zap_status_t status;
+ zap_wait_flag_t zapflags = 0;
+
+ zap_channel_t *zap_chan = openr2_chan_get_fd(r2chan);
+ int32_t timeout = block ? -1 : 0;
+
+ if (*flags & OR2_IO_READ) {
+ zapflags |= ZAP_READ;
+ }
+ if (*flags & OR2_IO_WRITE) {
+ zapflags |= ZAP_WRITE;
+ }
+ if (*flags & OR2_IO_OOB_EVENT) {
+ zapflags |= ZAP_EVENTS;
+ }
+
+ status = zap_channel_wait(zap_chan, &zapflags, timeout);
+
+ if (ZAP_SUCCESS != status) {
+ return -1;
+ }
+
+ *flags = 0;
+ if (zapflags & ZAP_READ) {
+ *flags |= OR2_IO_READ;
+ }
+ if (zapflags & ZAP_WRITE) {
+ *flags |= OR2_IO_WRITE;
+ }
+ if (zapflags & ZAP_EVENTS) {
+ *flags |= OR2_IO_OOB_EVENT;
+ }
+
+ return 0;
+}
+
+/* The following openr2 hooks never get called, read on for reasoning ... */
+/* since openzap takes care of opening the file descriptor and using openr2_chan_new_from_fd, openr2 should never call this hook */
+static openr2_io_fd_t zap_r2_io_open(openr2_context_t *r2context, int channo)
+{
+ zap_log(ZAP_LOG_ERROR, "I should not be called (I/O open)!!\n");
+ return NULL;
+}
+
+/* since openzap takes care of closing the file descriptor and uses openr2_chan_new_from_fd, openr2 should never call this hook */
+static int zap_r2_io_close(openr2_chan_t *r2chan)
+{
+ zap_log(ZAP_LOG_ERROR, "I should not be called (I/O close)!!\n");
+ return 0;
+}
+
+/* since openzap takes care of opening the file descriptor and using openr2_chan_new_from_fd, openr2 should never call this hook */
+static int zap_r2_io_setup(openr2_chan_t *r2chan)
+{
+ zap_log(ZAP_LOG_ERROR, "I should not be called (I/O Setup)!!\n");
+ return 0;
+}
+
+/* since the signaling thread calls openr2_chan_process_cas_signaling directly, openr2 should never call this hook */
+static int zap_r2_io_get_oob_event(openr2_chan_t *r2chan, openr2_oob_event_t *event)
+{
+ *event = 0;
+ zap_log(ZAP_LOG_ERROR, "I should not be called (I/O get oob event)!!\n");
+ return 0;
+}
+
+static openr2_io_interface_t zap_r2_io_iface = {
+ .open = zap_r2_io_open, /* never called */
+ .close = zap_r2_io_close, /* never called */
+ .set_cas = zap_r2_io_set_cas,
+ .get_cas = zap_r2_io_get_cas,
+ .flush_write_buffers = zap_r2_io_flush_write_buffers,
+ .write = zap_r2_io_write,
+ .read = zap_r2_io_read,
+ .setup = zap_r2_io_setup, /* never called */
+ .wait = zap_r2_io_wait,
+ .get_oob_event = zap_r2_io_get_oob_event /* never called */
+};
+
+static ZIO_SIG_CONFIGURE_FUNCTION(zap_r2_configure_span)
+ //zap_status_t (zap_span_t *span, zio_signal_cb_t sig_cb, va_list ap)
+{
+ int i = 0;
+ int conf_failure = 0;
+ char *var = NULL;
+ char *val = NULL;
+ zap_r2_data_t *r2data = NULL;
+ zap_r2_span_pvt_t *spanpvt = NULL;
+ zap_r2_call_t *r2call = NULL;
+ openr2_chan_t *r2chan = NULL;
+
+ assert(sig_cb != NULL);
+
+ oz_r2_conf_t r2conf =
+ {
+ .variant = OR2_VAR_ITU,
+ .category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER,
+ .loglevel = OR2_LOG_ERROR | OR2_LOG_WARNING,
+ .max_ani = 10,
+ .max_dnis = 4,
+ .mfback_timeout = -1,
+ .metering_pulse_timeout = -1,
+ .allow_collect_calls = -1,
+ .immediate_accept = -1,
+ .skip_category = -1,
+ .forced_release = -1,
+ .charge_calls = -1,
+ .get_ani_first = -1,
+ .call_files = -1,
+ .logdir = NULL,
+ .advanced_protocol_file = NULL
+ };
+
+
+ if (span->signal_type) {
+ snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
+ return ZAP_FAIL;
+ }
+
+ while ((var = va_arg(ap, char *))) {
+ zap_log(ZAP_LOG_DEBUG, "Reading R2 parameter %s for span %d\n", var, span->span_id);
+ if (!strcasecmp(var, "variant")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ if (zap_strlen_zero_buf(val)) {
+ zap_log(ZAP_LOG_NOTICE, "Ignoring empty R2 variant parameter\n");
+ continue;
+ }
+ r2conf.variant = openr2_proto_get_variant(val);
+ if (r2conf.variant == OR2_VAR_UNKNOWN) {
+ zap_log(ZAP_LOG_ERROR, "Unknown R2 variant %s\n", val);
+ conf_failure = 1;
+ break;
+ }
+ zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d for variant %s\n", span->span_id, val);
+ } else if (!strcasecmp(var, "category")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ if (zap_strlen_zero_buf(val)) {
+ zap_log(ZAP_LOG_NOTICE, "Ignoring empty R2 category parameter\n");
+ continue;
+ }
+ r2conf.category = openr2_proto_get_category(val);
+ if (r2conf.category == OR2_CALLING_PARTY_CATEGORY_UNKNOWN) {
+ zap_log(ZAP_LOG_ERROR, "Unknown R2 caller category %s\n", val);
+ conf_failure = 1;
+ break;
+ }
+ zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with default category %s\n", span->span_id, val);
+ } else if (!strcasecmp(var, "logdir")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ if (zap_strlen_zero_buf(val)) {
+ zap_log(ZAP_LOG_NOTICE, "Ignoring empty R2 logdir parameter\n");
+ continue;
+ }
+ r2conf.logdir = val;
+ zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with logdir %s\n", span->span_id, val);
+ } else if (!strcasecmp(var, "logging")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ if (zap_strlen_zero_buf(val)) {
+ zap_log(ZAP_LOG_NOTICE, "Ignoring empty R2 logging parameter\n");
+ continue;
+ }
+ openr2_log_level_t tmplevel;
+ char *clevel;
+ char *logval = malloc(strlen(val)+1); /* alloca man page scared me, so better to use good ol' malloc */
+ if (!logval) {
+ zap_log(ZAP_LOG_WARNING, "Ignoring R2 logging parameter: '%s', failed to alloc memory\n", val);
+ continue;
+ }
+ strcpy(logval, val);
+ while (logval) {
+ clevel = strsep(&logval, ",");
+ if (-1 == (tmplevel = openr2_log_get_level(clevel))) {
+ zap_log(ZAP_LOG_WARNING, "Ignoring invalid R2 logging level: '%s'\n", clevel);
+ continue;
+ }
+ r2conf.loglevel |= tmplevel;
+ zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with loglevel %s\n", span->span_id, clevel);
+ }
+ free(logval);
+ } else if (!strcasecmp(var, "advanced_protocol_file")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ if (zap_strlen_zero_buf(val)) {
+ zap_log(ZAP_LOG_NOTICE, "Ignoring empty R2 advanced_protocol_file parameter\n");
+ continue;
+ }
+ r2conf.advanced_protocol_file = val;
+ zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with advanced protocol file %s\n", span->span_id, val);
+ } else if (!strcasecmp(var, "allow_collect_calls")) {
+ r2conf.allow_collect_calls = va_arg(ap, int);
+ zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with allow collect calls max ani = %d\n", span->span_id, r2conf.allow_collect_calls);
+ } else if (!strcasecmp(var, "double_answer")) {
+ r2conf.double_answer = va_arg(ap, int);
+ zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with double answer = %d\n", span->span_id, r2conf.double_answer);
+ } else if (!strcasecmp(var, "immediate_accept")) {
+ r2conf.immediate_accept = va_arg(ap, int);
+ zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with immediate accept = %d\n", span->span_id, r2conf.immediate_accept);
+ } else if (!strcasecmp(var, "skip_category")) {
+ r2conf.skip_category = va_arg(ap, int);
+ zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with skip category = %d\n", span->span_id, r2conf.skip_category);
+ } else if (!strcasecmp(var, "forced_release")) {
+ r2conf.forced_release = va_arg(ap, int);
+ zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with forced release = %d\n", span->span_id, r2conf.forced_release);
+ } else if (!strcasecmp(var, "charge_calls")) {
+ r2conf.charge_calls = va_arg(ap, int);
+ zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with charge calls = %d\n", span->span_id, r2conf.charge_calls);
+ } else if (!strcasecmp(var, "get_ani_first")) {
+ r2conf.get_ani_first = va_arg(ap, int);
+ zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with get ani first = %d\n", span->span_id, r2conf.get_ani_first);
+ } else if (!strcasecmp(var, "call_files")) {
+ r2conf.call_files = va_arg(ap, int);
+ zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with call files = %d\n", span->span_id, r2conf.call_files);
+ } else if (!strcasecmp(var, "mfback_timeout")) {
+ r2conf.mfback_timeout = va_arg(ap, int);
+ zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with MF backward timeout = %dms\n", span->span_id, r2conf.mfback_timeout);
+ } else if (!strcasecmp(var, "metering_pulse_timeout")) {
+ r2conf.metering_pulse_timeout = va_arg(ap, int);
+ zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with metering pulse timeout = %dms\n", span->span_id, r2conf.metering_pulse_timeout);
+ } else if (!strcasecmp(var, "max_ani")) {
+ r2conf.max_ani = va_arg(ap, int);
+ zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with max ani = %d\n", span->span_id, r2conf.max_ani);
+ } else if (!strcasecmp(var, "max_dnis")) {
+ r2conf.max_dnis = va_arg(ap, int);
+ zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with max dnis = %d\n", span->span_id, r2conf.max_dnis);
+ } else {
+ snprintf(span->last_error, sizeof(span->last_error), "Unknown R2 parameter [%s]", var);
+ return ZAP_FAIL;
+ }
+ }
+
+ if (conf_failure) {
+ snprintf(span->last_error, sizeof(span->last_error), "R2 configuration error");
+ return ZAP_FAIL;
+ }
+
+ r2data = malloc(sizeof(*r2data));
+ if (!r2data) {
+ snprintf(span->last_error, sizeof(span->last_error), "Failed to allocate R2 data.");
+ return ZAP_FAIL;
+ }
+ memset(r2data, 0, sizeof(*r2data));
+
+ spanpvt = malloc(sizeof(*spanpvt));
+ if (!spanpvt) {
+ snprintf(span->last_error, sizeof(span->last_error), "Failed to allocate private span data container.");
+ goto fail;
+ }
+ memset(spanpvt, 0, sizeof(*spanpvt));
+
+ r2data->r2context = openr2_context_new(r2conf.variant, &zap_r2_event_iface, r2conf.max_ani, r2conf.max_dnis);
+ if (!r2data->r2context) {
+ snprintf(span->last_error, sizeof(span->last_error), "Cannot create openr2 context for span.");
+ goto fail;
+ }
+ openr2_context_set_io_type(r2data->r2context, OR2_IO_CUSTOM, &zap_r2_io_iface);
+ openr2_context_set_log_level(r2data->r2context, r2conf.loglevel);
+ openr2_context_set_ani_first(r2data->r2context, r2conf.get_ani_first);
+ openr2_context_set_skip_category_request(r2data->r2context, r2conf.skip_category);
+ openr2_context_set_mf_back_timeout(r2data->r2context, r2conf.mfback_timeout);
+ openr2_context_set_metering_pulse_timeout(r2data->r2context, r2conf.metering_pulse_timeout);
+ openr2_context_set_double_answer(r2data->r2context, r2conf.double_answer);
+ openr2_context_set_immediate_accept(r2data->r2context, r2conf.immediate_accept);
+ if (r2conf.logdir) {
+ openr2_context_set_log_directory(r2data->r2context, r2conf.logdir);
+ }
+ if (r2conf.advanced_protocol_file) {
+ openr2_context_configure_from_advanced_file(r2data->r2context, r2conf.advanced_protocol_file);
+ }
+
+ spanpvt->r2calls = create_hashtable(ZAP_MAX_CHANNELS_SPAN, zap_hash_hashfromstring, zap_hash_equalkeys);
+ if (!spanpvt->r2calls) {
+ snprintf(span->last_error, sizeof(span->last_error), "Cannot create channel calls hash for span.");
+ goto fail;
+ }
+
+ for (i = 1; (i <= span->chan_count) && (i <= ZAP_MAX_CHANNELS_SPAN); i++) {
+ r2chan = openr2_chan_new_from_fd(r2data->r2context, span->channels[i], span->channels[i]->physical_chan_id);
+ if (!r2chan) {
+ snprintf(span->last_error, sizeof(span->last_error), "Cannot create all openr2 channels for span.");
+ goto fail;
+ }
+ if (r2conf.call_files) {
+ openr2_chan_enable_call_files(r2chan);
+ openr2_chan_set_log_level(r2chan, r2conf.loglevel);
+ }
+
+ r2call = malloc(sizeof(*r2call));
+ if (!r2call) {
+ snprintf(span->last_error, sizeof(span->last_error), "Cannot create all R2 call data structures for the span.");
+ zap_safe_free(r2chan);
+ goto fail;
+ }
+ memset(r2call, 0, sizeof(*r2call));
+ openr2_chan_set_logging_func(r2chan, zap_r2_on_chan_log);
+ openr2_chan_set_client_data(r2chan, span->channels[i]);
+ r2call->r2chan = r2chan;
+ span->channels[i]->call_data = r2call;
+ /* value and key are the same so just free one of them */
+ snprintf(r2call->name, sizeof(r2call->name), "chancall%d", i);
+ hashtable_insert(spanpvt->r2calls, (void *)r2call->name, r2call, HASHTABLE_FLAG_FREE_VALUE);
+
+ }
+ spanpvt->r2context = r2data->r2context;
+
+ /* just the value must be freed by the hash */
+ hashtable_insert(g_mod_data_hash, (void *)span->name, spanpvt, HASHTABLE_FLAG_FREE_VALUE);
+
+ span->start = zap_r2_start;
+ r2data->flags = 0;
+ span->signal_cb = sig_cb;
+ span->signal_type = ZAP_SIGTYPE_R2;
+ span->signal_data = r2data;
+ span->outgoing_call = r2_outgoing_call;
+
+ return ZAP_SUCCESS;
+
+fail:
+
+ if (r2data && r2data->r2context) {
+ openr2_context_delete(r2data->r2context);
+ }
+ if (spanpvt && spanpvt->r2calls) {
+ hashtable_destroy(spanpvt->r2calls);
+ }
+ zap_safe_free(r2data);
+ zap_safe_free(spanpvt);
+ return ZAP_FAIL;
+
+}
+
+static void *zap_r2_channel_run(zap_thread_t *me, void *obj)
+{
+ zap_channel_t *closed_chan;
+ uint32_t interval = 0;
+ zap_sigmsg_t sigev;
+ zap_channel_t *zchan = (zap_channel_t *)obj;
+ openr2_chan_t *r2chan = R2CALL(zchan)->r2chan;
+
+ zap_set_flag_locked(zchan, ZAP_CHANNEL_INTHREAD);
+
+ zap_mutex_lock(g_thread_count_mutex);
+ g_thread_count++;
+ zap_mutex_unlock(g_thread_count_mutex);
+
+ zap_log(ZAP_LOG_DEBUG, "R2 CHANNEL thread starting on %d in state %s.\n",
+ zchan->physical_chan_id,
+ zap_channel_state2str(zchan->state));
+
+ if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "OPEN ERROR [%s]\n", zchan->last_error);
+ goto endthread;
+ }
+
+ zap_channel_command(zchan, ZAP_COMMAND_GET_INTERVAL, &interval);
+
+ assert(interval != 0);
+ zap_log(ZAP_LOG_DEBUG, "Got %d interval for chan %d\n", interval, zchan->physical_chan_id);
+
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ /* FIXME: is this needed? */
+ memset(zchan->caller_data.dnis.digits, 0, sizeof(zchan->caller_data.collected));
+ memset(zchan->caller_data.ani.digits, 0, sizeof(zchan->caller_data.collected));
+ }
+
+ memset(&sigev, 0, sizeof(sigev));
+ sigev.chan_id = zchan->chan_id;
+ sigev.span_id = zchan->span_id;
+ sigev.channel = zchan;
+
+ while (zap_running()) {
+ int32_t read_enabled = openr2_chan_get_read_enabled(r2chan);
+ zap_wait_flag_t flags = read_enabled ? ( ZAP_READ | ZAP_WRITE ) : 0;
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_STATE_CHANGE) && (R2CALL(zchan)->chanstate != zchan->state)) {
+
+ zap_log(ZAP_LOG_DEBUG, "Executing state handler on %d:%d for %s\n", zchan->span_id, zchan->chan_id, zap_channel_state2str(zchan->state));
+ R2CALL(zchan)->chanstate = zchan->state;
+
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND) && !R2CALL(zchan)->accepted &&
+ (zchan->state == ZAP_CHANNEL_STATE_PROGRESS ||
+ zchan->state == ZAP_CHANNEL_STATE_PROGRESS_MEDIA ||
+ zchan->state == ZAP_CHANNEL_STATE_UP) ) {
+ /* if an accept ack will be required we should not acknowledge the state change just yet,
+ it will be done below after processing the MF signals, otherwise we have a race condition between openzap calling
+ openr2_chan_answer_call and openr2 accepting the call first, if openzap calls openr2_chan_answer_call before the accept cycle
+ completes, openr2 will fail to answer the call */
+ zap_log(ZAP_LOG_DEBUG, "State ack in chan %d:%d for state %s will have to wait a bit\n", zchan->span_id, zchan->chan_id, zap_channel_state2str(zchan->state));
+ } else if (zchan->state != ZAP_CHANNEL_STATE_DOWN){
+ /* the down state will be completed in zap_channel_done below */
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_STATE_CHANGE);
+ zap_channel_complete_state(zchan);
+ }
+
+ switch (zchan->state) {
+
+ /* starting an incoming call */
+ case ZAP_CHANNEL_STATE_COLLECT:
+ {
+ zap_log(ZAP_LOG_DEBUG, "COLLECT: Starting processing of incoming call in channel %d with interval %d\n", zchan->physical_chan_id, interval);
+ }
+ break;
+
+ /* starting an outgoing call */
+ case ZAP_CHANNEL_STATE_DIALING:
+ {
+ // FIXME: use user defined calling party
+ zap_channel_use(zchan);
+ zap_log(ZAP_LOG_DEBUG, "DIALING: Starting processing of outgoing call in channel %d with interval %d\n", zchan->physical_chan_id, interval);
+ if (openr2_chan_make_call(r2chan, zchan->caller_data.cid_num.digits, zchan->caller_data.ani.digits, OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER)) {
+ zap_log(ZAP_LOG_ERROR, "%d:%d Failed to make call in R2 channel, openr2_chan_make_call failed\n", zchan->span_id, zchan->chan_id);
+ zchan->caller_data.hangup_cause = ZAP_CAUSE_DESTINATION_OUT_OF_ORDER;
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ }
+ break;
+
+ /* the call is ringing */
+ case ZAP_CHANNEL_STATE_PROGRESS:
+ case ZAP_CHANNEL_STATE_PROGRESS_MEDIA:
+ {
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ if (!R2CALL(zchan)->accepted) {
+ zap_log(ZAP_LOG_DEBUG, "PROGRESS: Accepting call on channel %d\n", zchan->physical_chan_id);
+ oz_r2_accept_call(zchan);
+ }
+ } else {
+ zap_log(ZAP_LOG_DEBUG, "PROGRESS: Notifying progress in channel %d\n", zchan->physical_chan_id);
+ sigev.event_id = ZAP_SIGEVENT_PROGRESS;
+ if (zap_span_send_signal(zchan->span, &sigev) != ZAP_SUCCESS) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ }
+ }
+ break;
+
+ /* the call was answered */
+ case ZAP_CHANNEL_STATE_UP:
+ {
+ zap_log(ZAP_LOG_DEBUG, "UP: Call was answered on channel %d\n", zchan->physical_chan_id);
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ if (!R2CALL(zchan)->accepted) {
+ zap_log(ZAP_LOG_DEBUG, "UP: Call has not been accepted, need to accept first\n");
+ // the answering will be done in the on_call_accepted handler
+ oz_r2_accept_call(zchan);
+ R2CALL(zchan)->answer_pending = 1;
+ } else {
+ oz_r2_answer_call(zchan);
+ }
+ } else {
+ zap_log(ZAP_LOG_DEBUG, "UP: Notifying of call answered in channel %d\n", zchan->physical_chan_id);
+ sigev.event_id = ZAP_SIGEVENT_UP;
+ if (zap_span_send_signal(zchan->span, &sigev) != ZAP_SUCCESS) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ }
+ }
+ break;
+
+ /* just got hangup */
+ case ZAP_CHANNEL_STATE_HANGUP:
+ {
+ /* FIXME: the cause should be retrieved from zchan->caller_data.hangup_cause and translated from Q931 to R2 cause */
+ zap_log(ZAP_LOG_DEBUG, "HANGUP: Clearing call on channel %d\n", zchan->physical_chan_id);
+ if (!R2CALL(zchan)->disconnect_rcvd) {
+ /* this will disconnect the call, but need to wait for the call end before moving to DOWN */
+ openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
+ } else {
+ /* at this point on_call_end possibly was already called,
+ * but we needed to wait for the openzap confirmation before moving to DOWN */
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ }
+ }
+ break;
+
+ /* just got hangup from the openzap side due to abnormal failure */
+ case ZAP_CHANNEL_STATE_CANCEL:
+ {
+ zap_log(ZAP_LOG_DEBUG, "CANCEL: Unable to receive call on channel %d\n", zchan->physical_chan_id);
+ openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
+ }
+ break;
+
+ /* finished call for good */
+ case ZAP_CHANNEL_STATE_DOWN:
+ {
+ zap_log(ZAP_LOG_DEBUG, "DOWN: Placing channel %d back to the pool of available channels\n", zchan->physical_chan_id);
+ zap_channel_done(zchan);
+ goto endthread;
+ }
+ break;
+
+ default:
+ {
+ zap_log(ZAP_LOG_ERROR, "%s: Unhandled channel state change in channel %d\n", zap_channel_state2str(zchan->state), zchan->physical_chan_id);
+ }
+ break;
+
+ }
+ }
+
+ if (flags) {
+ if (zap_channel_wait(zchan, &flags, interval * 2) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_DEBUG, "zap_channel_wait did not return ZAP_SUCCESS\n");
+ continue;
+ }
+
+ /* handle timeout events first if any */
+ openr2_chan_run_schedule(r2chan);
+
+ /* openr2 will now try to detect MF tones, make sense out of them, reply if necessary with another tone and trigger
+ * telephony events via the call event interface we provided when creating the R2 context.
+ * openr2 will also call our I/O callbacks to retrieve audio from the channel and call our wait poll I/O registered callback
+ * and will not return from this function until the I/O poll callback returns no pending events
+ * */
+ openr2_chan_process_mf_signaling(r2chan);
+ if (R2CALL(zchan)->state_ack_pending) {
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_STATE_CHANGE);
+ zap_channel_complete_state(zchan);
+ R2CALL(zchan)->state_ack_pending = 0;
+ }
+ } else {
+ /* once the MF signaling has end we just loop here waiting for state changes */
+ zap_sleep(interval);
+ }
+
+ }
+
+endthread:
+
+ closed_chan = zchan;
+ zap_channel_close(&closed_chan);
+ zap_clear_flag(zchan, ZAP_CHANNEL_INTHREAD);
+ zap_log(ZAP_LOG_DEBUG, "R2 channel %d thread ended.\n", zchan->physical_chan_id);
+
+ zap_mutex_lock(g_thread_count_mutex);
+ g_thread_count--;
+ zap_mutex_unlock(g_thread_count_mutex);
+
+ return NULL;
+}
+
+static void *zap_r2_run(zap_thread_t *me, void *obj)
+{
+ openr2_chan_t *r2chan;
+ zap_status_t status;
+ zap_span_t *span = (zap_span_t *) obj;
+ zap_r2_data_t *r2data = span->signal_data;
+ int waitms = 1000;
+ int i;
+
+ zap_log(ZAP_LOG_DEBUG, "OpenR2 monitor thread started.\n");
+ r2chan = NULL;
+ for (i = 1; i <= span->chan_count; i++) {
+ r2chan = R2CALL(span->channels[i])->r2chan;
+ openr2_chan_set_idle(r2chan);
+ openr2_chan_process_cas_signaling(r2chan);
+ }
+
+ while (zap_running() && zap_test_flag(r2data, ZAP_R2_RUNNING)) {
+ status = zap_span_poll_event(span, waitms);
+ if (ZAP_FAIL == status) {
+ zap_log(ZAP_LOG_ERROR, "Failure Polling event! [%s]\n", span->last_error);
+ continue;
+ }
+ if (ZAP_SUCCESS == status) {
+ zap_event_t *event;
+ while (zap_span_next_event(span, &event) == ZAP_SUCCESS) {
+ if (event->enum_id == ZAP_OOB_CAS_BITS_CHANGE) {
+ r2chan = R2CALL(event->channel)->r2chan;
+ zap_log(ZAP_LOG_DEBUG, "Handling CAS on channel %d.\n", openr2_chan_get_number(r2chan));
+ // we only expect CAS and other OOB events on this thread/loop, once a call is started
+ // the MF events (in-band signaling) are handled in the call thread
+ openr2_chan_process_cas_signaling(r2chan);
+ } else {
+ zap_log(ZAP_LOG_DEBUG, "Ignoring event %d on channel %d.\n", event->enum_id, openr2_chan_get_number(r2chan));
+ // XXX TODO: handle alarms here XXX
+ }
+ }
+ } else if (status != ZAP_TIMEOUT) {
+ zap_log(ZAP_LOG_ERROR, "zap_span_poll_event returned %d.\n", status);
+ } else {
+ //zap_log(ZAP_LOG_DEBUG, "timed out waiting for event on span %d\n", span->span_id);
+ }
+ }
+
+ /*
+ FIXME: we should set BLOCKED but at this point I/O routines of openzap caused segfault
+ for (i = 1; i <= span->chan_count; i++) {
+ r2chan = R2CALL(span->channels[i])->r2chan;
+ openr2_chan_set_blocked(r2chan);
+ }
+ */
+
+ zap_clear_flag(r2data, ZAP_R2_RUNNING);
+ zap_log(ZAP_LOG_DEBUG, "R2 thread ending.\n");
+
+ return NULL;
+
+}
+
+static ZIO_API_FUNCTION(zap_r2_api)
+{
+ char *mycmd = NULL, *argv[10] = { 0 };
+ int argc = 0;
+
+ if (data) {
+ mycmd = strdup(data);
+ argc = zap_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+ }
+
+ if (argc == 2) {
+ if (!strcasecmp(argv[0], "kill")) {
+ int span_id = atoi(argv[1]);
+ zap_span_t *span = NULL;
+
+ if (zap_span_find_by_name(argv[1], &span) == ZAP_SUCCESS || zap_span_find(span_id, &span) == ZAP_SUCCESS) {
+ zap_r2_data_t *r2data = span->signal_data;
+
+ if (span->start != zap_r2_start) {
+ stream->write_function(stream, "-ERR invalid span.\n");
+ goto done;
+ }
+
+ zap_clear_flag(r2data, ZAP_R2_RUNNING);
+ stream->write_function(stream, "+OK killed.\n");
+ goto done;
+ } else {
+ stream->write_function(stream, "-ERR invalid span.\n");
+ goto done;
+ }
+ }
+
+ if (!strcasecmp(argv[0], "status")) {
+ int span_id = atoi(argv[1]);
+ zap_r2_data_t *r2data = NULL;
+ zap_span_t *span = NULL;
+ openr2_chan_t *r2chan = NULL;
+ openr2_context_t *r2context = NULL;
+ int i = 0;
+
+ if (zap_span_find_by_name(argv[1], &span) == ZAP_SUCCESS || zap_span_find(span_id, &span) == ZAP_SUCCESS) {
+ if (span->start != zap_r2_start) {
+ stream->write_function(stream, "-ERR not an R2 span.\n");
+ goto done;
+ }
+ if (!(r2data = span->signal_data)) {
+ stream->write_function(stream, "-ERR invalid span. No R2 singal data in span.\n");
+ goto done;
+ }
+ r2context = r2data->r2context;
+ openr2_variant_t r2variant = openr2_context_get_variant(r2context);
+ stream->write_function(stream,
+ "Variant: %s\n"
+ "Max ANI: %d\n"
+ "Max DNIS: %d\n"
+ "ANI First: %s\n"
+ "Immediate Accept: %s\n",
+ openr2_proto_get_variant_string(r2variant),
+ openr2_context_get_max_ani(r2context),
+ openr2_context_get_max_dnis(r2context),
+ openr2_context_get_ani_first(r2context) ? "Yes" : "No",
+ openr2_context_get_immediate_accept(r2context) ? "Yes" : "No");
+ stream->write_function(stream, "\n");
+ stream->write_function(stream, "%4s %-12.12s %-12.12s\n", "Channel", "Tx CAS", "Rx CAS");
+ for (i = 1; i <= span->chan_count; i++) {
+ if (i == 16) continue;
+ r2chan = R2CALL(span->channels[i])->r2chan;
+ stream->write_function(stream, "%4d %-12.12s %-12.12s\n",
+ span->channels[i]->physical_chan_id,
+ openr2_chan_get_tx_cas_string(r2chan),
+ openr2_chan_get_rx_cas_string(r2chan));
+ }
+ stream->write_function(stream, "\n");
+ stream->write_function(stream, "+OK.\n");
+ goto done;
+ } else {
+ stream->write_function(stream, "-ERR invalid span.\n");
+ goto done;
+ }
+ }
+
+ }
+
+ if (argc == 1) {
+ if (!strcasecmp(argv[0], "threads")) {
+ zap_mutex_lock(g_thread_count_mutex);
+ stream->write_function(stream, "%d R2 channel threads up\n", g_thread_count);
+ zap_mutex_unlock(g_thread_count_mutex);
+ stream->write_function(stream, "+OK.\n");
+ goto done;
+ }
+
+ if (!strcasecmp(argv[0], "version")) {
+ stream->write_function(stream, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision());
+ stream->write_function(stream, "+OK.\n");
+ goto done;
+ }
+
+ if (!strcasecmp(argv[0], "variants")) {
+ int32_t numvariants = 0;
+ const openr2_variant_entry_t *variants = openr2_proto_get_variant_list(&numvariants);
+ if (!variants) {
+ stream->write_function(stream, "-ERR failed to retrieve openr2 variant list.\n");
+ goto done;
+ }
+#define VARIANT_FORMAT "%4s %40s\n"
+ stream->write_function(stream, VARIANT_FORMAT, "Variant Code", "Country");
+ numvariants--;
+ for (; numvariants; numvariants--) {
+ stream->write_function(stream, VARIANT_FORMAT, variants[numvariants].name, variants[numvariants].country);
+ }
+ stream->write_function(stream, "+OK.\n");
+#undef VARIANT_FORMAT
+ goto done;
+ }
+ }
+
+ stream->write_function(stream, "-ERR invalid command.\n");
+
+done:
+
+ zap_safe_free(mycmd);
+
+ return ZAP_SUCCESS;
+
+}
+
+static ZIO_IO_LOAD_FUNCTION(zap_r2_io_init)
+{
+ assert(zio != NULL);
+ memset(&g_zap_r2_interface, 0, sizeof(g_zap_r2_interface));
+
+ g_zap_r2_interface.name = "r2";
+ g_zap_r2_interface.api = zap_r2_api;
+
+ *zio = &g_zap_r2_interface;
+
+ return ZAP_SUCCESS;
+}
+
+static ZIO_SIG_LOAD_FUNCTION(zap_r2_init)
+{
+ g_mod_data_hash = create_hashtable(10, zap_hash_hashfromstring, zap_hash_equalkeys);
+ if (!g_mod_data_hash) {
+ return ZAP_FAIL;
+ }
+ zap_mutex_create(&g_thread_count_mutex);
+ return ZAP_SUCCESS;
+}
+
+static ZIO_SIG_UNLOAD_FUNCTION(zap_r2_destroy)
+{
+ zap_hash_iterator_t *i = NULL;
+ zap_r2_span_pvt_t *spanpvt = NULL;
+ const void *key = NULL;
+ void *val = NULL;
+ for (i = hashtable_first(g_mod_data_hash); i; i = hashtable_next(i)) {
+ hashtable_this(i, &key, NULL, &val);
+ if (key && val) {
+ spanpvt = val;
+ openr2_context_delete(spanpvt->r2context);
+ hashtable_destroy(spanpvt->r2calls);
+ }
+ }
+ hashtable_destroy(g_mod_data_hash);
+ zap_mutex_destroy(&g_thread_count_mutex);
+ return ZAP_SUCCESS;
+}
+
+zap_module_t zap_module = {
+ "r2",
+ zap_r2_io_init,
+ NULL,
+ zap_r2_init,
+ zap_r2_configure_span,
+ zap_r2_destroy
+};
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4
+ */
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1768 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#include "openzap.h"
+#include "sangoma_boost_client.h"
+#include "zap_sangoma_boost.h"
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#define MAX_TRUNK_GROUPS 64
+static time_t congestion_timeouts[MAX_TRUNK_GROUPS];
+
+/**
+ * \brief Strange flag
+ */
+typedef enum {
+ SFLAG_FREE_REQ_ID = (1 << 0),
+ SFLAG_SENT_FINAL_MSG = (1 << 1),
+ SFLAG_SENT_ACK = (1 << 2),
+ SFLAG_RECVD_ACK = (1 << 3),
+ SFLAG_HANGUP = (1 << 4),
+ SFLAG_TERMINATING = (1 << 5)
+} sflag_t;
+
+typedef uint16_t sangoma_boost_request_id_t;
+
+/**
+ * \brief SANGOMA boost request status
+ */
+typedef enum {
+ BST_FREE,
+ BST_WAITING,
+ BST_ACK,
+ BST_READY,
+ BST_FAIL
+} sangoma_boost_request_status_t;
+
+/**
+ * \brief SANGOMA boost request structure
+ */
+typedef struct {
+ sangoma_boost_request_status_t status;
+ sangomabc_short_event_t event;
+ zap_span_t *span;
+ zap_channel_t *zchan;
+ int hangup_cause;
+ int flags;
+} sangoma_boost_request_t;
+
+//#define MAX_REQ_ID ZAP_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN * ZAP_MAX_CHANNELS_PHYSICAL_SPAN
+#define MAX_REQ_ID 6000
+
+static uint16_t SETUP_GRID[ZAP_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN+1][ZAP_MAX_CHANNELS_PHYSICAL_SPAN+1] = {{ 0 }};
+
+static sangoma_boost_request_t OUTBOUND_REQUESTS[MAX_REQ_ID+1] = {{ 0 }};
+
+static zap_mutex_t *request_mutex = NULL;
+
+static uint8_t req_map[MAX_REQ_ID+1] = { 0 };
+static uint8_t nack_map[MAX_REQ_ID+1] = { 0 };
+
+/**
+ * \brief Releases span and channel from setup grid
+ * \param span Span number
+ * \param chan Channel number
+ * \param func Calling function
+ * \param line Line number on request
+ * \return NULL if not found, channel otherwise
+ */
+static void __release_request_id_span_chan(int span, int chan, const char *func, int line)
+{
+ int id;
+
+ zap_mutex_lock(request_mutex);
+ if ((id = SETUP_GRID[span][chan])) {
+ assert(id <= MAX_REQ_ID);
+ req_map[id] = 0;
+ SETUP_GRID[span][chan] = 0;
+ }
+ zap_mutex_unlock(request_mutex);
+}
+#define release_request_id_span_chan(s, c) __release_request_id_span_chan(s, c, __FUNCTION__, __LINE__)
+
+/**
+ * \brief Releases request ID
+ * \param func Calling function
+ * \param line Line number on request
+ * \return NULL if not found, channel otherwise
+ */
+static void __release_request_id(sangoma_boost_request_id_t r, const char *func, int line)
+{
+ assert(r <= MAX_REQ_ID);
+ zap_mutex_lock(request_mutex);
+ req_map[r] = 0;
+ zap_mutex_unlock(request_mutex);
+}
+#define release_request_id(r) __release_request_id(r, __FUNCTION__, __LINE__)
+
+static sangoma_boost_request_id_t last_req = 0;
+
+/**
+ * \brief Gets the first available tank request ID
+ * \param func Calling function
+ * \param line Line number on request
+ * \return 0 on failure, request ID on success
+ */
+static sangoma_boost_request_id_t __next_request_id(const char *func, int line)
+{
+ sangoma_boost_request_id_t r = 0, i = 0;
+ int found=0;
+
+ zap_mutex_lock(request_mutex);
+ //r = ++last_req;
+ //while(!r || req_map[r]) {
+
+ for (i=1; i<= MAX_REQ_ID; i++){
+ r = ++last_req;
+
+ if (r >= MAX_REQ_ID) {
+ r = i = last_req = 1;
+ }
+
+ if (req_map[r]) {
+ /* Busy find another */
+ continue;
+
+ }
+
+ req_map[r] = 1;
+ found=1;
+ break;
+
+ }
+
+ zap_mutex_unlock(request_mutex);
+
+ if (!found) {
+ return 0;
+ }
+
+ return r;
+}
+#define next_request_id() __next_request_id(__FUNCTION__, __LINE__)
+
+/**
+ * \brief Finds the channel that triggered an event
+ * \param span Span where to search the channel
+ * \param event SANGOMA event
+ * \param force Do not wait for the channel to be available if in use
+ * \return NULL if not found, channel otherwise
+ */
+static zap_channel_t *find_zchan(zap_span_t *span, sangomabc_short_event_t *event, int force)
+{
+ int i;
+ zap_channel_t *zchan = NULL;
+
+ for(i = 1; i <= span->chan_count; i++) {
+ if (span->channels[i]->physical_span_id == event->span+1 && span->channels[i]->physical_chan_id == event->chan+1) {
+ zchan = span->channels[i];
+ if (force || (zchan->state == ZAP_CHANNEL_STATE_DOWN && !zap_test_flag(zchan, ZAP_CHANNEL_INUSE))) {
+ break;
+ } else {
+ zchan = NULL;
+ zap_log(ZAP_LOG_DEBUG, "Channel %d:%d ~ %d:%d is already in use.\n",
+ span->channels[i]->span_id,
+ span->channels[i]->chan_id,
+ span->channels[i]->physical_span_id,
+ span->channels[i]->physical_chan_id
+ );
+ break;
+ }
+ }
+ }
+
+ return zchan;
+}
+
+static int check_congestion(int trunk_group)
+{
+ if (congestion_timeouts[trunk_group]) {
+ time_t now = time(NULL);
+
+ if (now >= congestion_timeouts[trunk_group]) {
+ congestion_timeouts[trunk_group] = 0;
+ } else {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * \brief Requests an sangoma boost channel on a span (outgoing call)
+ * \param span Span where to get a channel
+ * \param chan_id Specific channel to get (0 for any)
+ * \param direction Call direction
+ * \param caller_data Caller information
+ * \param zchan Channel to initialise
+ * \return Success or failure
+ */
+static ZIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request)
+{
+ zap_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+ zap_status_t status = ZAP_FAIL;
+ sangoma_boost_request_id_t r;
+ sangomabc_event_t event = {0};
+
+ /* sanity has to be more than 8 seconds.
+ * In PRI specs, timeout is 4 seconds for remote switch to respond to a SETUP,
+ * and PRI stack will retransmit a second SETUP after the first timeout, so
+ * we should allow for at least 8 seconds */
+
+ int sanity = 10000;
+ sangoma_boost_request_status_t st;
+ char ani[128] = "";
+ char *gr = NULL;
+ uint32_t count = 0;
+ int tg=0;
+
+ if (zap_test_flag(span, ZAP_SPAN_SUSPENDED)) {
+ zap_log(ZAP_LOG_CRIT, "SPAN is not online.\n");
+ *zchan = NULL;
+ return ZAP_FAIL;
+ }
+
+ zap_set_string(ani, caller_data->ani.digits);
+
+ if ((gr = strchr(ani, '@'))) {
+ *gr++ = '\0';
+ }
+
+ if (gr && *(gr+1)) {
+ tg = atoi(gr+1);
+ if (tg > 0) {
+ tg--;
+ }
+ }
+ event.trunk_group = tg;
+
+ if (check_congestion(tg)) {
+ zap_log(ZAP_LOG_CRIT, "All circuits are busy. Trunk Group=%i (BOOST REQUESTED BACK OFF)\n",tg+1);
+ *zchan = NULL;
+ return ZAP_FAIL;
+ }
+
+ zap_span_channel_use_count(span, &count);
+
+ if (count >= span->chan_count) {
+ zap_log(ZAP_LOG_CRIT, "All circuits are busy.\n");
+ *zchan = NULL;
+ return ZAP_FAIL;
+ }
+
+ r = next_request_id();
+ if (r == 0) {
+ zap_log(ZAP_LOG_CRIT, "All tanks ids are busy.\n");
+ *zchan = NULL;
+ return ZAP_FAIL;
+ }
+
+ /* sangomabc_call_init (event, calling, called, setup_id) */
+ sangomabc_call_init(&event, caller_data->cid_num.digits, ani, r);
+ //sangoma_bc_call_init will clear the trunk_group val so we need to set it again
+ event.trunk_group=tg;
+
+ if (gr && *(gr+1)) {
+
+ switch(*gr) {
+ case 'g':
+ event.hunt_group = SIGBOOST_HUNTGRP_SEQ_ASC;
+ break;
+ case 'G':
+ event.hunt_group = SIGBOOST_HUNTGRP_SEQ_DESC;
+ break;
+ case 'r':
+ event.hunt_group = SIGBOOST_HUNTGRP_RR_ASC;
+ break;
+ case 'R':
+ event.hunt_group = SIGBOOST_HUNTGRP_RR_DESC;
+ break;
+ default:
+ zap_log(ZAP_LOG_WARNING, "Failed to determine huntgroup (%s)\n", gr);
+ event.hunt_group = SIGBOOST_HUNTGRP_SEQ_ASC;
+ }
+ }
+
+ zap_set_string(event.calling_name, caller_data->cid_name);
+ zap_set_string(event.rdnis.digits, caller_data->rdnis.digits);
+
+ if (strlen(caller_data->rdnis.digits)) {
+ event.rdnis.digits_count = strlen(caller_data->rdnis.digits)+1;
+ event.rdnis.ton = caller_data->rdnis.type;
+ event.rdnis.npi = caller_data->rdnis.plan;
+ }
+
+ event.calling.screening_ind = caller_data->screen;
+ event.calling.presentation_ind = caller_data->pres;
+
+ event.calling.ton = caller_data->cid_num.type;
+ event.calling.npi = caller_data->cid_num.plan;
+
+ event.called.ton = caller_data->ani.type;
+ event.called.npi = caller_data->ani.plan;
+
+ OUTBOUND_REQUESTS[r].status = BST_WAITING;
+ OUTBOUND_REQUESTS[r].span = span;
+
+ if (sangomabc_connection_write(&sangoma_boost_data->mcon, &event) <= 0) {
+ zap_log(ZAP_LOG_CRIT, "Failed to tx on ISUP socket [%s]\n", strerror(errno));
+ status = ZAP_FAIL;
+ *zchan = NULL;
+ goto done;
+ }
+
+ while(zap_running() && OUTBOUND_REQUESTS[r].status == BST_WAITING) {
+ zap_sleep(1);
+ if (--sanity <= 0) {
+ status = ZAP_FAIL;
+ *zchan = NULL;
+ goto done;
+ }
+ }
+
+ if (OUTBOUND_REQUESTS[r].status == BST_READY && OUTBOUND_REQUESTS[r].zchan) {
+ *zchan = OUTBOUND_REQUESTS[r].zchan;
+ status = ZAP_SUCCESS;
+ } else {
+ status = ZAP_FAIL;
+ *zchan = NULL;
+ }
+
+ done:
+
+ st = OUTBOUND_REQUESTS[r].status;
+ OUTBOUND_REQUESTS[r].status = BST_FREE;
+
+ if (status == ZAP_FAIL) {
+ if (st == BST_FAIL) {
+ caller_data->hangup_cause = OUTBOUND_REQUESTS[r].hangup_cause;
+ } else {
+ caller_data->hangup_cause = ZAP_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
+ }
+ }
+
+ if (st == BST_FAIL) {
+ release_request_id(r);
+ } else if (st != BST_READY) {
+ assert(r <= MAX_REQ_ID);
+ nack_map[r] = 1;
+ sangomabc_exec_command(&sangoma_boost_data->mcon,
+ 0,
+ 0,
+ r,
+ SIGBOOST_EVENT_CALL_START_NACK,
+ 0,
+ 0);
+ }
+
+ return status;
+}
+
+/**
+ * \brief Starts an sangoma boost channel (outgoing call)
+ * \param zchan Channel to initiate call on
+ * \return Success
+ */
+static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(sangoma_boost_outgoing_call)
+{
+ zap_status_t status = ZAP_SUCCESS;
+
+ return status;
+}
+
+/**
+ * \brief Handler for call start ack no media event
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_progress(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ zap_channel_t *zchan;
+
+
+ if ((zchan = find_zchan(span, event, 1))) {
+ zap_mutex_lock(zchan->mutex);
+ if (zchan->state == ZAP_CHANNEL_STATE_HOLD) {
+ if ((event->flags & SIGBOOST_PROGRESS_MEDIA)) {
+ zchan->init_state = ZAP_CHANNEL_STATE_PROGRESS_MEDIA;
+ zap_log(ZAP_LOG_DEBUG, "Channel init state updated to PROGRESS_MEDIA [Csid:%d]\n", event->call_setup_id);
+ } else if ((event->flags & SIGBOOST_PROGRESS_RING)) {
+ zchan->init_state = ZAP_CHANNEL_STATE_PROGRESS;
+ zap_log(ZAP_LOG_DEBUG, "Channel init state updated to PROGRESS [Csid:%d]\n", event->call_setup_id);
+ } else {
+ zchan->init_state = ZAP_CHANNEL_STATE_IDLE;
+ zap_log(ZAP_LOG_DEBUG, "Channel init state updated to IDLE [Csid:%d]\n", event->call_setup_id);
+ }
+ } else {
+ if ((event->flags & SIGBOOST_PROGRESS_MEDIA)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS_MEDIA);
+ } else if ((event->flags & SIGBOOST_PROGRESS_RING)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS);
+ } else {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_IDLE);
+ }
+ }
+ zap_mutex_unlock(zchan->mutex);
+ }
+}
+
+/**
+ * \brief Handler for call start ack event
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_start_ack(sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ zap_channel_t *zchan;
+
+ if (nack_map[event->call_setup_id]) {
+ return;
+ }
+
+ OUTBOUND_REQUESTS[event->call_setup_id].event = *event;
+ SETUP_GRID[event->span][event->chan] = event->call_setup_id;
+
+ if ((zchan = find_zchan(OUTBOUND_REQUESTS[event->call_setup_id].span, event, 0))) {
+ if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "OPEN ERROR [%s]\n", zchan->last_error);
+ } else {
+ zap_set_flag(zchan, ZAP_CHANNEL_OUTBOUND);
+ zap_set_flag_locked(zchan, ZAP_CHANNEL_INUSE);
+ zchan->extra_id = event->call_setup_id;
+ zap_log(ZAP_LOG_DEBUG, "Assign chan %d:%d (%d:%d) CSid=%d\n", zchan->span_id, zchan->chan_id, event->span+1,event->chan+1, event->call_setup_id);
+ zchan->sflags = SFLAG_RECVD_ACK;
+
+ if ((event->flags & SIGBOOST_PROGRESS_MEDIA)) {
+ zchan->init_state = ZAP_CHANNEL_STATE_PROGRESS_MEDIA;
+ zap_log(ZAP_LOG_DEBUG, "Channel init state changed to PROGRESS_MEDIA [Csid:%d]\n", event->call_setup_id);
+ } else if ((event->flags & SIGBOOST_PROGRESS_RING)) {
+ zchan->init_state = ZAP_CHANNEL_STATE_PROGRESS;
+ zap_log(ZAP_LOG_DEBUG, "Channel init state changed to PROGRESS [Csid:%d]\n", event->call_setup_id);
+ } else {
+ zchan->init_state = ZAP_CHANNEL_STATE_IDLE;
+ zap_log(ZAP_LOG_DEBUG, "Channel init state changed to IDLE [Csid:%d]\n", event->call_setup_id);
+ }
+
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HOLD);
+
+ OUTBOUND_REQUESTS[event->call_setup_id].flags = event->flags;
+ OUTBOUND_REQUESTS[event->call_setup_id].zchan = zchan;
+ OUTBOUND_REQUESTS[event->call_setup_id].status = BST_READY;
+ return;
+ }
+ }
+
+ //printf("WTF BAD ACK CSid=%d span=%d chan=%d\n", event->call_setup_id, event->span+1,event->chan+1);
+ if ((zchan = find_zchan(OUTBOUND_REQUESTS[event->call_setup_id].span, event, 1))) {
+ //printf("WTF BAD ACK2 %d:%d (%d:%d) CSid=%d xtra_id=%d out=%d state=%s\n", zchan->span_id, zchan->chan_id, event->span+1,event->chan+1, event->call_setup_id, zchan->extra_id, zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND), zap_channel_state2str(zchan->state));
+ }
+
+ zap_set_sflag(zchan, SFLAG_SENT_FINAL_MSG);
+ zap_log(ZAP_LOG_CRIT, "START ACK CANT FIND A CHAN %d:%d\n", event->span+1,event->chan+1);
+ sangomabc_exec_command(mcon,
+ event->span,
+ event->chan,
+ event->call_setup_id,
+ SIGBOOST_EVENT_CALL_STOPPED,
+ ZAP_CAUSE_DESTINATION_OUT_OF_ORDER, 0);
+ OUTBOUND_REQUESTS[event->call_setup_id].status = BST_FAIL;
+ OUTBOUND_REQUESTS[event->call_setup_id].hangup_cause = ZAP_CAUSE_DESTINATION_OUT_OF_ORDER;
+
+}
+
+/**
+ * \brief Handler for call done event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_done(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ zap_channel_t *zchan;
+ int r = 0;
+
+ if ((zchan = find_zchan(span, event, 1))) {
+ zap_mutex_lock(zchan->mutex);
+
+ if (zchan->state == ZAP_CHANNEL_STATE_DOWN || zchan->state == ZAP_CHANNEL_STATE_HANGUP_COMPLETE || zap_test_sflag(zchan, SFLAG_TERMINATING)) {
+ goto done;
+ }
+
+ zap_set_state_r(zchan, ZAP_CHANNEL_STATE_HANGUP_COMPLETE, 0, r);
+ if (r) {
+ zap_set_sflag(zchan, SFLAG_FREE_REQ_ID);
+ zap_mutex_unlock(zchan->mutex);
+ return;
+ }
+ }
+
+ done:
+
+ if (zchan) {
+ zap_mutex_unlock(zchan->mutex);
+ }
+
+ if (event->call_setup_id) {
+ release_request_id(event->call_setup_id);
+ } else {
+ release_request_id_span_chan(event->span, event->chan);
+ }
+}
+
+/**
+ * \brief Handler for call start nack event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_start_nack(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ zap_channel_t *zchan;
+
+ if (event->release_cause == SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY) {
+ uint32_t count = 0;
+ int delay = 0;
+ int tg=event->trunk_group;
+
+ zap_span_channel_use_count(span, &count);
+
+ delay = (int) (count / 100) * 2;
+
+ if (delay > 10) {
+ delay = 10;
+ } else if (delay < 1) {
+ delay = 1;
+ }
+
+ if (tg < 0 || tg >= MAX_TRUNK_GROUPS) {
+ zap_log(ZAP_LOG_CRIT, "Invalid All Ckt Busy trunk group number %i\n", tg);
+ tg=0;
+ }
+
+ congestion_timeouts[tg] = time(NULL) + delay;
+ event->release_cause = 17;
+
+ } else if (event->release_cause == SIGBOOST_CALL_SETUP_CSUPID_DBL_USE) {
+ event->release_cause = 17;
+ }
+
+ if (event->call_setup_id) {
+
+ sangomabc_exec_command(mcon,
+ 0,
+ 0,
+ event->call_setup_id,
+ SIGBOOST_EVENT_CALL_START_NACK_ACK,
+ 0, 0);
+
+ OUTBOUND_REQUESTS[event->call_setup_id].event = *event;
+ OUTBOUND_REQUESTS[event->call_setup_id].status = BST_FAIL;
+ OUTBOUND_REQUESTS[event->call_setup_id].hangup_cause = event->release_cause;
+ return;
+ } else {
+ if ((zchan = find_zchan(span, event, 1))) {
+ int r = 0;
+ assert(!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND));
+
+ zchan->call_data = (void*)(intptr_t)event->event_id;
+
+ zap_mutex_lock(zchan->mutex);
+ zap_set_state_r(zchan, ZAP_CHANNEL_STATE_TERMINATING, 0, r);
+ if (r == ZAP_STATE_CHANGE_SUCCESS) {
+ zchan->caller_data.hangup_cause = event->release_cause;
+ }
+ zap_mutex_unlock(zchan->mutex);
+ if (r) {
+ return;
+ }
+ }
+ }
+
+ if (zchan) {
+ zap_set_sflag_locked(zchan, SFLAG_SENT_FINAL_MSG);
+ }
+
+ /* nobody else will do it so we have to do it ourselves */
+ sangomabc_exec_command(mcon,
+ event->span,
+ event->chan,
+ 0,
+ SIGBOOST_EVENT_CALL_START_NACK_ACK,
+ 0, 0);
+}
+
+/**
+ * \brief Handler for call stop event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_stop(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ zap_channel_t *zchan;
+
+ if ((zchan = find_zchan(span, event, 1))) {
+ int r = 0;
+
+ zap_mutex_lock(zchan->mutex);
+
+ if (zap_test_sflag(zchan, SFLAG_HANGUP)) {
+ /* racing condition where both sides initiated a hangup
+ * Do not change current state as channel is already clearing
+ * itself through local initiated hangup */
+
+ sangomabc_exec_command(mcon,
+ zchan->physical_span_id-1,
+ zchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_STOPPED_ACK,
+ 0, 0);
+ zap_mutex_unlock(zchan->mutex);
+ return;
+ } else {
+ if (zchan->state == ZAP_CHANNEL_STATE_HOLD) {
+ zchan->init_state = ZAP_CHANNEL_STATE_TERMINATING;
+ zap_log(ZAP_LOG_DEBUG, "Channel init state updated to TERMINATING [Csid:%d]\n", event->call_setup_id);
+ OUTBOUND_REQUESTS[event->call_setup_id].hangup_cause = event->release_cause;
+ zchan->caller_data.hangup_cause = event->release_cause;
+ zap_mutex_unlock(zchan->mutex);
+ return;
+ } else {
+ zap_set_state_r(zchan, ZAP_CHANNEL_STATE_TERMINATING, 0, r);
+ }
+ }
+
+ if (r == ZAP_STATE_CHANGE_SUCCESS) {
+ zchan->caller_data.hangup_cause = event->release_cause;
+ }
+
+ if (r) {
+ zap_set_sflag(zchan, SFLAG_FREE_REQ_ID);
+ }
+
+ zap_mutex_unlock(zchan->mutex);
+
+ if (r) {
+ return;
+ }
+ } /* else we have to do it ourselves.... */
+
+ zap_log(ZAP_LOG_WARNING, "We could not find chan: s%dc%d\n", event->span, event->chan);
+ release_request_id_span_chan(event->span, event->chan);
+}
+
+/**
+ * \brief Handler for call answer event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_answer(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ zap_channel_t *zchan;
+
+ if ((zchan = find_zchan(span, event, 1))) {
+ zap_mutex_lock(zchan->mutex);
+ if (zchan->state == ZAP_CHANNEL_STATE_HOLD) {
+ zchan->init_state = ZAP_CHANNEL_STATE_UP;
+ } else {
+ int r = 0;
+ zap_set_state_r(zchan, ZAP_CHANNEL_STATE_UP, 0, r);
+ }
+ zap_mutex_unlock(zchan->mutex);
+ } else {
+ zap_log(ZAP_LOG_CRIT, "ANSWER CANT FIND A CHAN %d:%d\n", event->span+1,event->chan+1);
+ sangomabc_exec_command(mcon,
+ event->span,
+ event->chan,
+ event->call_setup_id,
+ SIGBOOST_EVENT_CALL_STOPPED,
+ ZAP_CAUSE_DESTINATION_OUT_OF_ORDER, 0);
+ }
+}
+
+static __inline__ void advance_chan_states(zap_channel_t *zchan);
+
+/**
+ * \brief Handler for call start event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_start(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_event_t *event)
+{
+ zap_channel_t *zchan;
+ int hangup_cause = ZAP_CAUSE_CALL_REJECTED;
+
+ if (!(zchan = find_zchan(span, (sangomabc_short_event_t*)event, 0))) {
+ if ((zchan = find_zchan(span, (sangomabc_short_event_t*)event, 1))) {
+ int r;
+ if (zchan->state == ZAP_CHANNEL_STATE_UP) {
+ zap_log(ZAP_LOG_CRIT, "ZCHAN STATE UP -> Changed to TERMINATING %d:%d\n", event->span+1,event->chan+1);
+ zap_set_state_r(zchan, ZAP_CHANNEL_STATE_TERMINATING, 0, r);
+ } else if (zap_test_sflag(zchan, SFLAG_HANGUP)) {
+ zap_log(ZAP_LOG_CRIT, "ZCHAN STATE HANGUP -> Changed to HANGUP COMPLETE %d:%d\n", event->span+1,event->chan+1);
+ zap_set_state_r(zchan, ZAP_CHANNEL_STATE_HANGUP_COMPLETE, 0, r);
+ } else {
+ zap_log(ZAP_LOG_CRIT, "ZCHAN STATE INVALID %s on IN CALL %d:%d\n", zap_channel_state2str(zchan->state),event->span+1,event->chan+1);
+
+ }
+ zap_set_sflag(zchan, SFLAG_SENT_FINAL_MSG);
+ zchan=NULL;
+ }
+ zap_log(ZAP_LOG_CRIT, "START CANT FIND CHAN %d:%d\n", event->span+1,event->chan+1);
+ goto error;
+ }
+
+ if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_CRIT, "START CANT OPEN CHAN %d:%d\n", event->span+1,event->chan+1);
+ goto error;
+ }
+
+ zchan->sflags = 0;
+ zap_set_string(zchan->caller_data.cid_num.digits, (char *)event->calling.digits);
+ zap_set_string(zchan->caller_data.cid_name, (char *)event->calling.digits);
+ zap_set_string(zchan->caller_data.ani.digits, (char *)event->calling.digits);
+ zap_set_string(zchan->caller_data.dnis.digits, (char *)event->called.digits);
+ zap_set_string(zchan->caller_data.rdnis.digits, (char *)event->rdnis.digits);
+
+ if (strlen(event->calling_name)) {
+ zap_set_string(zchan->caller_data.cid_name, (char *)event->calling_name);
+ }
+
+ zchan->caller_data.cid_num.plan = event->calling.npi;
+ zchan->caller_data.cid_num.type = event->calling.ton;
+
+ zchan->caller_data.ani.plan = event->calling.npi;
+ zchan->caller_data.ani.type = event->calling.ton;
+
+ zchan->caller_data.dnis.plan = event->called.npi;
+ zchan->caller_data.dnis.type = event->called.ton;
+
+ zchan->caller_data.rdnis.plan = event->rdnis.npi;
+ zchan->caller_data.rdnis.type = event->rdnis.ton;
+
+ zchan->caller_data.screen = event->calling.screening_ind;
+ zchan->caller_data.pres = event->calling.presentation_ind;
+
+ if (event->custom_data_size) {
+ char* p = NULL;
+
+ p = strstr((char*)event->custom_data,"PRI001-ANI2-");
+ if (p!=NULL) {
+ int ani2 = 0;
+ sscanf(p, "PRI001-ANI2-%d", &ani2);
+ snprintf(zchan->caller_data.aniII, 5, "%.2d", ani2);
+ }
+ }
+
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RING);
+ return;
+
+ error:
+ if (zchan) {
+ hangup_cause = zchan->caller_data.hangup_cause;
+ } else {
+ zap_log(ZAP_LOG_CRIT, "START CANT FIND A CHAN %d:%d\n", event->span+1,event->chan+1);
+ hangup_cause = ZAP_CAUSE_REQUESTED_CHAN_UNAVAIL;
+ }
+ sangomabc_exec_command(mcon,
+ event->span,
+ event->chan,
+ 0,
+ SIGBOOST_EVENT_CALL_START_NACK,
+ hangup_cause, 0);
+
+}
+
+static void handle_call_loop_start(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ zap_status_t res = ZAP_FAIL;
+ zap_channel_t *zchan;
+
+ if (!(zchan = find_zchan(span, (sangomabc_short_event_t*)event, 0))) {
+ zap_log(ZAP_LOG_CRIT, "CANNOT START LOOP, CHAN NOT AVAILABLE %d:%d\n", event->span+1,event->chan+1);
+ return;
+ }
+
+ if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_CRIT, "CANNOT START LOOP, CANT OPEN CHAN %d:%d\n", event->span+1,event->chan+1);
+ return;
+ }
+
+ zap_set_state_r(zchan, ZAP_CHANNEL_STATE_IN_LOOP, 0, res);
+ if (res != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_CRIT, "yay, could not set the state of the channel to IN_LOOP, loop will fail\n");
+ zap_channel_done(zchan);
+ return;
+ }
+ zap_channel_command(zchan, ZAP_COMMAND_ENABLE_LOOP, NULL);
+}
+
+static void handle_call_loop_stop(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ zap_channel_t *zchan;
+ zap_status_t res = ZAP_FAIL;
+ if (!(zchan = find_zchan(span, (sangomabc_short_event_t*)event, 1))) {
+ zap_log(ZAP_LOG_CRIT, "CANNOT STOP LOOP, INVALID CHAN REQUESTED %d:%d\n", event->span+1,event->chan+1);
+ return;
+ }
+ if (zchan->state != ZAP_CHANNEL_STATE_IN_LOOP) {
+ zap_log(ZAP_LOG_ERROR, "Got stop loop request in a channel that is not in loop, ignoring ...\n");
+ return;
+ }
+ zap_channel_command(zchan, ZAP_COMMAND_DISABLE_LOOP, NULL);
+ /* even when we did not sent a msg we set this flag to avoid sending call stop in the DOWN state handler */
+ zap_set_flag(zchan, SFLAG_SENT_FINAL_MSG);
+ zap_set_state_r(zchan, ZAP_CHANNEL_STATE_DOWN, 0, res);
+}
+
+/**
+ * \brief Handler for heartbeat event
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_heartbeat(sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ int err;
+
+ err = sangomabc_connection_writep(mcon, (sangomabc_event_t*)event);
+
+ if (err <= 0) {
+ zap_log(ZAP_LOG_CRIT, "Failed to tx on ISUP socket [%s]: %s\n", strerror(errno));
+ }
+
+ mcon->hb_elapsed = 0;
+
+ return;
+}
+
+/**
+ * \brief Handler for restart ack event
+ * \param mcon sangoma boost connection
+ * \param span Span where event was fired
+ * \param event Event to handle
+ */
+static void handle_restart_ack(sangomabc_connection_t *mcon, zap_span_t *span, sangomabc_short_event_t *event)
+{
+ zap_log(ZAP_LOG_DEBUG, "RECV RESTART ACK\n");
+}
+
+/**
+ * \brief Handler for restart event
+ * \param mcon sangoma boost connection
+ * \param span Span where event was fired
+ * \param event Event to handle
+ */
+static void handle_restart(sangomabc_connection_t *mcon, zap_span_t *span, sangomabc_short_event_t *event)
+{
+ zap_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+
+ mcon->rxseq_reset = 0;
+ zap_set_flag((&sangoma_boost_data->mcon), MSU_FLAG_DOWN);
+ zap_set_flag_locked(span, ZAP_SPAN_SUSPENDED);
+ zap_set_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RESTARTING);
+
+ mcon->hb_elapsed = 0;
+}
+
+/**
+ * \brief Handler for incoming digit event
+ * \param mcon sangoma boost connection
+ * \param span Span where event was fired
+ * \param event Event to handle
+ */
+static void handle_incoming_digit(sangomabc_connection_t *mcon, zap_span_t *span, sangomabc_event_t *event)
+{
+ zap_channel_t *zchan = NULL;
+ char digits[MAX_DIALED_DIGITS + 2] = "";
+
+ if (!(zchan = find_zchan(span, (sangomabc_short_event_t *)event, 1))) {
+ zap_log(ZAP_LOG_ERROR, "Invalid channel\n");
+ return;
+ }
+
+ if (event->called_number_digits_count == 0) {
+ zap_log(ZAP_LOG_WARNING, "Error Incoming digit with len %s %d [w%dg%d]\n",
+ event->called_number_digits,
+ event->called_number_digits_count,
+ event->span+1, event->chan+1);
+ return;
+ }
+
+ zap_log(ZAP_LOG_WARNING, "Incoming digit with len %s %d [w%dg%d]\n",
+ event->called_number_digits,
+ event->called_number_digits_count,
+ event->span+1, event->chan+1);
+
+ memcpy(digits, event->called_number_digits, event->called_number_digits_count);
+ zap_channel_queue_dtmf(zchan, digits);
+
+ return;
+}
+
+
+/**
+ * \brief Checks if span has state changes pending and processes
+ * \param span Span where event was fired
+ * \param event Event to handle
+ */
+static zap_channel_t* event_process_states(zap_span_t *span, sangomabc_short_event_t *event)
+{
+ zap_channel_t *zchan = NULL;
+
+ switch (event->event_id) {
+ case SIGBOOST_EVENT_CALL_START_NACK:
+ case SIGBOOST_EVENT_CALL_START_NACK_ACK:
+ if (event->call_setup_id) {
+ return NULL;
+ }
+ //if event->span and event->chan is valid, fall-through
+ case SIGBOOST_EVENT_CALL_START:
+ case SIGBOOST_EVENT_CALL_START_ACK:
+ case SIGBOOST_EVENT_CALL_STOPPED:
+ case SIGBOOST_EVENT_CALL_PROGRESS:
+ case SIGBOOST_EVENT_CALL_ANSWERED:
+ case SIGBOOST_EVENT_CALL_STOPPED_ACK:
+ case SIGBOOST_EVENT_DIGIT_IN:
+ case SIGBOOST_EVENT_INSERT_CHECK_LOOP:
+ case SIGBOOST_EVENT_REMOVE_CHECK_LOOP:
+ if (!(zchan = find_zchan(span, (sangomabc_short_event_t*)event, 1))) {
+ zap_log(ZAP_LOG_DEBUG, "PROCESS STATES CANT FIND CHAN %d:%d\n", event->span+1,event->chan+1);
+ return NULL;
+ }
+ break;
+ case SIGBOOST_EVENT_HEARTBEAT:
+ case SIGBOOST_EVENT_SYSTEM_RESTART_ACK:
+ case SIGBOOST_EVENT_SYSTEM_RESTART:
+ case SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE:
+ return NULL;
+ default:
+ zap_log(ZAP_LOG_CRIT, "Unhandled event id:%d\n", event->event_id);
+ return NULL;
+ }
+
+ zap_mutex_lock(zchan->mutex);
+ advance_chan_states(zchan);
+ return zchan;
+}
+
+/**
+ * \brief Handler for sangoma boost event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static int parse_sangoma_event(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+ zap_channel_t* zchan = NULL;
+
+ if (!zap_running()) {
+ zap_log(ZAP_LOG_WARNING, "System is shutting down.\n");
+ goto end;
+ }
+
+ assert(event->call_setup_id <= MAX_REQ_ID);
+
+ /* process all pending state changes for that channel before
+ processing the new boost event */
+ zchan = event_process_states(span, event);
+
+ switch(event->event_id) {
+ case SIGBOOST_EVENT_CALL_START:
+ handle_call_start(span, mcon, (sangomabc_event_t*)event);
+ break;
+ case SIGBOOST_EVENT_CALL_STOPPED:
+ handle_call_stop(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_START_ACK:
+ handle_call_start_ack(mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_PROGRESS:
+ handle_call_progress(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_START_NACK:
+ handle_call_start_nack(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_ANSWERED:
+ handle_call_answer(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_HEARTBEAT:
+ handle_heartbeat(mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_STOPPED_ACK:
+ handle_call_done(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_START_NACK_ACK:
+ handle_call_done(span, mcon, event);
+ nack_map[event->call_setup_id] = 0;
+ break;
+ case SIGBOOST_EVENT_INSERT_CHECK_LOOP:
+ handle_call_loop_start(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_REMOVE_CHECK_LOOP:
+ handle_call_loop_stop(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_SYSTEM_RESTART_ACK:
+ handle_restart_ack(mcon, span, event);
+ break;
+ case SIGBOOST_EVENT_SYSTEM_RESTART:
+ handle_restart(mcon, span, event);
+ break;
+ case SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE:
+ //handle_gap_abate(event);
+ break;
+ case SIGBOOST_EVENT_DIGIT_IN:
+ handle_incoming_digit(mcon, span, (sangomabc_event_t*)event);
+ break;
+ default:
+ zap_log(ZAP_LOG_WARNING, "No handler implemented for [%s]\n", sangomabc_event_id_name(event->event_id));
+ break;
+ }
+
+ end:
+ if(zchan != NULL) {
+ advance_chan_states(zchan);
+ zap_mutex_unlock(zchan->mutex);
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Handler for channel state change
+ * \param zchan Channel to handle
+ */
+static __inline__ void state_advance(zap_channel_t *zchan)
+{
+
+ zap_sangoma_boost_data_t *sangoma_boost_data = zchan->span->signal_data;
+ sangomabc_connection_t *mcon = &sangoma_boost_data->mcon;
+ zap_sigmsg_t sig;
+ zap_status_t status;
+
+ zap_log(ZAP_LOG_DEBUG, "%d:%d STATE [%s]\n", zchan->span_id, zchan->chan_id, zap_channel_state2str(zchan->state));
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = zchan->chan_id;
+ sig.span_id = zchan->span_id;
+ sig.channel = zchan;
+
+ switch (zchan->state) {
+ case ZAP_CHANNEL_STATE_DOWN:
+ {
+ if (zap_test_sflag(zchan, SFLAG_FREE_REQ_ID)) {
+ release_request_id_span_chan(zchan->physical_span_id-1, zchan->physical_chan_id-1);
+ }
+
+ if (!zap_test_sflag(zchan, SFLAG_SENT_FINAL_MSG)) {
+ zap_set_sflag_locked(zchan, SFLAG_SENT_FINAL_MSG);
+
+ if (zchan->call_data && ((uint32_t)(intptr_t)zchan->call_data == SIGBOOST_EVENT_CALL_START_NACK)) {
+ sangomabc_exec_command(mcon,
+ zchan->physical_span_id-1,
+ zchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_START_NACK_ACK,
+ 0, 0);
+
+ } else {
+ sangomabc_exec_command(mcon,
+ zchan->physical_span_id-1,
+ zchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_STOPPED_ACK,
+ 0, 0);
+ }
+ }
+
+ if (zchan->extra_id) {
+ zchan->extra_id = 0;
+ }
+ zchan->sflags = 0;
+ zchan->call_data = NULL;
+ zap_channel_done(zchan);
+ }
+ break;
+ case ZAP_CHANNEL_STATE_PROGRESS_MEDIA:
+ {
+ if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ sig.event_id = ZAP_SIGEVENT_PROGRESS_MEDIA;
+ if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ } else {
+ if (!zap_test_sflag(zchan, SFLAG_SENT_ACK)) {
+ zap_set_sflag(zchan, SFLAG_SENT_ACK);
+ sangomabc_exec_command(mcon,
+ zchan->physical_span_id-1,
+ zchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_START_ACK,
+ 0,
+ SIGBOOST_PROGRESS_MEDIA);
+ }
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_PROGRESS:
+ {
+ if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ sig.event_id = ZAP_SIGEVENT_PROGRESS;
+ if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ } else {
+ if (!zap_test_sflag(zchan, SFLAG_SENT_ACK)) {
+ zap_set_sflag(zchan, SFLAG_SENT_ACK);
+ sangomabc_exec_command(mcon,
+ zchan->physical_span_id-1,
+ zchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_START_ACK,
+ 0,
+ SIGBOOST_PROGRESS_RING);
+ }
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_IDLE:
+ case ZAP_CHANNEL_STATE_HOLD:
+ /* twiddle */
+ break;
+ case ZAP_CHANNEL_STATE_RING:
+ {
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ sig.event_id = ZAP_SIGEVENT_START;
+ if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_RESTART:
+ {
+ sig.event_id = ZAP_SIGEVENT_RESTART;
+ status = zap_span_send_signal(zchan->span, &sig);
+ zap_set_sflag_locked(zchan, SFLAG_SENT_FINAL_MSG);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ }
+ break;
+ case ZAP_CHANNEL_STATE_UP:
+ {
+ if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ sig.event_id = ZAP_SIGEVENT_UP;
+ if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ } else {
+ if (!(zap_test_flag(zchan, ZAP_CHANNEL_PROGRESS) || zap_test_flag(zchan, ZAP_CHANNEL_MEDIA))) {
+ sangomabc_exec_command(mcon,
+ zchan->physical_span_id-1,
+ zchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_START_ACK,
+ 0, 0);
+ }
+
+ sangomabc_exec_command(mcon,
+ zchan->physical_span_id-1,
+ zchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_ANSWERED,
+ 0, 0);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_DIALING:
+ {
+ }
+ break;
+ case ZAP_CHANNEL_STATE_HANGUP_COMPLETE:
+ {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ }
+ break;
+ case ZAP_CHANNEL_STATE_HANGUP:
+ {
+ zap_set_sflag_locked(zchan, SFLAG_HANGUP);
+
+ if (zap_test_sflag(zchan, SFLAG_SENT_FINAL_MSG) || zap_test_sflag(zchan, SFLAG_TERMINATING)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP_COMPLETE);
+ } else {
+ zap_set_sflag_locked(zchan, SFLAG_SENT_FINAL_MSG);
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_ANSWERED) ||
+ zap_test_flag(zchan, ZAP_CHANNEL_PROGRESS) ||
+ zap_test_flag(zchan, ZAP_CHANNEL_MEDIA) || zap_test_sflag(zchan, SFLAG_RECVD_ACK)) {
+
+ sangomabc_exec_command(mcon,
+ zchan->physical_span_id-1,
+ zchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_STOPPED,
+ zchan->caller_data.hangup_cause, 0);
+ } else {
+ sangomabc_exec_command(mcon,
+ zchan->physical_span_id-1,
+ zchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_START_NACK,
+ zchan->caller_data.hangup_cause, 0);
+ }
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_TERMINATING:
+ {
+ zap_set_sflag_locked(zchan, SFLAG_TERMINATING);
+ sig.event_id = ZAP_SIGEVENT_STOP;
+ status = zap_span_send_signal(zchan->span, &sig);
+ }
+ break;
+ case ZAP_CHANNEL_STATE_IN_LOOP:
+ {
+ /* nothing to do, we sent the ZAP_COMMAND_ENABLE_LOOP command in handle_call_loop_start() right away */
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static __inline__ void advance_chan_states(zap_channel_t *zchan)
+{
+ while (zap_test_flag(zchan, ZAP_CHANNEL_STATE_CHANGE)) {
+ zap_clear_flag(zchan, ZAP_CHANNEL_STATE_CHANGE);
+ state_advance(zchan);
+ zap_channel_complete_state(zchan);
+ }
+}
+
+/**
+ * \brief Initialises outgoing requests array
+ */
+static __inline__ void init_outgoing_array(void)
+{
+ memset(&OUTBOUND_REQUESTS, 0, sizeof(OUTBOUND_REQUESTS));
+
+}
+
+/**
+ * \brief Checks current state on a span
+ * \param span Span to check status on
+ */
+static __inline__ void check_state(zap_span_t *span)
+{
+ zap_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+ int susp = zap_test_flag(span, ZAP_SPAN_SUSPENDED);
+
+ if (susp && zap_check_state_all(span, ZAP_CHANNEL_STATE_DOWN)) {
+ susp = 0;
+ }
+
+ if (zap_test_flag(span, ZAP_SPAN_STATE_CHANGE) || susp) {
+ uint32_t j;
+ zap_clear_flag_locked(span, ZAP_SPAN_STATE_CHANGE);
+ for(j = 1; j <= span->chan_count; j++) {
+ if (zap_test_flag((span->channels[j]), ZAP_CHANNEL_STATE_CHANGE) || susp) {
+ zap_mutex_lock(span->channels[j]->mutex);
+ zap_clear_flag((span->channels[j]), ZAP_CHANNEL_STATE_CHANGE);
+ if (susp && span->channels[j]->state != ZAP_CHANNEL_STATE_DOWN) {
+ zap_channel_set_state(span->channels[j], ZAP_CHANNEL_STATE_RESTART, 0);
+ }
+ state_advance(span->channels[j]);
+ zap_channel_complete_state(span->channels[j]);
+ zap_mutex_unlock(span->channels[j]->mutex);
+ }
+ }
+ }
+
+ if (zap_test_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RESTARTING)) {
+ if (zap_check_state_all(span, ZAP_CHANNEL_STATE_DOWN)) {
+ sangomabc_exec_command(&sangoma_boost_data->mcon,
+ 0,
+ 0,
+ -1,
+ SIGBOOST_EVENT_SYSTEM_RESTART_ACK,
+ 0, 0);
+ zap_clear_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RESTARTING);
+ zap_clear_flag_locked(span, ZAP_SPAN_SUSPENDED);
+ zap_clear_flag((&sangoma_boost_data->mcon), MSU_FLAG_DOWN);
+ sangoma_boost_data->mcon.hb_elapsed = 0;
+ init_outgoing_array();
+ }
+ }
+}
+
+
+/**
+ * \brief Checks for events on a span
+ * \param span Span to check for events
+ */
+static __inline__ void check_events(zap_span_t *span, int ms_timeout)
+{
+ zap_status_t status;
+
+ status = zap_span_poll_event(span, ms_timeout);
+
+ switch(status) {
+ case ZAP_SUCCESS:
+ {
+ zap_event_t *event;
+ while (zap_span_next_event(span, &event) == ZAP_SUCCESS) {
+ // for now we do nothing with events, this is here
+ // just to have the hardware layer to get any HW DTMF
+ // events and enqueue the DTMF on the channel (done during zap_span_next_event())
+ }
+ }
+ break;
+ case ZAP_FAIL:
+ {
+ zap_log(ZAP_LOG_DEBUG, "Boost Check Event Failure Failure! %d\n", zap_running());
+ }
+ break;
+ default:
+ break;
+ }
+
+ return;
+}
+
+/**
+ * \brief Main thread function for sangoma boost span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *zap_sangoma_events_run(zap_thread_t *me, void *obj)
+{
+ zap_span_t *span = (zap_span_t *) obj;
+ zap_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+
+ while (zap_test_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RUNNING) && zap_running()) {
+ check_events(span,100);
+ }
+
+ return NULL;
+}
+
+/**
+ * \brief Main thread function for sangoma boost span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *zap_sangoma_boost_run(zap_thread_t *me, void *obj)
+{
+ zap_span_t *span = (zap_span_t *) obj;
+ zap_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+ sangomabc_connection_t *mcon, *pcon;
+ uint32_t ms = 10; //, too_long = 20000;
+
+
+ sangoma_boost_data->pcon = sangoma_boost_data->mcon;
+
+ if (sangomabc_connection_open(&sangoma_boost_data->mcon,
+ sangoma_boost_data->mcon.cfg.local_ip,
+ sangoma_boost_data->mcon.cfg.local_port,
+ sangoma_boost_data->mcon.cfg.remote_ip,
+ sangoma_boost_data->mcon.cfg.remote_port) < 0) {
+ zap_log(ZAP_LOG_ERROR, "Error: Opening MCON Socket [%d] %s\n", sangoma_boost_data->mcon.socket, strerror(errno));
+ goto end;
+ }
+
+ if (sangomabc_connection_open(&sangoma_boost_data->pcon,
+ sangoma_boost_data->pcon.cfg.local_ip,
+ ++sangoma_boost_data->pcon.cfg.local_port,
+ sangoma_boost_data->pcon.cfg.remote_ip,
+ ++sangoma_boost_data->pcon.cfg.remote_port) < 0) {
+ zap_log(ZAP_LOG_ERROR, "Error: Opening PCON Socket [%d] %s\n", sangoma_boost_data->pcon.socket, strerror(errno));
+ goto end;
+ }
+
+ mcon = &sangoma_boost_data->mcon;
+ pcon = &sangoma_boost_data->pcon;
+
+ init_outgoing_array();
+
+ sangomabc_exec_commandp(pcon,
+ 0,
+ 0,
+ -1,
+ SIGBOOST_EVENT_SYSTEM_RESTART,
+ 0);
+ zap_set_flag(mcon, MSU_FLAG_DOWN);
+
+ while (zap_test_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RUNNING)) {
+ fd_set rfds, efds;
+ struct timeval tv = { 0, ms * 1000 };
+ int max, activity, i = 0;
+ sangomabc_event_t *event = NULL;
+
+ if (!zap_running()) {
+ sangomabc_exec_commandp(pcon,
+ 0,
+ 0,
+ -1,
+ SIGBOOST_EVENT_SYSTEM_RESTART,
+ 0);
+ zap_set_flag(mcon, MSU_FLAG_DOWN);
+ break;
+ }
+
+ FD_ZERO(&rfds);
+ FD_ZERO(&efds);
+ FD_SET(mcon->socket, &rfds);
+ FD_SET(mcon->socket, &efds);
+ FD_SET(pcon->socket, &rfds);
+ FD_SET(pcon->socket, &efds);
+
+ max = ((pcon->socket > mcon->socket) ? pcon->socket : mcon->socket) + 1;
+
+ if ((activity = select(max, &rfds, NULL, &efds, &tv)) < 0) {
+ goto error;
+ }
+
+ if (activity) {
+ if (FD_ISSET(pcon->socket, &efds) || FD_ISSET(mcon->socket, &efds)) {
+ goto error;
+ }
+
+ if (FD_ISSET(pcon->socket, &rfds)) {
+ while ((event = sangomabc_connection_readp(pcon, i))) {
+ parse_sangoma_event(span, pcon, (sangomabc_short_event_t*)event);
+ i++;
+ }
+ }
+ i=0;
+
+ if (FD_ISSET(mcon->socket, &rfds)) {
+ if ((event = sangomabc_connection_read(mcon, i))) {
+ parse_sangoma_event(span, mcon, (sangomabc_short_event_t*)event);
+ i++;
+ }
+ }
+
+ }
+
+
+ pcon->hb_elapsed += ms;
+
+ if (zap_test_flag(span, ZAP_SPAN_SUSPENDED) || zap_test_flag(mcon, MSU_FLAG_DOWN)) {
+ pcon->hb_elapsed = 0;
+ }
+
+
+#if 0
+ if (pcon->hb_elapsed >= too_long) {
+ zap_log(ZAP_LOG_CRIT, "Lost Heartbeat!\n");
+ zap_set_flag_locked(span, ZAP_SPAN_SUSPENDED);
+ zap_set_flag(mcon, MSU_FLAG_DOWN);
+ sangomabc_exec_commandp(pcon,
+ 0,
+ 0,
+ -1,
+ SIGBOOST_EVENT_SYSTEM_RESTART,
+ 0);
+ }
+#endif
+
+ if (zap_running()) {
+ check_state(span);
+ }
+ }
+
+ goto end;
+
+ error:
+ zap_log(ZAP_LOG_CRIT, "Socket Error!\n");
+
+ end:
+
+ sangomabc_connection_close(&sangoma_boost_data->mcon);
+ sangomabc_connection_close(&sangoma_boost_data->pcon);
+
+ zap_clear_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RUNNING);
+
+ zap_log(ZAP_LOG_DEBUG, "SANGOMA_BOOST thread ended.\n");
+ return NULL;
+}
+
+/**
+ * \brief Loads sangoma boost signaling module
+ * \param zio Openzap IO interface
+ * \return Success
+ */
+static ZIO_SIG_LOAD_FUNCTION(zap_sangoma_boost_init)
+{
+ zap_mutex_create(&request_mutex);
+
+ return ZAP_SUCCESS;
+}
+
+static zap_status_t zap_sangoma_boost_start(zap_span_t *span)
+{
+ int err;
+ zap_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+ zap_set_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RUNNING);
+ err=zap_thread_create_detached(zap_sangoma_boost_run, span);
+ if (err) {
+ zap_clear_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RUNNING);
+ return err;
+ }
+ // launch the events thread to handle HW DTMF and possibly
+ // other events in the future
+ err=zap_thread_create_detached(zap_sangoma_events_run, span);
+ if (err) {
+ zap_clear_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RUNNING);
+ }
+ return err;
+}
+
+static zap_state_map_t boost_state_map = {
+ {
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_ANY_STATE},
+ {ZAP_CHANNEL_STATE_RESTART, ZAP_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_RESTART, ZAP_END},
+ {ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+ {ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_IDLE, ZAP_CHANNEL_STATE_HOLD, ZAP_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_HOLD, ZAP_END},
+ {ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_PROGRESS,
+ ZAP_CHANNEL_STATE_IDLE, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_UP, ZAP_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_IDLE, ZAP_END},
+ {ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_PROGRESS, ZAP_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_IDLE, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_UP, ZAP_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_CHANNEL_STATE_HANGUP, ZAP_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_END},
+ {ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_UP, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END}
+ },
+
+ /****************************************/
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_ANY_STATE},
+ {ZAP_CHANNEL_STATE_RESTART, ZAP_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_RESTART, ZAP_END},
+ {ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_DOWN},
+ {ZAP_CHANNEL_STATE_IN_LOOP, ZAP_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_IN_LOOP},
+ {ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+ {ZAP_CHANNEL_STATE_RING, ZAP_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_RING, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_PROGRESS_MEDIA,ZAP_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_CHANNEL_STATE_HANGUP, ZAP_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+ {ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_UP, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {ZAP_CHANNEL_STATE_UP, ZAP_END},
+ {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+ },
+
+
+ }
+};
+
+/**
+ * \brief Initialises an sangoma boost span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static ZIO_SIG_CONFIGURE_FUNCTION(zap_sangoma_boost_configure_span)
+{
+ zap_sangoma_boost_data_t *sangoma_boost_data = NULL;
+ const char *local_ip = "127.0.0.65", *remote_ip = "127.0.0.66";
+ int local_port = 53000, remote_port = 53000;
+ char *var, *val;
+ int *intval;
+
+ while((var = va_arg(ap, char *))) {
+ if (!strcasecmp(var, "local_ip")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ local_ip = val;
+ } else if (!strcasecmp(var, "remote_ip")) {
+ if (!(val = va_arg(ap, char *))) {
+ break;
+ }
+ remote_ip = val;
+ } else if (!strcasecmp(var, "local_port")) {
+ if (!(intval = va_arg(ap, int *))) {
+ break;
+ }
+ local_port = *intval;
+ } else if (!strcasecmp(var, "remote_port")) {
+ if (!(intval = va_arg(ap, int *))) {
+ break;
+ }
+ remote_port = *intval;
+ } else {
+ snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+ return ZAP_FAIL;
+ }
+ }
+
+
+ if (!local_ip && local_port && remote_ip && remote_port && sig_cb) {
+ zap_set_string(span->last_error, "missing params");
+ return ZAP_FAIL;
+ }
+
+ sangoma_boost_data = malloc(sizeof(*sangoma_boost_data));
+ assert(sangoma_boost_data);
+ memset(sangoma_boost_data, 0, sizeof(*sangoma_boost_data));
+
+ zap_set_string(sangoma_boost_data->mcon.cfg.local_ip, local_ip);
+ sangoma_boost_data->mcon.cfg.local_port = local_port;
+ zap_set_string(sangoma_boost_data->mcon.cfg.remote_ip, remote_ip);
+ sangoma_boost_data->mcon.cfg.remote_port = remote_port;
+ span->signal_cb = sig_cb;
+ span->start = zap_sangoma_boost_start;
+ span->signal_data = sangoma_boost_data;
+ span->signal_type = ZAP_SIGTYPE_SANGOMABOOST;
+ span->outgoing_call = sangoma_boost_outgoing_call;
+ span->channel_request = sangoma_boost_channel_request;
+ span->state_map = &boost_state_map;
+ zap_set_flag_locked(span, ZAP_SPAN_SUSPENDED);
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Openzap sangoma boost signaling module definition
+ */
+zap_module_t zap_module = {
+ "sangoma_boost",
+ NULL,
+ NULL,
+ zap_sangoma_boost_init,
+ zap_sangoma_boost_configure_span,
+ NULL
+};
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ * 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.
+ */
+
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include "openzap.h"
+#include <sangoma_boost_client.h>
+
+#ifndef HAVE_GETHOSTBYNAME_R
+extern int gethostbyname_r (const char *__name,
+ struct hostent *__result_buf,
+ char *__buf, size_t __buflen,
+ struct hostent **__result,
+ int *__h_errnop);
+#endif
+
+struct sangomabc_map {
+ uint32_t event_id;
+ const char *name;
+};
+
+static struct sangomabc_map sangomabc_table[] = {
+ {SIGBOOST_EVENT_CALL_START, "CALL_START"},
+ {SIGBOOST_EVENT_CALL_START_ACK, "CALL_START_ACK"},
+ {SIGBOOST_EVENT_CALL_START_NACK, "CALL_START_NACK"},
+ {SIGBOOST_EVENT_CALL_PROGRESS, "CALL PROGRESS"},
+ {SIGBOOST_EVENT_CALL_START_NACK_ACK, "CALL_START_NACK_ACK"},
+ {SIGBOOST_EVENT_CALL_ANSWERED, "CALL_ANSWERED"},
+ {SIGBOOST_EVENT_CALL_STOPPED, "CALL_STOPPED"},
+ {SIGBOOST_EVENT_CALL_STOPPED_ACK, "CALL_STOPPED_ACK"},
+ {SIGBOOST_EVENT_SYSTEM_RESTART, "SYSTEM_RESTART"},
+ {SIGBOOST_EVENT_SYSTEM_RESTART_ACK, "SYSTEM_RESTART_ACK"},
+ {SIGBOOST_EVENT_HEARTBEAT, "HEARTBEAT"},
+ {SIGBOOST_EVENT_INSERT_CHECK_LOOP, "LOOP START"},
+ {SIGBOOST_EVENT_REMOVE_CHECK_LOOP, "LOOP STOP"},
+ {SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE, "AUTO_CALL_GAP_ABATE"},
+ {SIGBOOST_EVENT_DIGIT_IN, "DIGIT_IN"}
+};
+
+
+
+static void sangomabc_print_event_call(sangomabc_connection_t *mcon, sangomabc_event_t *event, int priority, int dir, const char *file, const char *func, int line)
+{
+ if (event->event_id == SIGBOOST_EVENT_HEARTBEAT)
+ return;
+
+ zap_log(file, func, line, ZAP_LOG_LEVEL_WARNING, "%s EVENT: %s:(%X) [w%dg%d] CSid=%i Seq=%i Cn=[%s] Cd=[%s] Ci=[%s] Rdnis=[%s]\n",
+ dir ? "TX":"RX",
+ sangomabc_event_id_name(event->event_id),
+ event->event_id,
+ event->span+1,
+ event->chan+1,
+ event->call_setup_id,
+ event->fseqno,
+ strlen(event->calling_name)?event->calling_name:"N/A",
+ (event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
+ (event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A"),
+ event->isup_in_rdnis);
+
+}
+static void sangomabc_print_event_short(sangomabc_connection_t *mcon, sangomabc_short_event_t *event, int priority, int dir, const char *file, const char *func, int line)
+{
+ if (event->event_id == SIGBOOST_EVENT_HEARTBEAT)
+ return;
+ zap_log(file, func, line, ZAP_LOG_LEVEL_WARNING, "%s EVENT (%s): %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i \n",
+ dir ? "TX":"RX",
+ priority ? "P":"N",
+ sangomabc_event_id_name(event->event_id),
+ event->event_id,
+ event->span+1,
+ event->chan+1,
+ event->release_cause,
+ event->call_setup_id,
+ event->fseqno);
+}
+
+
+static int create_conn_socket(sangomabc_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
+{
+ int rc;
+ struct hostent *result, *local_result;
+ char buf[512], local_buf[512];
+ int err = 0, local_err = 0;
+
+ memset(&mcon->remote_hp, 0, sizeof(mcon->remote_hp));
+ memset(&mcon->local_hp, 0, sizeof(mcon->local_hp));
+#ifdef HAVE_NETINET_SCTP_H
+ zap_log(ZAP_LOG_DEBUG, "Creating SCTP socket L=%s:%d R=%s:%d\n",
+ local_ip, local_port, ip, port);
+ mcon->socket = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+#else
+ zap_log(ZAP_LOG_DEBUG, "Creating UDP socket L=%s:%d R=%s:%d\n",
+ local_ip, local_port, ip, port);
+ mcon->socket = socket(AF_INET, SOCK_DGRAM, 0);
+#endif
+
+ if (mcon->socket >= 0) {
+ int flag;
+
+ flag = 1;
+#ifdef HAVE_GETHOSTBYNAME_R_FIVE
+ gethostbyname_r(ip, &mcon->remote_hp, buf, sizeof(buf), &err);
+ gethostbyname_r(local_ip, &mcon->local_hp, local_buf, sizeof(local_buf), &local_err);
+ if (!err && !local_err) {
+#else
+ gethostbyname_r(ip, &mcon->remote_hp, buf, sizeof(buf), &result, &err);
+ gethostbyname_r(local_ip, &mcon->local_hp, local_buf, sizeof(local_buf), &local_result, &local_err);
+ if (result && local_result) {
+#endif
+ mcon->remote_addr.sin_family = mcon->remote_hp.h_addrtype;
+ memcpy((char *) &mcon->remote_addr.sin_addr.s_addr, mcon->remote_hp.h_addr_list[0], mcon->remote_hp.h_length);
+ mcon->remote_addr.sin_port = htons(port);
+
+ mcon->local_addr.sin_family = mcon->local_hp.h_addrtype;
+ memcpy((char *) &mcon->local_addr.sin_addr.s_addr, mcon->local_hp.h_addr_list[0], mcon->local_hp.h_length);
+ mcon->local_addr.sin_port = htons(local_port);
+
+#ifdef HAVE_NETINET_SCTP_H
+ setsockopt(mcon->socket, IPPROTO_SCTP, SCTP_NODELAY,
+ (char *)&flag, sizeof(int));
+#endif
+
+ if ((rc = bind(mcon->socket,
+ (struct sockaddr *) &mcon->local_addr,
+ sizeof(mcon->local_addr))) < 0) {
+ close(mcon->socket);
+ mcon->socket = -1;
+ } else {
+#ifdef HAVE_NETINET_SCTP_H
+ rc=listen(mcon->socket, 100);
+ if (rc) {
+ close(mcon->socket);
+ mcon->socket = -1;
+ }
+#endif
+ }
+ }
+ }
+
+ zap_mutex_create(&mcon->mutex);
+
+ return mcon->socket;
+}
+
+int sangomabc_connection_close(sangomabc_connection_t *mcon)
+{
+ if (mcon->socket > -1) {
+ close(mcon->socket);
+ }
+
+ if (mcon->mutex) {
+ zap_mutex_lock(mcon->mutex);
+ zap_mutex_unlock(mcon->mutex);
+ zap_mutex_destroy(&mcon->mutex);
+ }
+ memset(mcon, 0, sizeof(*mcon));
+ mcon->socket = -1;
+
+ return 0;
+}
+
+int sangomabc_connection_open(sangomabc_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
+{
+ create_conn_socket(mcon, local_ip, local_port, ip, port);
+ return mcon->socket;
+}
+
+
+int sangomabc_exec_command(sangomabc_connection_t *mcon, int span, int chan, int id, int cmd, int cause, int flags)
+{
+ sangomabc_short_event_t oevent;
+ int retry = 5;
+
+ sangomabc_event_init(&oevent, cmd, chan, span);
+ oevent.release_cause = cause;
+ oevent.flags = flags;
+
+ if (cmd == SIGBOOST_EVENT_SYSTEM_RESTART || cmd == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
+ mcon->rxseq_reset = 1;
+ mcon->txseq = 0;
+ mcon->rxseq = 0;
+ mcon->txwindow = 0;
+ }
+
+ if (id >= 0) {
+ oevent.call_setup_id = id;
+ }
+
+ while (sangomabc_connection_write(mcon, (sangomabc_event_t*)&oevent) <= 0) {
+ if (--retry <= 0) {
+ zap_log(ZAP_LOG_CRIT, "Failed to tx on ISUP socket: %s\n", strerror(errno));
+ return -1;
+ } else {
+ zap_log(ZAP_LOG_WARNING, "Failed to tx on ISUP socket: %s :retry %i\n", strerror(errno), retry);
+ zap_sleep(1);
+ }
+ }
+
+ return 0;
+}
+
+
+int sangomabc_exec_commandp(sangomabc_connection_t *pcon, int span, int chan, int id, int cmd, int cause)
+{
+ sangomabc_short_event_t oevent;
+ int retry = 5;
+
+ sangomabc_event_init(&oevent, cmd, chan, span);
+ oevent.release_cause = cause;
+
+ if (id >= 0) {
+ oevent.call_setup_id = id;
+ }
+
+ while (sangomabc_connection_writep(pcon, (sangomabc_event_t*)&oevent) <= 0) {
+ if (--retry <= 0) {
+ zap_log(ZAP_LOG_CRIT, "Failed to tx on ISUP socket: %s\n", strerror(errno));
+ return -1;
+ } else {
+ zap_log(ZAP_LOG_WARNING, "Failed to tx on ISUP socket: %s :retry %i\n", strerror(errno), retry);
+ zap_sleep(1);
+ }
+ }
+
+ return 0;
+}
+
+sangomabc_event_t *__sangomabc_connection_read(sangomabc_connection_t *mcon, int iteration, const char *file, const char *func, int line)
+{
+ unsigned int fromlen = sizeof(struct sockaddr_in);
+ int bytes = 0;
+ int msg_ok = 0;
+
+ bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT,
+ (struct sockaddr *) &mcon->local_addr, &fromlen);
+
+ if (bytes <= 0) {
+ return NULL;
+ }
+
+ if (mcon->event.version != SIGBOOST_VERSION) {
+ zap_log(ZAP_LOG_CRIT, "Invalid Boost Version %i Expecting %i\n",mcon->event.version, SIGBOOST_VERSION);
+ }
+
+ /* Must check for < 0 cannot rely on bytes > MIN_SIZE_... compiler issue */
+ if (bytes < 0) {
+ msg_ok=0;
+
+ } else if ((bytes >= MIN_SIZE_CALLSTART_MSG) && boost_full_event(mcon->event.event_id)) {
+ msg_ok=1;
+
+ } else if (bytes == sizeof(sangomabc_short_event_t)) {
+ msg_ok=1;
+
+ } else {
+ msg_ok=0;
+ }
+
+ if (msg_ok){
+
+ if (sangomabc_test_flag(mcon, MSU_FLAG_DOWN)) {
+ if (mcon->event.event_id != SIGBOOST_EVENT_SYSTEM_RESTART &&
+ mcon->event.event_id != SIGBOOST_EVENT_SYSTEM_RESTART_ACK &&
+ mcon->event.event_id != SIGBOOST_EVENT_HEARTBEAT) {
+ zap_log(file, func, line, ZAP_LOG_LEVEL_WARNING, "Not reading packets when connection is down. [%s]\n",
+ sangomabc_event_id_name(mcon->event.event_id));
+ return NULL;
+ }
+ }
+
+ if (boost_full_event(mcon->event.event_id)) {
+ sangomabc_print_event_call(mcon, &mcon->event, 0, 0, file, func, line);
+ } else {
+ sangomabc_print_event_short(mcon, (sangomabc_short_event_t*)&mcon->event, 0, 0, file, func, line);
+ }
+
+#if 0
+/* NC: NOT USED ANY MORE */
+ if (mcon->rxseq_reset) {
+ //if (mcon->event.event_id == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
+ zap_log(ZAP_LOG_DEBUG, "Rx sync ok\n");
+ mcon->rxseq = mcon->event.fseqno;
+ return &mcon->event;
+ //}
+ errno=EAGAIN;
+ zap_log(ZAP_LOG_DEBUG, "Waiting for rx sync...\n");
+ return NULL;
+ }
+#endif
+
+ mcon->txwindow = mcon->txseq - mcon->event.bseqno;
+ mcon->rxseq++;
+
+#if 0
+ if (mcon->rxseq != mcon->event.fseqno) {
+ zap_log(ZAP_LOG_CRIT, "Invalid Sequence Number Expect=%i Rx=%i\n", mcon->rxseq, mcon->event.fseqno);
+ return NULL;
+ }
+#endif
+
+ return &mcon->event;
+ } else {
+ if (iteration == 0) {
+ zap_log(ZAP_LOG_CRIT, "NC - Invalid Event length from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+sangomabc_event_t *__sangomabc_connection_readp(sangomabc_connection_t *mcon, int iteration, const char *file, const char *func, int line)
+{
+ unsigned int fromlen = sizeof(struct sockaddr_in);
+ int bytes = 0;
+
+ bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT, (struct sockaddr *) &mcon->local_addr, &fromlen);
+
+ if (bytes <= 0) {
+ return NULL;
+ }
+
+ if (mcon->event.version != SIGBOOST_VERSION) {
+ zap_log(ZAP_LOG_CRIT, "Invalid Boost Version %i Expecting %i\n",mcon->event.version, SIGBOOST_VERSION);
+ }
+
+ if (bytes == sizeof(sangomabc_short_event_t)) {
+
+ if (boost_full_event(mcon->event.event_id)) {
+ sangomabc_print_event_call(mcon, &mcon->event, 1, 0, file, func, line);
+ } else {
+ sangomabc_print_event_short(mcon, (sangomabc_short_event_t*)&mcon->event, 1, 0, file, func, line);
+ }
+
+ return &mcon->event;
+ } else {
+ if (iteration == 0) {
+ zap_log(ZAP_LOG_CRIT, "Critical Error: PQ Invalid Event lenght from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+
+int __sangomabc_connection_write(sangomabc_connection_t *mcon, sangomabc_event_t *event, const char *file, const char *func, int line)
+{
+ int err;
+ int event_size=MIN_SIZE_CALLSTART_MSG+event->isup_in_rdnis_size;
+
+ if (!event || mcon->socket < 0 || !mcon->mutex) {
+ zap_log(file, func, line, ZAP_LOG_LEVEL_CRIT, "Critical Error: No Event Device\n");
+ return -EINVAL;
+ abort();
+ }
+
+ if (event->span >= ZAP_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN || event->chan >= ZAP_MAX_CHANNELS_PHYSICAL_SPAN ) {
+ zap_log(file, func, line, ZAP_LOG_LEVEL_CRIT, "Critical Error: TX Cmd=%s Invalid Span=%i Chan=%i\n", sangomabc_event_id_name(event->event_id), event->span, event->chan);
+ abort();
+ return -1;
+ }
+
+ if (!boost_full_event(event->event_id)) {
+ event_size=sizeof(sangomabc_short_event_t);
+ }
+
+ if (sangomabc_test_flag(mcon, MSU_FLAG_DOWN)) {
+ if (event->event_id != SIGBOOST_EVENT_SYSTEM_RESTART &&
+ event->event_id != SIGBOOST_EVENT_SYSTEM_RESTART_ACK &&
+ event->event_id != SIGBOOST_EVENT_HEARTBEAT) {
+ zap_log(file, func, line, ZAP_LOG_LEVEL_WARNING, "Not writing packets when connection is down. [%s]\n",
+ sangomabc_event_id_name(event->event_id));
+ return 0;
+ }
+ }
+
+ zap_mutex_lock(mcon->mutex);
+ if (event->event_id == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
+ mcon->txseq=0;
+ mcon->rxseq=0;
+ event->fseqno=0;
+ } else {
+ event->fseqno = mcon->txseq++;
+ }
+ event->bseqno = mcon->rxseq;
+ event->version = SIGBOOST_VERSION;
+ err = sendto(mcon->socket, event, event_size, 0, (struct sockaddr *) &mcon->remote_addr, sizeof(mcon->remote_addr));
+
+ zap_mutex_unlock(mcon->mutex);
+
+ if (err != event_size) {
+ err = -1;
+ abort();
+ }
+
+ if (boost_full_event(event->event_id)) {
+ sangomabc_print_event_call(mcon, event, 0, 1, file, func, line);
+ } else {
+ sangomabc_print_event_short(mcon, (sangomabc_short_event_t*)event, 0, 1, file, func, line);
+ }
+
+ return err;
+}
+
+
+int __sangomabc_connection_writep(sangomabc_connection_t *mcon, sangomabc_event_t *event, const char *file, const char *func, int line)
+{
+ int err;
+ int event_size=sizeof(sangomabc_event_t);
+
+ if (!event || mcon->socket < 0 || !mcon->mutex) {
+ zap_log(file, func, line, ZAP_LOG_LEVEL_CRIT, "Critical Error: No Event Device\n");
+ return -EINVAL;
+ abort();
+ }
+
+ if (!boost_full_event(event->event_id)) {
+ event_size=sizeof(sangomabc_short_event_t);
+ }
+
+ zap_mutex_lock(mcon->mutex);
+ event->version = SIGBOOST_VERSION;
+ err = sendto(mcon->socket, event, event_size, 0, (struct sockaddr *) &mcon->remote_addr, sizeof(mcon->remote_addr));
+ zap_mutex_unlock(mcon->mutex);
+
+ if (err != event_size) {
+ err = -1;
+ abort();
+ }
+
+ if (boost_full_event(event->event_id)) {
+ sangomabc_print_event_call(mcon, event, 1, 1, file, func, line);
+ } else {
+ sangomabc_print_event_short(mcon, (sangomabc_short_event_t*)event, 1, 1, file, func, line);
+ }
+
+ return err;
+}
+
+
+void sangomabc_call_init(sangomabc_event_t *event, const char *calling, const char *called, int setup_id)
+{
+ memset(event, 0, sizeof(sangomabc_event_t));
+ event->event_id = SIGBOOST_EVENT_CALL_START;
+
+ if (calling) {
+ strncpy((char*)event->calling_number_digits, calling, sizeof(event->calling_number_digits)-1);
+ event->calling_number_digits_count = strlen(calling);
+ }
+
+ if (called) {
+ strncpy((char*)event->called_number_digits, called, sizeof(event->called_number_digits)-1);
+ event->called_number_digits_count = strlen(called);
+ }
+
+ event->call_setup_id = setup_id;
+
+}
+
+void sangomabc_event_init(sangomabc_short_event_t *event, sangomabc_event_id_t event_id, int chan, int span)
+{
+ memset(event, 0, sizeof(sangomabc_short_event_t));
+ event->event_id = event_id;
+ event->chan = chan;
+ event->span = span;
+}
+
+const char *sangomabc_event_id_name(uint32_t event_id)
+{
+ unsigned int x;
+ const char *ret = NULL;
+
+ for (x = 0 ; x < sizeof(sangomabc_table)/sizeof(struct sangomabc_map); x++) {
+ if (sangomabc_table[x].event_id == event_id) {
+ ret = sangomabc_table[x].name;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ * 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.
+ */
+
+#ifndef _SANGOMABC_H
+#define _SANGOMABC_H
+
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifdef HAVE_NETINET_SCTP_H
+#include <netinet/sctp.h>
+#endif
+#include <arpa/inet.h>
+#include <stdarg.h>
+#include <netdb.h>
+#include <sigboost.h>
+#include <sys/time.h>
+
+#define sangomabc_test_flag(p,flag) ({ \
+ ((p)->flags & (flag)); \
+ })
+
+#define sangomabc_set_flag(p,flag) do { \
+ ((p)->flags |= (flag)); \
+ } while (0)
+
+#define sangomabc_clear_flag(p,flag) do { \
+ ((p)->flags &= ~(flag)); \
+ } while (0)
+
+#define sangomabc_copy_flags(dest,src,flagz) do { \
+ (dest)->flags &= ~(flagz); \
+ (dest)->flags |= ((src)->flags & (flagz)); \
+ } while (0)
+
+typedef t_sigboost_callstart sangomabc_event_t;
+typedef t_sigboost_short sangomabc_short_event_t;
+typedef uint32_t sangomabc_event_id_t;
+
+typedef struct sangomabc_ip_cfg
+{
+ char local_ip[25];
+ int local_port;
+ char remote_ip[25];
+ int remote_port;
+}sangomabc_ip_cfg_t;
+
+typedef enum {
+ MSU_FLAG_EVENT = (1 << 0),
+ MSU_FLAG_DOWN = (1 << 1)
+} sangomabc_flag_t;
+
+
+struct sangomabc_connection {
+ zap_socket_t socket;
+ struct sockaddr_in local_addr;
+ struct sockaddr_in remote_addr;
+ sangomabc_event_t event;
+ struct hostent remote_hp;
+ struct hostent local_hp;
+ unsigned int flags;
+ zap_mutex_t *mutex;
+ FILE *log;
+ unsigned int txseq;
+ unsigned int rxseq;
+ unsigned int txwindow;
+ unsigned int rxseq_reset;
+ sangomabc_ip_cfg_t cfg;
+ uint32_t hb_elapsed;
+};
+
+typedef struct sangomabc_connection sangomabc_connection_t;
+
+/* disable nagle's algorythm */
+static inline void sctp_no_nagle(int socket)
+{
+#ifdef HAVE_NETINET_SCTP_H
+ int flag = 1;
+ setsockopt(socket, IPPROTO_SCTP, SCTP_NODELAY, (char *) &flag, sizeof(int));
+#endif
+}
+
+int sangomabc_connection_close(sangomabc_connection_t *mcon);
+int sangomabc_connection_open(sangomabc_connection_t *mcon, char *local_ip, int local_port, char *ip, int port);
+sangomabc_event_t *__sangomabc_connection_read(sangomabc_connection_t *mcon, int iteration, const char *file, const char *func, int line);
+sangomabc_event_t *__sangomabc_connection_readp(sangomabc_connection_t *mcon, int iteration, const char *file, const char *func, int line);
+int __sangomabc_connection_write(sangomabc_connection_t *mcon, sangomabc_event_t *event, const char *file, const char *func, int line);
+int __sangomabc_connection_writep(sangomabc_connection_t *mcon, sangomabc_event_t *event, const char *file, const char *func, int line);
+#define sangomabc_connection_write(_m,_e) __sangomabc_connection_write(_m, _e, __FILE__, __func__, __LINE__)
+#define sangomabc_connection_writep(_m,_e) __sangomabc_connection_writep(_m, _e, __FILE__, __func__, __LINE__)
+#define sangomabc_connection_read(_m,_e) __sangomabc_connection_read(_m, _e, __FILE__, __func__, __LINE__)
+#define sangomabc_connection_readp(_m,_e) __sangomabc_connection_readp(_m, _e, __FILE__, __func__, __LINE__)
+void sangomabc_event_init(sangomabc_short_event_t *event, sangomabc_event_id_t event_id, int chan, int span);
+void sangomabc_call_init(sangomabc_event_t *event, const char *calling, const char *called, int setup_id);
+const char *sangomabc_event_id_name(uint32_t event_id);
+int sangomabc_exec_command(sangomabc_connection_t *mcon, int span, int chan, int id, int cmd, int cause, int flags);
+int sangomabc_exec_commandp(sangomabc_connection_t *pcon, int span, int chan, int id, int cmd, int cause);
+
+#endif
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sigboost.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sigboost.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sigboost.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,209 @@
+/****************************************************************************
+ * sigboost.h $Revision: 1.13 $
+ *
+ * Definitions for the sigboost interface.
+ *
+ * WARNING WARNING WARNING
+ *
+ * This file is used by sangoma_mgd and perhaps other programs. Any changes
+ * to this file must be coordinated with other user programs,
+ *
+ * Copyright (C) 2005 Xygnada Technology, Inc.
+ *
+****************************************************************************/
+#ifndef _SIGBOOST_H_
+#define _SIGBOOST_H_
+
+#define SIGBOOST_VERSION 103
+
+#include <stdint.h>
+#include <sys/time.h>
+
+#ifdef HAVE_FREETDM
+#include <freetdm.h>
+#endif
+
+enum e_sigboost_event_id_values
+{
+ SIGBOOST_EVENT_CALL_START = 0x80, /*128*/
+ SIGBOOST_EVENT_CALL_START_ACK = 0x81, /*129*/
+ SIGBOOST_EVENT_CALL_START_NACK = 0x82, /*130*/
+ SIGBOOST_EVENT_CALL_START_NACK_ACK = 0x83, /*131*/
+ SIGBOOST_EVENT_CALL_ANSWERED = 0x84, /*132*/
+ SIGBOOST_EVENT_CALL_STOPPED = 0x85, /*133*/
+ SIGBOOST_EVENT_CALL_STOPPED_ACK = 0x86, /*134*/
+ SIGBOOST_EVENT_SYSTEM_RESTART = 0x87, /*135*/
+ SIGBOOST_EVENT_SYSTEM_RESTART_ACK = 0x88, /*136*/
+ /* CALL_RELEASED is aimed to fix a race condition that became obvious
+ * when the boost socket was replaced by direct function calls
+ * and the channel hunting was moved to freetdm, the problem is
+ * we can get CALL_STOPPED msg and reply with CALL_STOPPED_ACK
+ * but the signaling module will still (in PRI) send RELEASE and
+ * wait for RELEASE_COMPLETE from the isdn network before
+ * marking the channel as available, therefore freetdm should
+ * also not mark the channel as available until CALL_RELEASED
+ * is received, for socket mode we can continue working as usual
+ * with CALL_STOPPED being the last step because the hunting is
+ * done in the signaling module.
+ *
+ * CALL_RELEASED is only used in queue mode
+ * */
+ SIGBOOST_EVENT_CALL_RELEASED = 0x51, /* 81 */
+ SIGBOOST_EVENT_CALL_PROGRESS = 0x50, /*decimal 80*/
+ /* Following IDs are ss7boost to sangoma_mgd only. */
+ SIGBOOST_EVENT_HEARTBEAT = 0x89, /*137*/
+ SIGBOOST_EVENT_INSERT_CHECK_LOOP = 0x8a, /*138*/
+ SIGBOOST_EVENT_REMOVE_CHECK_LOOP = 0x8b, /*139*/
+ SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE = 0x8c, /*140*/
+ SIGBOOST_EVENT_DIGIT_IN = 0x8d, /*141*/
+};
+enum e_sigboost_release_cause_values
+{
+ SIGBOOST_RELEASE_CAUSE_UNDEFINED = 0,
+ SIGBOOST_RELEASE_CAUSE_NORMAL = 16,
+ /* probable elimination */
+ //SIGBOOST_RELEASE_CAUSE_BUSY = 0x91, /* 145 */
+ //SIGBOOST_RELEASE_CAUSE_CALLED_NOT_EXIST = 0x92, /* 146 */
+ //SIGBOOST_RELEASE_CAUSE_CIRCUIT_RESET = 0x93, /* 147 */
+ //SIGBOOST_RELEASE_CAUSE_NOANSWER = 0x94, /* 148 */
+};
+
+enum e_sigboost_call_setup_ack_nack_cause_values
+{
+ //SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY = 34, /* Q.850 value - don't use */
+ SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY = 117, /* non Q.850 value indicates local all ckt busy
+ causing sangoma_mgd to perform automatic call
+ gapping*/
+ SIGBOOST_CALL_SETUP_NACK_TEST_CKT_BUSY = 17, /* Q.850 value */
+ SIGBOOST_CALL_SETUP_NACK_INVALID_NUMBER = 28, /* Q.850 value */
+ SIGBOOST_CALL_SETUP_CSUPID_DBL_USE = 200, /* unused Q.850 value */
+};
+
+
+enum e_sigboost_huntgroup_values
+{
+ SIGBOOST_HUNTGRP_SEQ_ASC = 0x00, /* sequential with lowest available first */
+ SIGBOOST_HUNTGRP_SEQ_DESC = 0x01, /* sequential with highest available first */
+ SIGBOOST_HUNTGRP_RR_ASC = 0x02, /* round-robin with lowest available first */
+ SIGBOOST_HUNTGRP_RR_DESC = 0x03, /* round-robin with highest available first */
+};
+
+enum e_sigboost_event_info_par_values
+{
+ SIGBOOST_EVI_SPARE = 0x00,
+ SIGBOOST_EVI_ALERTING = 0x01,
+ SIGBOOST_EVI_PROGRESS = 0x02,
+};
+
+enum e_sigboost_progress_flags
+{
+ SIGBOOST_PROGRESS_RING = (1 << 0),
+ SIGBOOST_PROGRESS_MEDIA = (1 << 1)
+};
+
+#define MAX_DIALED_DIGITS 31
+
+/* Next two defines are used to create the range of values for call_setup_id
+ * in the t_sigboost structure.
+ * 0..((CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN) - 1) */
+#define CORE_MAX_SPANS 200
+#define CORE_MAX_CHAN_PER_SPAN 32
+#define MAX_PENDING_CALLS CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN
+/* 0..(MAX_PENDING_CALLS-1) is range of call_setup_id below */
+
+/* Should only be used by server */
+#define MAX_CALL_SETUP_ID 0xFFFF
+
+#define SIZE_CUSTOM 900
+#define SIZE_RDNIS SIZE_CUSTOM
+
+
+#pragma pack(1)
+
+typedef struct
+{
+ uint8_t capability;
+ uint8_t uil1p;
+} t_sigboost_bearer;
+
+typedef struct
+{
+ uint8_t digits_count;
+ char digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
+ uint8_t npi;
+ uint8_t ton;
+ uint8_t screening_ind;
+ uint8_t presentation_ind;
+}t_sigboost_digits;
+
+typedef struct
+{
+ uint16_t version;
+ uint32_t event_id;
+ /* delete sequence numbers - SCTP does not need them */
+ uint32_t fseqno;
+ uint32_t bseqno;
+ uint16_t call_setup_id;
+ uint32_t trunk_group;
+ uint8_t span;
+ uint8_t chan;
+ uint32_t flags;
+ /* struct timeval tv; */
+ t_sigboost_digits called;
+ t_sigboost_digits calling;
+ t_sigboost_digits rdnis;
+ /* ref. Q.931 Table 4-11 and Q.951 Section 3 */
+ char calling_name[MAX_DIALED_DIGITS + 1];
+ t_sigboost_bearer bearer;
+ uint8_t hunt_group;
+ uint16_t custom_data_size;
+ char custom_data[SIZE_CUSTOM]; /* it's a null terminated string */
+
+} t_sigboost_callstart;
+
+#define called_number_digits_count called.digits_count
+#define called_number_digits called.digits
+#define calling_number_digits_count calling.digits_count
+#define calling_number_digits calling.digits
+#define calling_number_screening_ind calling.screening_ind
+#define calling_number_presentation calling.presentation_ind
+
+#define isup_in_rdnis_size custom_data_size
+#define isup_in_rdnis custom_data
+
+
+#define MIN_SIZE_CALLSTART_MSG sizeof(t_sigboost_callstart) - SIZE_CUSTOM
+
+typedef struct
+{
+ uint16_t version;
+ uint32_t event_id;
+ /* delete sequence numbers - SCTP does not need them */
+ uint32_t fseqno;
+ uint32_t bseqno;
+ uint16_t call_setup_id;
+ uint32_t trunk_group;
+ uint8_t span;
+ uint8_t chan;
+ uint32_t flags;
+ /* struct timeval tv; */
+ uint8_t release_cause;
+} t_sigboost_short;
+#pragma pack()
+
+
+static inline int boost_full_event(int event_id)
+{
+ switch (event_id) {
+ case SIGBOOST_EVENT_CALL_START:
+ case SIGBOOST_EVENT_DIGIT_IN:
+ case SIGBOOST_EVENT_CALL_PROGRESS:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+#endif
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/zap_sangoma_boost.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/zap_sangoma_boost.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/zap_sangoma_boost.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#ifndef ZAP_SANGOMA_BOOST_H
+#define ZAP_SANGOMA_BOOST_H
+#include "sangoma_boost_client.h"
+#include "openzap.h"
+
+typedef enum {
+ ZAP_SANGOMA_BOOST_RUNNING = (1 << 0),
+ ZAP_SANGOMA_BOOST_RESTARTING = (1 << 1)
+} zap_sangoma_boost_flag_t;
+
+typedef struct zap_sangoma_boost_data {
+ sangomabc_connection_t mcon;
+ sangomabc_connection_t pcon;
+ uint32_t flags;
+} zap_sangoma_boost_data_t;
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_skel/ozmod_skel.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_skel/ozmod_skel.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_skel/ozmod_skel.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+
+#include "openzap.h"
+//#include "zap_skel.h"
+
+static ZIO_CONFIGURE_FUNCTION(skel_configure)
+{
+ return ZAP_FAIL;
+}
+
+static ZIO_CONFIGURE_SPAN_FUNCTION(skel_configure_span)
+{
+ return ZAP_FAIL;
+}
+
+static ZIO_OPEN_FUNCTION(skel_open)
+{
+ return ZAP_FAIL;
+}
+
+static ZIO_CLOSE_FUNCTION(skel_close)
+{
+ return ZAP_FAIL;
+}
+
+static ZIO_WAIT_FUNCTION(skel_wait)
+{
+ return ZAP_FAIL;
+}
+
+static ZIO_READ_FUNCTION(skel_read)
+{
+ return ZAP_FAIL;
+}
+
+static ZIO_WRITE_FUNCTION(skel_write)
+{
+ return ZAP_FAIL;
+}
+
+static ZIO_COMMAND_FUNCTION(skel_command)
+{
+ return ZAP_FAIL;
+}
+
+static ZIO_SPAN_POLL_EVENT_FUNCTION(skel_poll_event)
+{
+ return ZAP_FAIL;
+}
+
+static ZIO_SPAN_NEXT_EVENT_FUNCTION(skel_next_event)
+{
+ return ZAP_FAIL;
+}
+
+static ZIO_CHANNEL_DESTROY_FUNCTION(skel_channel_destroy)
+{
+ return ZAP_FAIL;
+}
+
+static ZIO_SPAN_DESTROY_FUNCTION(skel_span_destroy)
+{
+ return ZAP_FAIL;
+}
+
+static ZIO_GET_ALARMS_FUNCTION(skel_get_alarms)
+{
+ return ZAP_FAIL;
+}
+
+static zap_io_interface_t skel_interface;
+
+static ZIO_IO_LOAD_FUNCTION(skel_init)
+{
+ assert(zio != NULL);
+ memset(&skel_interface, 0, sizeof(skel_interface));
+
+ skel_interface.name = "skel";
+ skel_interface.configure = skel_configure;
+ skel_interface.configure_span = skel_configure_span;
+ skel_interface.open = skel_open;
+ skel_interface.close = skel_close;
+ skel_interface.wait = skel_wait;
+ skel_interface.read = skel_read;
+ skel_interface.write = skel_write;
+ skel_interface.command = skel_command;
+ skel_interface.poll_event = skel_poll_event;
+ skel_interface.next_event = skel_next_event;
+ skel_interface.channel_destroy = skel_channel_destroy;
+ skel_interface.span_destroy = skel_span_destroy;
+ skel_interface.get_alarms = skel_get_alarms;
+ *zio = &skel_interface;
+
+ return ZAP_SUCCESS;
+}
+
+static ZIO_IO_UNLOAD_FUNCTION(skel_destroy)
+{
+ return ZAP_SUCCESS;
+}
+
+
+zap_module_t zap_module = {
+ "skel",
+ skel_init,
+ skel_destroy,
+};
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.2005.vcproj (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.2005.vcproj (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.2005.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,196 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ozmod_wanpipe"
+ ProjectGUID="{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}"
+ RootNamespace="ozmod_wanpipe"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="openzap.lib libsangoma.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=""$(OutDir)";../../../wanpipe/api/lib/x86"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="openzap.lib libsangoma.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories=""$(OutDir)";../../../wanpipe/api/lib/x86"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\ozmod_wanpipe.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.2008.vcproj (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.2008.vcproj (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.2008.vcproj 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,355 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="ozmod_wanpipe"
+ ProjectGUID="{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}"
+ RootNamespace="ozmod_wanpipe"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="openzap.lib libsangoma.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=""$(OutDir)";../../../wanpipe/api/lib/x86"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="openzap.lib libsangoma.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=""$(OutDir)";../../../wanpipe/api/lib/x64"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="openzap.lib libsangoma.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories=""$(OutDir)";../../../wanpipe/api/lib/x86"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="openzap.lib libsangoma.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories=""$(OutDir)";../../../wanpipe/api/lib/x64"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\ozmod_wanpipe.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1235 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#ifdef __sun
+#include <unistd.h>
+#include <stropts.h>
+#endif
+#include "openzap.h"
+#ifndef __WINDOWS__
+#include <poll.h>
+#include <sys/socket.h>
+#endif
+#include "libsangoma.h"
+
+#if defined(__WINDOWS__)
+/* remove this when http://jira.freeswitch.org/browse/FSBUILD-259 wanpipe issue is fixed */
+#define WINDOWS_BUILD_BROKEN 1
+/*! Backward compatible defines - current code is all using the old names*/
+#define sangoma_open_tdmapi_span_chan sangoma_open_api_span_chan
+#define sangoma_open_tdmapi_span sangoma_open_api_span
+#define sangoma_open_tdmapi_ctrl sangoma_open_api_ctrl
+#define sangoma_tdm_get_fe_status sangoma_get_fe_status
+#define sangoma_socket_close sangoma_close
+#define sangoma_tdm_get_hw_coding sangoma_get_hw_coding
+#define sangoma_tdm_set_fe_status sangoma_set_fe_status
+#define sangoma_tdm_get_link_status sangoma_get_link_status
+#define sangoma_tdm_flush_bufs sangoma_flush_bufs
+#define sangoma_tdm_cmd_exec sangoma_cmd_exec
+#define sangoma_tdm_read_event sangoma_read_event
+#define sangoma_readmsg_tdm sangoma_readmsg
+#define sangoma_readmsg_socket sangoma_readmsg
+#define sangoma_sendmsg_socket sangoma_writemsg
+#define sangoma_writemsg_tdm sangoma_writemsg
+#define sangoma_create_socket_intr sangoma_open_api_span_chan
+#endif
+
+/*! Starting with libsangoma 3 we can use the new libsangoma waitable API, the poor souls of those using a release were LIBSANGOMA version
+ * is defined but the version is not higher or equal to 3.0.0 will be forced to upgrade
+ * */
+#ifdef LIBSANGOMA_VERSION
+#if LIBSANGOMA_VERSION_CODE < LIBSANGOMA_VERSION(3,0,0)
+#undef LIBSANGOMA_VERSION
+#endif
+#endif
+
+/**
+ * \brief Wanpipe flags
+ */
+typedef enum {
+ WP_RINGING = (1 << 0)
+} wp_flag_t;
+
+/**
+ * \brief Wanpipe globals
+ */
+static struct {
+ uint32_t codec_ms;
+ uint32_t wink_ms;
+ uint32_t flash_ms;
+ uint32_t ring_on_ms;
+ uint32_t ring_off_ms;
+} wp_globals;
+
+/* a bunch of this stuff should go into the wanpipe_tdm_api_iface.h */
+
+ZIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event);
+ZIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event);
+
+#define WP_INVALID_SOCKET -1
+
+/**
+ * \brief Poll for event on a wanpipe socket
+ * \param fd Wanpipe socket descriptor
+ * \param timeout Time to wait for event
+ * \param flags Sangoma event flags
+ * \return -1 on failure, wanpipe event flags on success
+ *
+ * a cross platform way to poll on an actual pollset (span and/or list of spans) will probably also be needed for analog
+ * so we can have one analong handler thread that will deal with all the idle analog channels for events
+ * the alternative would be for the driver to provide one socket for all of the oob events for all analog channels
+ */
+static __inline__ int tdmv_api_wait_socket(zap_channel_t *zchan, int timeout, int *flags)
+{
+
+#ifdef LIBSANGOMA_VERSION
+ int err;
+ uint32_t inflags = *flags;
+ uint32_t outflags = 0;
+ sangoma_wait_obj_t *sangoma_wait_obj = zchan->mod_data;
+
+ err = sangoma_waitfor(sangoma_wait_obj, inflags, &outflags, timeout);
+ *flags = 0;
+ if (err == SANG_STATUS_SUCCESS) {
+ *flags = outflags;
+ err = 1; /* ideally should be the number of file descriptors with something to read */
+ }
+ if (err == SANG_STATUS_APIPOLL_TIMEOUT) {
+ err = 0;
+ }
+ return err;
+#else
+ struct pollfd pfds[1];
+ int res;
+
+ memset(&pfds[0], 0, sizeof(pfds[0]));
+ pfds[0].fd = zchan->sockfd;
+ pfds[0].events = *flags;
+ res = poll(pfds, 1, timeout);
+ *flags = 0;
+
+ if (pfds[0].revents & POLLERR) {
+ res = -1;
+ }
+
+ if (res > 0) {
+ *flags = pfds[0].revents;
+ }
+
+ return res;
+#endif
+
+}
+
+/**
+ * \brief Opens a sangoma channel socket (TDM API)
+ * \param span Span number
+ * \param chan Channel number
+ * \return 0 on success, wanpipe error code on failure
+ */
+static __inline__ sng_fd_t tdmv_api_open_span_chan(int span, int chan)
+{
+ return sangoma_open_tdmapi_span_chan(span, chan);
+}
+
+#ifdef LIBSANGOMA_VERSION
+static __inline__ sng_fd_t __tdmv_api_open_span_chan(int span, int chan)
+{
+ return __sangoma_open_tdmapi_span_chan(span, chan);
+}
+#endif
+
+static zap_io_interface_t wanpipe_interface;
+
+/**
+ * \brief Inverts bit string
+ * \param cas_bits CAS bit string
+ * \return Swapped bits
+ */
+static unsigned char wanpipe_swap_bits(unsigned char cas_bits)
+{
+ unsigned char swapped_bits = 0x0;
+ if (cas_bits & 0x8) {
+ swapped_bits |= 0x1;
+ }
+ if (cas_bits & 0x4) {
+ swapped_bits |= 0x2;
+ }
+ if (cas_bits & 0x2) {
+ swapped_bits |= 0x4;
+ }
+ if (cas_bits & 0x1) {
+ swapped_bits |= 0x8;
+ }
+ return swapped_bits;
+}
+
+/**
+ * \brief Initialises a range of wanpipe channels
+ * \param span Openzap span
+ * \param spanno Wanpipe span number
+ * \param start Initial wanpipe channel number
+ * \param end Final wanpipe channel number
+ * \param type Openzap channel type
+ * \param name Openzap span name
+ * \param number Openzap span number
+ * \param cas_bits CAS bits
+ * \return number of spans configured
+ */
+static unsigned wp_open_range(zap_span_t *span, unsigned spanno, unsigned start, unsigned end, zap_chan_type_t type, char *name, char *number, unsigned char cas_bits)
+{
+ unsigned configured = 0, x;
+#ifdef LIBSANGOMA_VERSION
+ sangoma_status_t sangstatus;
+ sangoma_wait_obj_t *sangoma_wait_obj;
+#endif
+
+ if (type == ZAP_CHAN_TYPE_CAS) {
+ zap_log(ZAP_LOG_DEBUG, "Configuring Wanpipe CAS channels with abcd == 0x%X\n", cas_bits);
+ }
+ for(x = start; x < end; x++) {
+ zap_channel_t *chan;
+ zap_socket_t sockfd = WP_INVALID_SOCKET;
+ const char *dtmf = "none";
+ if (!strncasecmp(span->name, "smg_prid_nfas", 8) && span->trunk_type == ZAP_TRUNK_T1 && x == 24) {
+#ifdef LIBSANGOMA_VERSION
+ sockfd = __tdmv_api_open_span_chan(spanno, x);
+#else
+ zap_log(ZAP_LOG_ERROR, "span %d channel %d cannot be configured as smg_prid_nfas, you need to compile openzap with newer libsangoma\n", spanno, x);
+#endif
+ } else {
+ sockfd = tdmv_api_open_span_chan(spanno, x);
+ }
+
+ if (sockfd == WP_INVALID_SOCKET) {
+ zap_log(ZAP_LOG_ERROR, "Failed to open wanpipe device span %d channel %d\n", spanno, x);
+ continue;
+ }
+
+ if (zap_span_add_channel(span, sockfd, type, &chan) == ZAP_SUCCESS) {
+ wanpipe_tdm_api_t tdm_api;
+ memset(&tdm_api, 0, sizeof(tdm_api));
+#ifdef LIBSANGOMA_VERSION
+ sangstatus = sangoma_wait_obj_create(&sangoma_wait_obj, sockfd, SANGOMA_DEVICE_WAIT_OBJ);
+ if (sangstatus != SANG_STATUS_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "failure create waitable object for s%dc%d\n", spanno, x);
+ continue;
+ }
+ chan->mod_data = sangoma_wait_obj;
+#endif
+
+ chan->physical_span_id = spanno;
+ chan->physical_chan_id = x;
+ chan->rate = 8000;
+
+ if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO || type == ZAP_CHAN_TYPE_B) {
+ int err;
+
+ dtmf = "software";
+
+ /* FIXME: Handle Error Condition Check for return code */
+ err = sangoma_tdm_get_hw_coding(chan->sockfd, &tdm_api);
+
+ if (tdm_api.wp_tdm_cmd.hw_tdm_coding) {
+ chan->native_codec = chan->effective_codec = ZAP_CODEC_ALAW;
+ } else {
+ chan->native_codec = chan->effective_codec = ZAP_CODEC_ULAW;
+ }
+
+ err = sangoma_tdm_get_hw_dtmf(chan->sockfd, &tdm_api);
+ if (err > 0) {
+ err = sangoma_tdm_enable_dtmf_events(chan->sockfd, &tdm_api);
+ if (err == 0) {
+ zap_channel_set_feature(chan, ZAP_CHANNEL_FEATURE_DTMF_DETECT);
+ dtmf = "hardware";
+ }
+ }
+ }
+
+#ifdef LIBSANGOMA_VERSION
+ if (type == ZAP_CHAN_TYPE_FXS) {
+ if (sangoma_tdm_disable_ring_trip_detect_events(chan->sockfd, &tdm_api)) {
+ /* we had problems of on-hook/off-hook detection due to how ring trip events were handled
+ * if this fails, I believe we will still work ok as long as we dont handle them incorrectly */
+ zap_log(ZAP_LOG_WARNING, "Failed to disable ring trip events in channel s%dc%d\n", spanno, x);
+ }
+ }
+#endif
+#if 0
+ if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO) {
+ /* Enable FLASH/Wink Events */
+ int err=sangoma_set_rm_rxflashtime(chan->sockfd, &tdm_api, wp_globals.flash_ms);
+ if (err == 0) {
+ zap_log(ZAP_LOG_ERROR, "flash enabled s%dc%d\n", spanno, x);
+ } else {
+ zap_log(ZAP_LOG_ERROR, "flash disabled s%dc%d\n", spanno, x);
+ }
+ }
+#endif
+
+ if (type == ZAP_CHAN_TYPE_CAS || type == ZAP_CHAN_TYPE_EM) {
+#ifdef LIBSANGOMA_VERSION
+ sangoma_tdm_write_rbs(chan->sockfd,&tdm_api,chan->physical_chan_id, wanpipe_swap_bits(cas_bits));
+
+ /* this should probably be done for old libsangoma but I am not sure if the API is available and I'm lazy to check,
+ The poll rate is hard coded to 100 per second (done in the driver, is the max rate of polling allowed by wanpipe)
+ */
+ if (sangoma_tdm_enable_rbs_events(chan->sockfd, &tdm_api, 100)) {
+ zap_log(ZAP_LOG_ERROR, "Failed to enable RBS/CAS events in device %d:%d fd:%d\n", chan->span_id, chan->chan_id, sockfd);
+ continue;
+ }
+ /* probably done by the driver but lets write defensive code this time */
+ sangoma_flush_bufs(chan->sockfd, &tdm_api);
+#else
+ /*
+ * With wanpipe 3.4.4.2 I get failure even though the events are enabled, /var/log/messages said:
+ * wanpipe4: WARNING: Event type 9 is already pending!
+ * wanpipe4: Failed to add new fe event 09 ch_map=FFFFFFFF!
+ * may be we should not send an error until that is fixed in the driver
+ */
+ if (sangoma_tdm_enable_rbs_events(chan->sockfd, &tdm_api, 100)) {
+ zap_log(ZAP_LOG_ERROR, "Failed to enable RBS/CAS events in device %d:%d fd:%d\n", chan->span_id, chan->chan_id, sockfd);
+ }
+ /* probably done by the driver but lets write defensive code this time */
+ sangoma_tdm_flush_bufs(chan->sockfd, &tdm_api);
+ sangoma_tdm_write_rbs(chan->sockfd,&tdm_api, wanpipe_swap_bits(cas_bits));
+#endif
+ }
+
+ if (!zap_strlen_zero(name)) {
+ zap_copy_string(chan->chan_name, name, sizeof(chan->chan_name));
+ }
+
+ if (!zap_strlen_zero(number)) {
+ zap_copy_string(chan->chan_number, number, sizeof(chan->chan_number));
+ }
+ configured++;
+ zap_log(ZAP_LOG_INFO, "configuring device s%dc%d as OpenZAP device %d:%d fd:%d DTMF: %s\n",
+ spanno, x, chan->span_id, chan->chan_id, sockfd, dtmf);
+
+ } else {
+ zap_log(ZAP_LOG_ERROR, "zap_span_add_channel failed for wanpipe span %d channel %d\n", spanno, x);
+ }
+ }
+
+ return configured;
+}
+
+/**
+ * \brief Process configuration variable for a Wanpipe profile
+ * \param category Wanpipe profile name
+ * \param var Variable name
+ * \param val Variable value
+ * \param lineno Line number from configuration file
+ * \return Success
+ */
+static ZIO_CONFIGURE_FUNCTION(wanpipe_configure)
+{
+ int num;
+
+ if (!strcasecmp(category, "defaults")) {
+ if (!strcasecmp(var, "codec_ms")) {
+ num = atoi(val);
+ if (num < 10 || num > 60) {
+ zap_log(ZAP_LOG_WARNING, "invalid codec ms at line %d\n", lineno);
+ } else {
+ wp_globals.codec_ms = num;
+ }
+ } else if (!strcasecmp(var, "wink_ms")) {
+ num = atoi(val);
+ if (num < 50 || num > 3000) {
+ zap_log(ZAP_LOG_WARNING, "invalid wink ms at line %d\n", lineno);
+ } else {
+ wp_globals.wink_ms = num;
+ }
+ } else if (!strcasecmp(var, "flash_ms")) {
+ num = atoi(val);
+ if (num < 50 || num > 3000) {
+ zap_log(ZAP_LOG_WARNING, "invalid flash ms at line %d\n", lineno);
+ } else {
+ wp_globals.flash_ms = num;
+ }
+ } else if (!strcasecmp(var, "ring_on_ms")) {
+ num = atoi(val);
+ if (num < 500 || num > 5000) {
+ zap_log(ZAP_LOG_WARNING, "invalid ring_on_ms at line %d (valid range 500 to 5000)\n", lineno);
+ } else {
+ wp_globals.ring_on_ms = num;
+ }
+ } else if (!strcasecmp(var, "ring_off_ms")) {
+ num = atoi(val);
+ if (num < 500 || num > 5000) {
+ zap_log(ZAP_LOG_WARNING, "invalid ring_off_ms at line %d (valid range 500 to 5000)\n", lineno);
+ } else {
+ wp_globals.ring_off_ms = num;
+ }
+ }
+ }
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Initialises an openzap Wanpipe span from a configuration string
+ * \param span Openzap span
+ * \param str Configuration string
+ * \param type Openzap span type
+ * \param name Openzap span name
+ * \param number Openzap span number
+ * \return Success or failure
+ */
+static ZIO_CONFIGURE_SPAN_FUNCTION(wanpipe_configure_span)
+{
+ int items, i;
+ char *mydata, *item_list[10];
+ char *sp, *ch, *mx;
+ unsigned char cas_bits = 0;
+ int channo;
+ int spanno;
+ int top = 0;
+ unsigned configured = 0;
+
+ assert(str != NULL);
+
+
+ mydata = strdup(str);
+ assert(mydata != NULL);
+
+
+ items = zap_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
+
+ for(i = 0; i < items; i++) {
+ sp = item_list[i];
+ if ((ch = strchr(sp, ':'))) {
+ *ch++ = '\0';
+ }
+
+ if (!(sp && ch)) {
+ zap_log(ZAP_LOG_ERROR, "No valid wanpipe span and channel was specified\n");
+ continue;
+ }
+
+ channo = atoi(ch);
+ spanno = atoi(sp);
+
+ if (channo < 0) {
+ zap_log(ZAP_LOG_ERROR, "Invalid channel number %d\n", channo);
+ continue;
+ }
+
+ if (spanno < 0) {
+ zap_log(ZAP_LOG_ERROR, "Invalid span number %d\n", channo);
+ continue;
+ }
+
+ if ((mx = strchr(ch, '-'))) {
+ mx++;
+ top = atoi(mx) + 1;
+ } else {
+ top = channo + 1;
+ }
+
+
+ if (top < 0) {
+ zap_log(ZAP_LOG_ERROR, "Invalid range number %d\n", top);
+ continue;
+ }
+ if (ZAP_CHAN_TYPE_CAS == type && zap_config_get_cas_bits(ch, &cas_bits)) {
+ zap_log(ZAP_LOG_ERROR, "Failed to get CAS bits in CAS channel\n");
+ continue;
+ }
+ configured += wp_open_range(span, spanno, channo, top, type, name, number, cas_bits);
+
+ }
+
+ free(mydata);
+
+ return configured;
+}
+
+/**
+ * \brief Opens Wanpipe channel
+ * \param zchan Channel to open
+ * \return Success or failure
+ */
+static ZIO_OPEN_FUNCTION(wanpipe_open)
+{
+
+ wanpipe_tdm_api_t tdm_api;
+
+ memset(&tdm_api,0,sizeof(tdm_api));
+ sangoma_tdm_flush_bufs(zchan->sockfd, &tdm_api);
+#ifdef LIBSANGOMA_VERSION
+ sangoma_flush_event_bufs(zchan->sockfd, &tdm_api);
+#endif
+
+ if (zchan->type == ZAP_CHAN_TYPE_DQ921 || zchan->type == ZAP_CHAN_TYPE_DQ931) {
+ zchan->native_codec = zchan->effective_codec = ZAP_CODEC_NONE;
+ } else {
+ zchan->effective_codec = zchan->native_codec;
+
+ sangoma_tdm_set_usr_period(zchan->sockfd, &tdm_api, wp_globals.codec_ms);
+
+ zap_channel_set_feature(zchan, ZAP_CHANNEL_FEATURE_INTERVAL);
+ zchan->effective_interval = zchan->native_interval = wp_globals.codec_ms;
+ zchan->packet_len = zchan->native_interval * 8;
+ }
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Closes Wanpipe channel
+ * \param zchan Channel to close
+ * \return Success
+ */
+static ZIO_CLOSE_FUNCTION(wanpipe_close)
+{
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Executes an Openzap command on a Wanpipe channel
+ * \param zchan Channel to execute command on
+ * \param command Openzap command to execute
+ * \param obj Object (unused)
+ * \return Success or failure
+ */
+static ZIO_COMMAND_FUNCTION(wanpipe_command)
+{
+ wanpipe_tdm_api_t tdm_api;
+ int err = 0;
+
+ memset(&tdm_api, 0, sizeof(tdm_api));
+
+ switch(command) {
+ case ZAP_COMMAND_OFFHOOK:
+ {
+ err=sangoma_tdm_txsig_offhook(zchan->sockfd,&tdm_api);
+ if (err) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "OFFHOOK Failed");
+ return ZAP_FAIL;
+ }
+ zap_set_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
+ }
+ break;
+ case ZAP_COMMAND_ONHOOK:
+ {
+ err=sangoma_tdm_txsig_onhook(zchan->sockfd,&tdm_api);
+ if (err) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "ONHOOK Failed");
+ return ZAP_FAIL;
+ }
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
+ }
+ break;
+ case ZAP_COMMAND_GENERATE_RING_ON:
+ {
+ err=sangoma_tdm_txsig_start(zchan->sockfd,&tdm_api);
+ if (err) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring Failed");
+ return ZAP_FAIL;
+ }
+ zap_set_flag_locked(zchan, ZAP_CHANNEL_RINGING);
+ zap_set_pflag_locked(zchan, WP_RINGING);
+ zchan->ring_time = zap_current_time_in_ms() + wp_globals.ring_on_ms;
+ }
+ break;
+ case ZAP_COMMAND_GENERATE_RING_OFF:
+ {
+ err=sangoma_tdm_txsig_offhook(zchan->sockfd,&tdm_api);
+ if (err) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring-off Failed");
+ return ZAP_FAIL;
+ }
+ zap_clear_pflag_locked(zchan, WP_RINGING);
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_RINGING);
+ }
+ break;
+ case ZAP_COMMAND_GET_INTERVAL:
+ {
+ err=sangoma_tdm_get_usr_period(zchan->sockfd, &tdm_api);
+ if (err > 0 ) {
+ ZAP_COMMAND_OBJ_INT = err;
+ err=0;
+ }
+ }
+ break;
+ case ZAP_COMMAND_ENABLE_ECHOCANCEL:
+ {
+#ifndef WINDOWS_BUILD_BROKEN
+ err=sangoma_tdm_enable_hwec(zchan->sockfd, &tdm_api);
+ if (err) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "HWEC Enable Failed");
+ return ZAP_FAIL;
+ }
+#endif /* WINDOWS_BUILD_BROKEN */
+ }
+ break;
+ case ZAP_COMMAND_DISABLE_ECHOCANCEL:
+ {
+#ifndef WINDOWS_BUILD_BROKEN
+ err=sangoma_tdm_disable_hwec(zchan->sockfd, &tdm_api);
+ if (err) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "HWEC Disable Failed");
+ return ZAP_FAIL;
+ }
+#endif /* WINDOWS_BUILD_BROKEN */
+ }
+ break;
+ case ZAP_COMMAND_ENABLE_LOOP:
+ {
+#ifndef WINDOWS_BUILD_BROKEN
+#ifdef WP_API_FEATURE_LOOP
+ err=sangoma_tdm_enable_loop(zchan->sockfd, &tdm_api);
+ if (err) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "Loop Enable Failed");
+ return ZAP_FAIL;
+ }
+#endif
+#endif /* WINDOWS_BUILD_BROKEN */
+ }
+ case ZAP_COMMAND_DISABLE_LOOP:
+ {
+#ifndef WINDOWS_BUILD_BROKEN
+#ifdef WP_API_FEATURE_LOOP
+ err=sangoma_tdm_disable_loop(zchan->sockfd, &tdm_api);
+ if (err) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "Loop Disable Failed");
+ return ZAP_FAIL;
+ }
+#endif
+#endif /* WINDOWS_BUILD_BROKEN */
+ }
+ case ZAP_COMMAND_SET_INTERVAL:
+ {
+ err=sangoma_tdm_set_usr_period(zchan->sockfd, &tdm_api, ZAP_COMMAND_OBJ_INT);
+ zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8);
+ }
+ break;
+ case ZAP_COMMAND_SET_CAS_BITS:
+ {
+#ifdef LIBSANGOMA_VERSION
+ err = sangoma_tdm_write_rbs(zchan->sockfd,&tdm_api, zchan->physical_chan_id, wanpipe_swap_bits(ZAP_COMMAND_OBJ_INT));
+#else
+ err = sangoma_tdm_write_rbs(zchan->sockfd, &tdm_api, wanpipe_swap_bits(ZAP_COMMAND_OBJ_INT));
+#endif
+ }
+ break;
+ case ZAP_COMMAND_GET_CAS_BITS:
+ {
+#ifdef LIBSANGOMA_VERSION
+ unsigned char rbsbits;
+ err = sangoma_tdm_read_rbs(zchan->sockfd, &tdm_api, zchan->physical_chan_id, &rbsbits);
+ if (!err) {
+ ZAP_COMMAND_OBJ_INT = wanpipe_swap_bits(rbsbits);
+ }
+#else
+ // does sangoma_tdm_read_rbs is available here?
+ ZAP_COMMAND_OBJ_INT = zchan->rx_cas_bits;
+#endif
+ }
+ break;
+ default:
+ break;
+ };
+
+ if (err) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
+ return ZAP_FAIL;
+ }
+
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Reads data from a Wanpipe channel
+ * \param zchan Channel to read from
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success, failure or timeout
+ */
+static ZIO_READ_FUNCTION(wanpipe_read)
+{
+ int rx_len = 0;
+ wp_tdm_api_rx_hdr_t hdrframe;
+
+ memset(&hdrframe, 0, sizeof(hdrframe));
+
+ rx_len = sangoma_readmsg_tdm(zchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (int)*datalen,0);
+ *datalen = rx_len;
+
+ if (rx_len == 0 || rx_len == -17) {
+ return ZAP_TIMEOUT;
+ }
+
+ if (rx_len < 0) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
+ return ZAP_FAIL;
+ }
+
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Writes data to a Wanpipe channel
+ * \param zchan Channel to write to
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success or failure
+ */
+static ZIO_WRITE_FUNCTION(wanpipe_write)
+{
+ int bsent;
+ wp_tdm_api_tx_hdr_t hdrframe;
+
+ /* Do we even need the headerframe here? on windows, we don't even pass it to the driver */
+ memset(&hdrframe, 0, sizeof(hdrframe));
+ if (*datalen == 0) {
+ return ZAP_SUCCESS;
+ }
+ bsent = sangoma_writemsg_tdm(zchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (unsigned short)(*datalen),0);
+
+ /* should we be checking if bsent == *datalen here? */
+ if (bsent > 0) {
+ *datalen = bsent;
+ return ZAP_SUCCESS;
+ }
+
+ return ZAP_FAIL;
+}
+
+/**
+ * \brief Waits for an event on a Wanpipe channel
+ * \param zchan Channel to open
+ * \param flags Type of event to wait for
+ * \param to Time to wait (in ms)
+ * \return Success, failure or timeout
+ */
+
+static ZIO_WAIT_FUNCTION(wanpipe_wait)
+{
+ int32_t inflags = 0;
+ int result;
+
+ if (*flags & ZAP_READ) {
+ inflags |= POLLIN;
+ }
+
+ if (*flags & ZAP_WRITE) {
+ inflags |= POLLOUT;
+ }
+
+ if (*flags & ZAP_EVENTS) {
+ inflags |= POLLPRI;
+ }
+
+ result = tdmv_api_wait_socket(zchan, to, &inflags);
+
+ *flags = ZAP_NO_FLAGS;
+
+ if (result < 0){
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "Poll failed");
+ return ZAP_FAIL;
+ }
+
+ if (result == 0) {
+ return ZAP_TIMEOUT;
+ }
+
+ if (inflags & POLLIN) {
+ *flags |= ZAP_READ;
+ }
+
+ if (inflags & POLLOUT) {
+ *flags |= ZAP_WRITE;
+ }
+
+ if (inflags & POLLPRI) {
+ *flags |= ZAP_EVENTS;
+ }
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Checks for events on a Wanpipe span
+ * \param span Span to check for events
+ * \param ms Time to wait for event
+ * \return Success if event is waiting or failure if not
+ */
+ZIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event)
+{
+#ifdef LIBSANGOMA_VERSION
+ sangoma_status_t sangstatus;
+ sangoma_wait_obj_t *pfds[ZAP_MAX_CHANNELS_SPAN] = { 0 };
+ uint32_t inflags[ZAP_MAX_CHANNELS_SPAN];
+ uint32_t outflags[ZAP_MAX_CHANNELS_SPAN];
+#else
+ struct pollfd pfds[ZAP_MAX_CHANNELS_SPAN];
+#endif
+
+ uint32_t i, j = 0, k = 0, l = 0;
+ int r;
+
+ for(i = 1; i <= span->chan_count; i++) {
+ zap_channel_t *zchan = span->channels[i];
+
+ if (!strncasecmp(span->name, "smg_prid_nfas", 8) && span->trunk_type == ZAP_TRUNK_T1 && zchan->physical_chan_id == 24) {
+ continue;
+ }
+
+#ifdef LIBSANGOMA_VERSION
+ if (!zchan->mod_data) {
+ continue; /* should never happen but happens when shutting down */
+ }
+ pfds[j] = zchan->mod_data;
+ inflags[j] = POLLPRI;
+#else
+ memset(&pfds[j], 0, sizeof(pfds[j]));
+ pfds[j].fd = span->channels[i]->sockfd;
+ pfds[j].events = POLLPRI;
+#endif
+
+ /* The driver probably should be able to do this wink/flash/ringing by itself this is sort of a hack to make it work! */
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_WINK) || zap_test_flag(zchan, ZAP_CHANNEL_FLASH)) {
+ l = 5;
+ }
+
+ j++;
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_RINGING)) {
+ l = 5;
+ }
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_RINGING) && zap_current_time_in_ms() >= zchan->ring_time) {
+ wanpipe_tdm_api_t tdm_api;
+ int err;
+ memset(&tdm_api, 0, sizeof(tdm_api));
+ if (zap_test_pflag(zchan, WP_RINGING)) {
+ err=sangoma_tdm_txsig_offhook(zchan->sockfd,&tdm_api);
+ if (err) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring-off Failed");
+ return ZAP_FAIL;
+ }
+ zap_clear_pflag_locked(zchan, WP_RINGING);
+ zchan->ring_time = zap_current_time_in_ms() + wp_globals.ring_off_ms;
+ } else {
+ err=sangoma_tdm_txsig_start(zchan->sockfd,&tdm_api);
+ if (err) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring Failed");
+ return ZAP_FAIL;
+ }
+ zap_set_pflag_locked(zchan, WP_RINGING);
+ zchan->ring_time = zap_current_time_in_ms() + wp_globals.ring_on_ms;
+ }
+ }
+ }
+
+ if (l) {
+ ms = l;
+ }
+#ifdef LIBSANGOMA_VERSION
+ sangstatus = sangoma_waitfor_many(pfds, inflags, outflags, j, ms);
+ if (SANG_STATUS_APIPOLL_TIMEOUT == sangstatus) {
+ r = 0;
+ } else if (SANG_STATUS_SUCCESS == sangstatus) {
+ r = 1; /* hopefully we never need how many changed -_- */
+ } else {
+ r = -1;
+ }
+#else
+ r = poll(pfds, j, ms);
+#endif
+
+ if (r == 0) {
+ return l ? ZAP_SUCCESS : ZAP_TIMEOUT;
+ } else if (r < 0) {
+ snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+ return ZAP_FAIL;
+ }
+
+ for(i = 1; i <= span->chan_count; i++) {
+ zap_channel_t *zchan = span->channels[i];
+
+#ifdef LIBSANGOMA_VERSION
+ if (outflags[i-1] & POLLPRI) {
+#else
+ if (pfds[i-1].revents & POLLPRI) {
+#endif
+ zap_set_flag(zchan, ZAP_CHANNEL_EVENT);
+ zchan->last_event_time = zap_current_time_in_ms();
+ k++;
+ }
+ }
+
+
+ return k ? ZAP_SUCCESS : ZAP_FAIL;
+}
+
+/**
+ * \brief Gets alarms from a Wanpipe Channel
+ * \param zchan Channel to get alarms from
+ * \return Success or failure
+ */
+static ZIO_GET_ALARMS_FUNCTION(wanpipe_get_alarms)
+{
+ wanpipe_tdm_api_t tdm_api;
+ unsigned int alarms = 0;
+ int err;
+
+ memset(&tdm_api,0,sizeof(tdm_api));
+
+#ifdef LIBSANGOMA_VERSION
+ if ((err = sangoma_tdm_get_fe_alarms(zchan->sockfd, &tdm_api, &alarms))) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "ioctl failed (%s)", strerror(errno));
+ snprintf(zchan->span->last_error, sizeof(zchan->span->last_error), "ioctl failed (%s)", strerror(errno));
+ return ZAP_FAIL;
+ }
+#else
+ if ((err = sangoma_tdm_get_fe_alarms(zchan->sockfd, &tdm_api)) < 0){
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "ioctl failed (%s)", strerror(errno));
+ snprintf(zchan->span->last_error, sizeof(zchan->span->last_error), "ioctl failed (%s)", strerror(errno));
+ return ZAP_FAIL;
+ }
+ alarms = tdm_api.wp_tdm_cmd.fe_alarms;
+#endif
+ zchan->alarm_flags = ZAP_ALARM_NONE;
+
+ if (alarms & WAN_TE_BIT_ALARM_RED) {
+ zchan->alarm_flags |= ZAP_ALARM_RED;
+ alarms &= ~WAN_TE_BIT_ALARM_RED;
+ }
+
+ if (alarms & WAN_TE_BIT_ALARM_AIS) {
+ zchan->alarm_flags |= ZAP_ALARM_AIS;
+ zchan->alarm_flags |= ZAP_ALARM_BLUE;
+ alarms &= ~WAN_TE_BIT_ALARM_AIS;
+ }
+
+ if (alarms & WAN_TE_BIT_ALARM_RAI) {
+ zchan->alarm_flags |= ZAP_ALARM_RAI;
+ zchan->alarm_flags |= ZAP_ALARM_YELLOW;
+ alarms &= ~WAN_TE_BIT_ALARM_RAI;
+ }
+
+ /* still missing to map:
+ * ZAP_ALARM_RECOVER
+ * ZAP_ALARM_LOOPBACK
+ * ZAP_ALARM_NOTOPEN
+ * */
+
+ /* if we still have alarms that we did not map, set the general alarm */
+ if (alarms) {
+ zap_log(ZAP_LOG_DEBUG, "Unmapped wanpipe alarms: %d\n", alarms);
+ zchan->alarm_flags |= ZAP_ALARM_GENERAL;
+ }
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Retrieves an event from a wanpipe span
+ * \param span Span to retrieve event from
+ * \param event Openzap event to return
+ * \return Success or failure
+ */
+ZIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event)
+{
+ uint32_t i,err;
+ zap_oob_event_t event_id;
+ for(i = 1; i <= span->chan_count; i++) {
+ if (span->channels[i]->last_event_time && !zap_test_flag(span->channels[i], ZAP_CHANNEL_EVENT)) {
+ uint32_t diff = (uint32_t)(zap_current_time_in_ms() - span->channels[i]->last_event_time);
+ /* XX printf("%u %u %u\n", diff, (unsigned)zap_current_time_in_ms(), (unsigned)span->channels[i]->last_event_time); */
+ if (zap_test_flag(span->channels[i], ZAP_CHANNEL_WINK)) {
+ if (diff > wp_globals.wink_ms) {
+ zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_WINK);
+ zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_FLASH);
+ zap_set_flag_locked(span->channels[i], ZAP_CHANNEL_OFFHOOK);
+ event_id = ZAP_OOB_OFFHOOK;
+ goto event;
+ }
+ }
+
+ if (zap_test_flag(span->channels[i], ZAP_CHANNEL_FLASH)) {
+ if (diff > wp_globals.flash_ms) {
+ zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_FLASH);
+ zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_WINK);
+ zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_OFFHOOK);
+ event_id = ZAP_OOB_ONHOOK;
+
+ if (span->channels[i]->type == ZAP_CHAN_TYPE_FXO) {
+ zap_channel_t *zchan = span->channels[i];
+ wanpipe_tdm_api_t tdm_api;
+ memset(&tdm_api, 0, sizeof(tdm_api));
+
+ sangoma_tdm_txsig_onhook(zchan->sockfd,&tdm_api);
+ }
+ goto event;
+ }
+ }
+ }
+ if (zap_test_flag(span->channels[i], ZAP_CHANNEL_EVENT)) {
+ wanpipe_tdm_api_t tdm_api;
+ zap_channel_t *zchan = span->channels[i];
+ memset(&tdm_api, 0, sizeof(tdm_api));
+ zap_clear_flag(span->channels[i], ZAP_CHANNEL_EVENT);
+
+ err = sangoma_tdm_read_event(zchan->sockfd, &tdm_api);
+ if (err != ZAP_SUCCESS) {
+ snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+ return ZAP_FAIL;
+ }
+
+ switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) {
+
+ case WP_TDMAPI_EVENT_LINK_STATUS:
+ {
+ zap_sigmsg_t sigmsg;
+ memset(&sigmsg, 0, sizeof(sigmsg));
+ switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
+ case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
+ event_id = ZAP_OOB_ALARM_CLEAR;
+ break;
+ default:
+ event_id = ZAP_OOB_ALARM_TRAP;
+ break;
+ };
+ sigmsg.chan_id = zchan->chan_id;
+ sigmsg.span_id = zchan->span_id;
+ sigmsg.channel = zchan;
+ sigmsg.event_id = (event_id == ZAP_OOB_ALARM_CLEAR) ? ZAP_SIGEVENT_ALARM_CLEAR : ZAP_SIGEVENT_ALARM_TRAP;
+ zap_span_send_signal(zchan->span, &sigmsg);
+ }
+ break;
+
+ case WP_TDMAPI_EVENT_RXHOOK:
+ {
+ if (span->channels[i]->type == ZAP_CHAN_TYPE_FXS) {
+ event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? ZAP_OOB_OFFHOOK : ZAP_OOB_ONHOOK;
+ if (event_id == ZAP_OOB_OFFHOOK) {
+ if (zap_test_flag(span->channels[i], ZAP_CHANNEL_FLASH)) {
+ zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_FLASH);
+ zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_WINK);
+ event_id = ZAP_OOB_FLASH;
+ goto event;
+ } else {
+ zap_set_flag_locked(span->channels[i], ZAP_CHANNEL_WINK);
+ }
+ } else {
+ if (zap_test_flag(span->channels[i], ZAP_CHANNEL_WINK)) {
+ zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_WINK);
+ zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_FLASH);
+ event_id = ZAP_OOB_WINK;
+ goto event;
+ } else {
+ zap_set_flag_locked(span->channels[i], ZAP_CHANNEL_FLASH);
+ }
+ }
+ continue;
+ } else {
+ int err;
+ zap_channel_t *zchan = span->channels[i];
+ err=sangoma_tdm_txsig_onhook(zchan->sockfd,&tdm_api);
+ if (err) {
+ snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "ONHOOK Failed");
+ return ZAP_FAIL;
+ }
+ event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? ZAP_OOB_ONHOOK : ZAP_OOB_NOOP;
+ }
+ }
+ break;
+ case WP_TDMAPI_EVENT_RING_DETECT:
+ {
+ event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? ZAP_OOB_RING_START : ZAP_OOB_RING_STOP;
+ }
+ break;
+ /*
+ disabled this ones when configuring, we don't need them, do we?
+ case WP_TDMAPI_EVENT_RING_TRIP_DETECT:
+ {
+ event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? ZAP_OOB_ONHOOK : ZAP_OOB_OFFHOOK;
+ }
+ break;
+ */
+ case WP_TDMAPI_EVENT_RBS:
+ {
+ event_id = ZAP_OOB_CAS_BITS_CHANGE;
+ span->channels[i]->rx_cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
+ }
+ break;
+ case WP_TDMAPI_EVENT_DTMF:
+ {
+ char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 };
+ event_id = ZAP_OOB_NOOP;
+
+ //zap_log(ZAP_LOG_WARNING, "%d:%d queue hardware dtmf %s %s\n", zchan->span_id, zchan->chan_id, tmp_dtmf,
+ //tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT ? "on" : "off");
+ if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) {
+ zap_set_flag_locked(zchan, ZAP_CHANNEL_MUTE);
+ }
+
+ if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_MUTE);
+ if (zap_test_flag(zchan, ZAP_CHANNEL_INUSE)) {
+ zap_channel_queue_dtmf(zchan, tmp_dtmf);
+ }
+ }
+ }
+ break;
+ case WP_TDMAPI_EVENT_ALARM:
+ {
+ zap_sigmsg_t sigmsg;
+ zap_log(ZAP_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api.wp_tdm_cmd.event.wp_api_event_alarm);
+ memset(&sigmsg, 0, sizeof(sigmsg));
+ event_id = ZAP_OOB_ALARM_TRAP;
+ sigmsg.chan_id = zchan->chan_id;
+ sigmsg.span_id = zchan->span_id;
+ sigmsg.channel = zchan;
+ sigmsg.event_id = (event_id == ZAP_OOB_ALARM_CLEAR) ? ZAP_SIGEVENT_ALARM_CLEAR : ZAP_SIGEVENT_ALARM_TRAP;
+ zap_span_send_signal(zchan->span, &sigmsg);
+ }
+ break;
+ default:
+ {
+ zap_log(ZAP_LOG_WARNING, "Unhandled event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
+ event_id = ZAP_OOB_INVALID;
+ }
+ break;
+ }
+
+ event:
+
+ span->channels[i]->last_event_time = 0;
+ span->event_header.e_type = ZAP_EVENT_OOB;
+ span->event_header.enum_id = event_id;
+ span->event_header.channel = span->channels[i];
+ *event = &span->event_header;
+ return ZAP_SUCCESS;
+ }
+ }
+
+ return ZAP_FAIL;
+
+}
+
+/**
+ * \brief Destroys a Wanpipe Channel
+ * \param zchan Channel to destroy
+ * \return Success
+ */
+static ZIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy)
+{
+#ifdef LIBSANGOMA_VERSION
+ if (zchan->mod_data) {
+ sangoma_wait_obj_t *sangoma_wait_obj;
+ sangoma_wait_obj = zchan->mod_data;
+ zchan->mod_data = NULL;
+ sangoma_wait_obj_delete(&sangoma_wait_obj);
+ }
+#endif
+
+ if (zchan->sockfd > -1) {
+ close(zchan->sockfd);
+ zchan->sockfd = WP_INVALID_SOCKET;
+ }
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Loads wanpipe IO module
+ * \param zio Openzap IO interface
+ * \return Success
+ */
+static ZIO_IO_LOAD_FUNCTION(wanpipe_init)
+{
+ assert(zio != NULL);
+ memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
+
+ wp_globals.codec_ms = 20;
+ wp_globals.wink_ms = 150;
+ wp_globals.flash_ms = 750;
+ wp_globals.ring_on_ms = 2000;
+ wp_globals.ring_off_ms = 4000;
+ wanpipe_interface.name = "wanpipe";
+ wanpipe_interface.configure_span = wanpipe_configure_span;
+ wanpipe_interface.configure = wanpipe_configure;
+ wanpipe_interface.open = wanpipe_open;
+ wanpipe_interface.close = wanpipe_close;
+ wanpipe_interface.command = wanpipe_command;
+ wanpipe_interface.wait = wanpipe_wait;
+ wanpipe_interface.read = wanpipe_read;
+ wanpipe_interface.write = wanpipe_write;
+ wanpipe_interface.poll_event = wanpipe_poll_event;
+ wanpipe_interface.next_event = wanpipe_next_event;
+ wanpipe_interface.channel_destroy = wanpipe_channel_destroy;
+ wanpipe_interface.get_alarms = wanpipe_get_alarms;
+ *zio = &wanpipe_interface;
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Unloads wanpipe IO module
+ * \return Success
+ */
+static ZIO_IO_UNLOAD_FUNCTION(wanpipe_destroy)
+{
+ memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Openzap wanpipe IO module definition
+ */
+EX_DECLARE_DATA zap_module_t zap_module = {
+ "wanpipe",
+ wanpipe_init,
+ wanpipe_destroy,
+};
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4
+ */
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/wanpipe_tdm_api_iface.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/wanpipe_tdm_api_iface.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/wanpipe_tdm_api_iface.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,351 @@
+/*****************************************************************************
+* wanpipe_tdm_api_iface.h
+*
+* WANPIPE(tm) AFT TE1 Hardware Support
+*
+* Authors: Nenad Corbic <ncorbic@sangoma.com>
+*
+* Copyright (c) 2007 - 08, Sangoma Technologies
+* 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 <organization> 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 <copyright holder> ``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 <copyright holder> 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.
+
+* ============================================================================
+* Oct 04, 2005 Nenad Corbic Initial version.
+*
+* Jul 25, 2006 David Rokhvarg <davidr@sangoma.com> Ported to Windows.
+*****************************************************************************/
+
+#ifndef __WANPIPE_TDM_API_IFACE_H_
+#define __WANPIPE_TDM_API_IFACE_H_
+
+
+#if defined(__WINDOWS__)
+typedef HANDLE sng_fd_t;
+#else
+typedef int sng_fd_t;
+#endif
+
+/* Indicate to library that new features exist */
+#define WP_TDM_FEATURE_DTMF_EVENTS 1
+#define WP_TDM_FEATURE_FE_ALARM 1
+#define WP_TDM_FEATURE_EVENTS 1
+#define WP_TDM_FEATURE_LINK_STATUS 1
+
+enum wanpipe_tdm_api_cmds {
+
+ SIOC_WP_TDM_GET_USR_MTU_MRU, /* 0x00 */
+
+ SIOC_WP_TDM_SET_USR_PERIOD, /* 0x01 */
+ SIOC_WP_TDM_GET_USR_PERIOD, /* 0x02 */
+
+ SIOC_WP_TDM_SET_HW_MTU_MRU, /* 0x03 */
+ SIOC_WP_TDM_GET_HW_MTU_MRU, /* 0x04 */
+
+ SIOC_WP_TDM_SET_CODEC, /* 0x05 */
+ SIOC_WP_TDM_GET_CODEC, /* 0x06 */
+
+ SIOC_WP_TDM_SET_POWER_LEVEL, /* 0x07 */
+ SIOC_WP_TDM_GET_POWER_LEVEL, /* 0x08 */
+
+ SIOC_WP_TDM_TOGGLE_RX, /* 0x09 */
+ SIOC_WP_TDM_TOGGLE_TX, /* 0x0A */
+
+ SIOC_WP_TDM_GET_HW_CODING, /* 0x0B */
+ SIOC_WP_TDM_SET_HW_CODING, /* 0x0C */
+
+ SIOC_WP_TDM_GET_FULL_CFG, /* 0x0D */
+
+ SIOC_WP_TDM_SET_EC_TAP, /* 0x0E */
+ SIOC_WP_TDM_GET_EC_TAP, /* 0x0F */
+
+ SIOC_WP_TDM_ENABLE_RBS_EVENTS, /* 0x10 */
+ SIOC_WP_TDM_DISABLE_RBS_EVENTS, /* 0x11 */
+ SIOC_WP_TDM_WRITE_RBS_BITS, /* 0x12 */
+
+ SIOC_WP_TDM_GET_STATS, /* 0x13 */
+ SIOC_WP_TDM_FLUSH_BUFFERS, /* 0x14 */
+
+ SIOC_WP_TDM_READ_EVENT, /* 0x15 */
+
+ SIOC_WP_TDM_SET_EVENT, /* 0x16 */
+
+ SIOC_WP_TDM_SET_RX_GAINS, /* 0x17 */
+ SIOC_WP_TDM_SET_TX_GAINS, /* 0x18 */
+ SIOC_WP_TDM_CLEAR_RX_GAINS, /* 0x19 */
+ SIOC_WP_TDM_CLEAR_TX_GAINS, /* 0x1A */
+
+ SIOC_WP_TDM_GET_FE_ALARMS, /* 0x1B */
+
+ SIOC_WP_TDM_ENABLE_HWEC, /* 0x1C */
+ SIOC_WP_TDM_DISABLE_HWEC, /* 0x1D */
+
+ SIOC_WP_TDM_SET_FE_STATUS, /* 0x1E */
+ SIOC_WP_TDM_GET_FE_STATUS, /* 0x1F */
+
+ SIOC_WP_TDM_GET_HW_DTMF, /* 0x20 */
+
+ SIOC_WP_TDM_NOTSUPP /* */
+
+};
+
+#define SIOC_WP_TDM_GET_LINK_STATUS SIOC_WP_TDM_GET_FE_STATUS
+
+enum wanpipe_tdm_api_events {
+ WP_TDMAPI_EVENT_NONE,
+ WP_TDMAPI_EVENT_RBS,
+ WP_TDMAPI_EVENT_ALARM,
+ WP_TDMAPI_EVENT_DTMF,
+ WP_TDMAPI_EVENT_RM_DTMF,
+ WP_TDMAPI_EVENT_RXHOOK,
+ WP_TDMAPI_EVENT_RING,
+ WP_TDMAPI_EVENT_RING_DETECT,
+ WP_TDMAPI_EVENT_RING_TRIP_DETECT,
+ WP_TDMAPI_EVENT_TONE,
+ WP_TDMAPI_EVENT_TXSIG_KEWL,
+ WP_TDMAPI_EVENT_TXSIG_START,
+ WP_TDMAPI_EVENT_TXSIG_OFFHOOK,
+ WP_TDMAPI_EVENT_TXSIG_ONHOOK,
+ WP_TDMAPI_EVENT_ONHOOKTRANSFER,
+ WP_TDMAPI_EVENT_SETPOLARITY,
+ WP_TDMAPI_EVENT_BRI_CHAN_LOOPBACK,
+ WP_TDMAPI_EVENT_LINK_STATUS
+};
+
+#define WP_TDMAPI_EVENT_FE_ALARM WP_TDMAPI_EVENT_ALARM
+
+
+#define WP_TDMAPI_EVENT_ENABLE 0x01
+#define WP_TDMAPI_EVENT_DISABLE 0x02
+#define WP_TDMAPI_EVENT_MODE_DECODE(mode) \
+ ((mode) == WP_TDMAPI_EVENT_ENABLE) ? "Enable" : \
+ ((mode) == WP_TDMAPI_EVENT_DISABLE) ? "Disable" : \
+ "(Unknown mode)"
+
+#define WPTDM_A_BIT WAN_RBS_SIG_A
+#define WPTDM_B_BIT WAN_RBS_SIG_B
+#define WPTDM_C_BIT WAN_RBS_SIG_C
+#define WPTDM_D_BIT WAN_RBS_SIG_D
+
+#define WP_TDMAPI_EVENT_RXHOOK_OFF 0x01
+#define WP_TDMAPI_EVENT_RXHOOK_ON 0x02
+#define WP_TDMAPI_EVENT_RXHOOK_DECODE(state) \
+ ((state) == WP_TDMAPI_EVENT_RXHOOK_OFF) ? "Off-hook" : \
+ ((state) == WP_TDMAPI_EVENT_RXHOOK_ON) ? "On-hook" : \
+ "(Unknown state)"
+
+#define WP_TDMAPI_EVENT_RING_PRESENT 0x01
+#define WP_TDMAPI_EVENT_RING_STOP 0x02
+#define WP_TDMAPI_EVENT_RING_DECODE(state) \
+ ((state) == WP_TDMAPI_EVENT_RING_PRESENT) ? "Ring Present" : \
+ ((state) == WP_TDMAPI_EVENT_RING_STOP) ? "Ring Stop" : \
+ "(Unknown state)"
+
+#define WP_TDMAPI_EVENT_RING_TRIP_PRESENT 0x01
+#define WP_TDMAPI_EVENT_RING_TRIP_STOP 0x02
+#define WP_TDMAPI_EVENT_RING_TRIP_DECODE(state) \
+ ((state) == WP_TDMAPI_EVENT_RING_TRIP_PRESENT) ? "Ring Present" : \
+ ((state) == WP_TDMAPI_EVENT_RING_TRIP_STOP) ? "Ring Stop" : \
+ "(Unknown state)"
+/*Link Status */
+#define WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED 0x01
+#define WP_TDMAPI_EVENT_LINK_STATUS_DISCONNECTED 0x02
+#define WP_TDMAPI_EVENT_LINK_STATUS_DECODE(status) \
+ ((status) == WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED) ? "Connected" : \
+ ((status) == WP_TDMAPI_EVENT_LINK_STATUS_DISCONNECTED) ? "Disconnected" : \
+ "Unknown"
+#define WP_TDMAPI_EVENT_TONE_DIAL 0x01
+#define WP_TDMAPI_EVENT_TONE_BUSY 0x02
+#define WP_TDMAPI_EVENT_TONE_RING 0x03
+#define WP_TDMAPI_EVENT_TONE_CONGESTION 0x04
+
+/* BRI channels list */
+#define WAN_BRI_BCHAN1 0x01
+#define WAN_BRI_BCHAN2 0x02
+#define WAN_BRI_DCHAN 0x03
+
+
+typedef struct {
+
+ u_int8_t type;
+ u_int8_t mode;
+ u_int32_t time_stamp;
+ u_int8_t channel;
+ u_int32_t chan_map;
+ u_int8_t span;
+ union {
+ struct {
+ u_int8_t alarm;
+ } te1_alarm;
+ struct {
+ u_int8_t rbs_bits;
+ } te1_rbs;
+ struct {
+ u_int8_t state;
+ u_int8_t sig;
+ } rm_hook;
+ struct {
+ u_int8_t state;
+ } rm_ring;
+ struct {
+ u_int8_t type;
+ } rm_tone;
+ struct {
+ u_int8_t digit; /* DTMF: digit */
+ u_int8_t port; /* DTMF: SOUT/ROUT */
+ u_int8_t type; /* DTMF: PRESET/STOP */
+ } dtmf;
+ struct {
+ u_int16_t polarity;
+ u_int16_t ohttimer;
+ } rm_common;
+ struct{
+ u_int16_t status;
+ } linkstatus;
+ } wp_tdm_api_event_u;
+#define wp_tdm_api_event_type type
+#define wp_tdm_api_event_mode mode
+#define wp_tdm_api_event_alarm wp_tdm_api_event_u.te1_alarm.alarm
+#define wp_tdm_api_event_alarm wp_tdm_api_event_u.te1_alarm.alarm
+#define wp_tdm_api_event_rbs_bits wp_tdm_api_event_u.te1_rbs.rbs_bits
+#define wp_tdm_api_event_hook_state wp_tdm_api_event_u.rm_hook.state
+#define wp_tdm_api_event_hook_sig wp_tdm_api_event_u.rm_hook.sig
+#define wp_tdm_api_event_ring_state wp_tdm_api_event_u.rm_ring.state
+#define wp_tdm_api_event_tone_type wp_tdm_api_event_u.rm_tone.type
+#define wp_tdm_api_event_dtmf_digit wp_tdm_api_event_u.dtmf.digit
+#define wp_tdm_api_event_dtmf_type wp_tdm_api_event_u.dtmf.type
+#define wp_tdm_api_event_dtmf_port wp_tdm_api_event_u.dtmf.port
+#define wp_tdm_api_event_ohttimer wp_tdm_api_event_u.rm_common.ohttimer
+#define wp_tdm_api_event_polarity wp_tdm_api_event_u.rm_common.polarity
+#define wp_tdm_api_event_link_status wp_tdm_api_event_u.linkstatus.status
+} wp_tdm_api_event_t;
+
+typedef struct {
+ union {
+ unsigned char reserved[16];
+ }wp_rx_hdr_u;
+} wp_tdm_api_rx_hdr_t;
+
+typedef struct {
+ wp_tdm_api_rx_hdr_t hdr;
+ unsigned char data[1];
+} wp_tdm_api_rx_element_t;
+
+typedef struct {
+ union {
+ struct {
+ unsigned char _rbs_rx_bits;
+ unsigned int _time_stamp;
+ }wp_tx;
+ unsigned char reserved[16];
+ }wp_tx_hdr_u;
+#define wp_api_time_stamp wp_tx_hdr_u.wp_tx._time_stamp
+} wp_tdm_api_tx_hdr_t;
+
+typedef struct {
+ wp_tdm_api_tx_hdr_t hdr;
+ unsigned char data[1];
+} wp_tdm_api_tx_element_t;
+
+
+
+typedef struct wp_tdm_chan_stats
+{
+ unsigned int rx_packets; /* total packets received */
+ unsigned int tx_packets; /* total packets transmitted */
+ unsigned int rx_bytes; /* total bytes received */
+ unsigned int tx_bytes; /* total bytes transmitted */
+ unsigned int rx_errors; /* bad packets received */
+ unsigned int tx_errors; /* packet transmit problems */
+ unsigned int rx_dropped; /* no space in linux buffers */
+ unsigned int tx_dropped; /* no space available in linux */
+ unsigned int multicast; /* multicast packets received */
+#if !defined(__WINDOWS__)
+ unsigned int collisions;
+#endif
+ /* detailed rx_errors: */
+ unsigned int rx_length_errors;
+ unsigned int rx_over_errors; /* receiver ring buff overflow */
+ unsigned int rx_crc_errors; /* recved pkt with crc error */
+ unsigned int rx_frame_errors; /* recv'd frame alignment error */
+#if !defined(__WINDOWS__)
+ unsigned int rx_fifo_errors; /* recv'r fifo overrun */
+#endif
+ unsigned int rx_missed_errors; /* receiver missed packet */
+
+ /* detailed tx_errors */
+#if !defined(__WINDOWS__)
+ unsigned int tx_aborted_errors;
+ unsigned int tx_carrier_errors;
+#endif
+ unsigned int tx_fifo_errors;
+ unsigned int tx_heartbeat_errors;
+ unsigned int tx_window_errors;
+
+}wp_tdm_chan_stats_t;
+
+
+
+typedef struct wanpipe_tdm_api_cmd{
+ unsigned int cmd;
+ unsigned int hw_tdm_coding; /* Set/Get HW TDM coding: uLaw muLaw */
+ unsigned int hw_mtu_mru; /* Set/Get HW TDM MTU/MRU */
+ unsigned int usr_period; /* Set/Get User Period in ms */
+ unsigned int tdm_codec; /* Set/Get TDM Codec: SLinear */
+ unsigned int power_level; /* Set/Get Power level treshold */
+ unsigned int rx_disable; /* Enable/Disable Rx */
+ unsigned int tx_disable; /* Enable/Disable Tx */
+ unsigned int usr_mtu_mru; /* Set/Get User TDM MTU/MRU */
+ unsigned int ec_tap; /* Echo Cancellation Tap */
+ unsigned int rbs_poll; /* Enable/Disable RBS Polling */
+ unsigned int rbs_rx_bits; /* Rx RBS Bits */
+ unsigned int rbs_tx_bits; /* Tx RBS Bits */
+ unsigned int hdlc; /* HDLC based device */
+ unsigned int idle_flag; /* IDLE flag to Tx */
+ unsigned int fe_alarms; /* FE Alarms detected */
+ wp_tdm_chan_stats_t stats; /* TDM Statistics */
+ /* Do NOT add anything above this! Important for binary backward compatibility. */
+ wp_tdm_api_event_t event; /* TDM Event */
+ unsigned int data_len;
+ void *data;
+ unsigned char fe_status; /* FE status - Connected or Disconnected */
+ unsigned int hw_dtmf; /* HW DTMF enabled */
+}wanpipe_tdm_api_cmd_t;
+
+typedef struct wanpipe_tdm_api_event{
+ int (*wp_rbs_event)(sng_fd_t fd, unsigned char rbs_bits);
+ int (*wp_dtmf_event)(sng_fd_t fd, unsigned char dtmf, unsigned char type, unsigned char port);
+ int (*wp_rxhook_event)(sng_fd_t fd, unsigned char hook_state);
+ int (*wp_ring_detect_event)(sng_fd_t fd, unsigned char ring_state);
+ int (*wp_ring_trip_detect_event)(sng_fd_t fd, unsigned char ring_state);
+ int (*wp_fe_alarm_event)(sng_fd_t fd, unsigned char fe_alarm_event);
+ int (*wp_link_status_event)(sng_fd_t fd, unsigned char link_status_event);
+}wanpipe_tdm_api_event_t;
+
+typedef struct wanpipe_tdm_api{
+ wanpipe_tdm_api_cmd_t wp_tdm_cmd;
+ wanpipe_tdm_api_event_t wp_tdm_event;
+}wanpipe_tdm_api_t;
+
+
+#endif
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1251 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+
+#include "openzap.h"
+#include "ozmod_zt.h"
+
+/**
+ * \brief Zaptel globals
+ */
+static struct {
+ uint32_t codec_ms;
+ uint32_t wink_ms;
+ uint32_t flash_ms;
+ uint32_t eclevel;
+ uint32_t etlevel;
+ float rxgain;
+ float txgain;
+} zt_globals;
+
+/**
+ * \brief General IOCTL codes
+ */
+struct ioctl_codes {
+ int GET_BLOCKSIZE;
+ int SET_BLOCKSIZE;
+ int FLUSH;
+ int SYNC;
+ int GET_PARAMS;
+ int SET_PARAMS;
+ int HOOK;
+ int GETEVENT;
+ int IOMUX;
+ int SPANSTAT;
+ int MAINT;
+ int GETCONF;
+ int SETCONF;
+ int CONFLINK;
+ int CONFDIAG;
+ int GETGAINS;
+ int SETGAINS;
+ int SPANCONFIG;
+ int CHANCONFIG;
+ int SET_BUFINFO;
+ int GET_BUFINFO;
+ int AUDIOMODE;
+ int ECHOCANCEL;
+ int HDLCRAWMODE;
+ int HDLCFCSMODE;
+ int SPECIFY;
+ int SETLAW;
+ int SETLINEAR;
+ int GETCONFMUTE;
+ int ECHOTRAIN;
+ int SETTXBITS;
+ int GETRXBITS;
+};
+
+/**
+ * \brief Zaptel IOCTL codes
+ */
+static struct ioctl_codes zt_ioctl_codes = {
+ .GET_BLOCKSIZE = ZT_GET_BLOCKSIZE,
+ .SET_BLOCKSIZE = ZT_SET_BLOCKSIZE,
+ .FLUSH = ZT_FLUSH,
+ .SYNC = ZT_SYNC,
+ .GET_PARAMS = ZT_GET_PARAMS,
+ .SET_PARAMS = ZT_SET_PARAMS,
+ .HOOK = ZT_HOOK,
+ .GETEVENT = ZT_GETEVENT,
+ .IOMUX = ZT_IOMUX,
+ .SPANSTAT = ZT_SPANSTAT,
+ .MAINT = ZT_MAINT,
+ .GETCONF = ZT_GETCONF,
+ .SETCONF = ZT_SETCONF,
+ .CONFLINK = ZT_CONFLINK,
+ .CONFDIAG = ZT_CONFDIAG,
+ .GETGAINS = ZT_GETGAINS,
+ .SETGAINS = ZT_SETGAINS,
+ .SPANCONFIG = ZT_SPANCONFIG,
+ .CHANCONFIG = ZT_CHANCONFIG,
+ .SET_BUFINFO = ZT_SET_BUFINFO,
+ .GET_BUFINFO = ZT_GET_BUFINFO,
+ .AUDIOMODE = ZT_AUDIOMODE,
+ .ECHOCANCEL = ZT_ECHOCANCEL,
+ .HDLCRAWMODE = ZT_HDLCRAWMODE,
+ .HDLCFCSMODE = ZT_HDLCFCSMODE,
+ .SPECIFY = ZT_SPECIFY,
+ .SETLAW = ZT_SETLAW,
+ .SETLINEAR = ZT_SETLINEAR,
+ .GETCONFMUTE = ZT_GETCONFMUTE,
+ .ECHOTRAIN = ZT_ECHOTRAIN,
+ .SETTXBITS = ZT_SETTXBITS,
+ .GETRXBITS = ZT_GETRXBITS
+};
+
+/**
+ * \brief Dahdi IOCTL codes
+ */
+static struct ioctl_codes dahdi_ioctl_codes = {
+ .GET_BLOCKSIZE = DAHDI_GET_BLOCKSIZE,
+ .SET_BLOCKSIZE = DAHDI_SET_BLOCKSIZE,
+ .FLUSH = DAHDI_FLUSH,
+ .SYNC = DAHDI_SYNC,
+ .GET_PARAMS = DAHDI_GET_PARAMS,
+ .SET_PARAMS = DAHDI_SET_PARAMS,
+ .HOOK = DAHDI_HOOK,
+ .GETEVENT = DAHDI_GETEVENT,
+ .IOMUX = DAHDI_IOMUX,
+ .SPANSTAT = DAHDI_SPANSTAT,
+ .MAINT = DAHDI_MAINT,
+ .GETCONF = DAHDI_GETCONF,
+ .SETCONF = DAHDI_SETCONF,
+ .CONFLINK = DAHDI_CONFLINK,
+ .CONFDIAG = DAHDI_CONFDIAG,
+ .GETGAINS = DAHDI_GETGAINS,
+ .SETGAINS = DAHDI_SETGAINS,
+ .SPANCONFIG = DAHDI_SPANCONFIG,
+ .CHANCONFIG = DAHDI_CHANCONFIG,
+ .SET_BUFINFO = DAHDI_SET_BUFINFO,
+ .GET_BUFINFO = DAHDI_GET_BUFINFO,
+ .AUDIOMODE = DAHDI_AUDIOMODE,
+ .ECHOCANCEL = DAHDI_ECHOCANCEL,
+ .HDLCRAWMODE = DAHDI_HDLCRAWMODE,
+ .HDLCFCSMODE = DAHDI_HDLCFCSMODE,
+ .SPECIFY = DAHDI_SPECIFY,
+ .SETLAW = DAHDI_SETLAW,
+ .SETLINEAR = DAHDI_SETLINEAR,
+ .GETCONFMUTE = DAHDI_GETCONFMUTE,
+ .ECHOTRAIN = DAHDI_ECHOTRAIN,
+ .SETTXBITS = DAHDI_SETTXBITS,
+ .GETRXBITS = DAHDI_GETRXBITS
+};
+
+#define ZT_INVALID_SOCKET -1
+static struct ioctl_codes codes;
+static const char *ctlpath = NULL;
+static const char *chanpath = NULL;
+
+static const char dahdi_ctlpath[] = "/dev/dahdi/ctl";
+static const char dahdi_chanpath[] = "/dev/dahdi/channel";
+
+static const char zt_ctlpath[] = "/dev/zap/ctl";
+static const char zt_chanpath[] = "/dev/zap/channel";
+
+static zap_socket_t CONTROL_FD = ZT_INVALID_SOCKET;
+
+ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event);
+ZIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event);
+
+/**
+ * \brief Initialises codec, and rx/tx gains
+ * \param g Structure for gains to be initialised
+ * \param rxgain RX gain value
+ * \param txgain TX gain value
+ * \param codec Codec
+ */
+static void zt_build_gains(struct zt_gains *g, float rxgain, float txgain, int codec)
+{
+ int j;
+ int k;
+ float linear_rxgain = pow(10.0, rxgain / 20.0);
+ float linear_txgain = pow(10.0, txgain / 20.0);
+
+ switch (codec) {
+ case ZAP_CODEC_ALAW:
+ for (j = 0; j < (sizeof(g->receive_gain) / sizeof(g->receive_gain[0])); j++) {
+ if (rxgain) {
+ k = (int) (((float) alaw_to_linear(j)) * linear_rxgain);
+ if (k > 32767) k = 32767;
+ if (k < -32767) k = -32767;
+ g->receive_gain[j] = linear_to_alaw(k);
+ } else {
+ g->receive_gain[j] = j;
+ }
+ if (txgain) {
+ k = (int) (((float) alaw_to_linear(j)) * linear_txgain);
+ if (k > 32767) k = 32767;
+ if (k < -32767) k = -32767;
+ g->transmit_gain[j] = linear_to_alaw(k);
+ } else {
+ g->transmit_gain[j] = j;
+ }
+ }
+ break;
+ case ZAP_CODEC_ULAW:
+ for (j = 0; j < (sizeof(g->receive_gain) / sizeof(g->receive_gain[0])); j++) {
+ if (rxgain) {
+ k = (int) (((float) ulaw_to_linear(j)) * linear_rxgain);
+ if (k > 32767) k = 32767;
+ if (k < -32767) k = -32767;
+ g->receive_gain[j] = linear_to_ulaw(k);
+ } else {
+ g->receive_gain[j] = j;
+ }
+ if (txgain) {
+ k = (int) (((float) ulaw_to_linear(j)) * linear_txgain);
+ if (k > 32767) k = 32767;
+ if (k < -32767) k = -32767;
+ g->transmit_gain[j] = linear_to_ulaw(k);
+ } else {
+ g->transmit_gain[j] = j;
+ }
+ }
+ break;
+ }
+}
+
+/**
+ * \brief Initialises a range of zaptel channels
+ * \param span Openzap span
+ * \param start Initial wanpipe channel number
+ * \param end Final wanpipe channel number
+ * \param type Openzap channel type
+ * \param name Openzap span name
+ * \param number Openzap span number
+ * \param cas_bits CAS bits
+ * \return number of spans configured
+ */
+static unsigned zt_open_range(zap_span_t *span, unsigned start, unsigned end, zap_chan_type_t type, char *name, char *number, unsigned char cas_bits)
+{
+ unsigned configured = 0, x;
+ zt_params_t ztp;
+
+ memset(&ztp, 0, sizeof(ztp));
+
+ if (type == ZAP_CHAN_TYPE_CAS) {
+ zap_log(ZAP_LOG_DEBUG, "Configuring CAS channels with abcd == 0x%X\n", cas_bits);
+ }
+ for(x = start; x < end; x++) {
+ zap_channel_t *zchan;
+ zap_socket_t sockfd = ZT_INVALID_SOCKET;
+ int len;
+
+ sockfd = open(chanpath, O_RDWR);
+ if (sockfd != ZT_INVALID_SOCKET && zap_span_add_channel(span, sockfd, type, &zchan) == ZAP_SUCCESS) {
+
+ if (ioctl(sockfd, codes.SPECIFY, &x)) {
+ zap_log(ZAP_LOG_ERROR, "failure configuring device %s chan %d fd %d (%s)\n", chanpath, x, sockfd, strerror(errno));
+ close(sockfd);
+ continue;
+ }
+
+ if (zchan->type == ZAP_CHAN_TYPE_DQ921) {
+ struct zt_bufferinfo binfo;
+ memset(&binfo, 0, sizeof(binfo));
+ binfo.txbufpolicy = 0;
+ binfo.rxbufpolicy = 0;
+ binfo.numbufs = 32;
+ binfo.bufsize = 1024;
+ if (ioctl(sockfd, codes.SET_BUFINFO, &binfo)) {
+ zap_log(ZAP_LOG_ERROR, "failure configuring device %s as OpenZAP device %d:%d fd:%d\n", chanpath, zchan->span_id, zchan->chan_id, sockfd);
+ close(sockfd);
+ continue;
+ }
+ }
+
+ if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO) {
+ struct zt_chanconfig cc;
+ memset(&cc, 0, sizeof(cc));
+ cc.chan = cc.master = x;
+
+ switch(type) {
+ case ZAP_CHAN_TYPE_FXS:
+ {
+ switch(span->start_type) {
+ case ZAP_ANALOG_START_KEWL:
+ cc.sigtype = ZT_SIG_FXOKS;
+ break;
+ case ZAP_ANALOG_START_LOOP:
+ cc.sigtype = ZT_SIG_FXOLS;
+ break;
+ case ZAP_ANALOG_START_GROUND:
+ cc.sigtype = ZT_SIG_FXOGS;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case ZAP_CHAN_TYPE_FXO:
+ {
+ switch(span->start_type) {
+ case ZAP_ANALOG_START_KEWL:
+ cc.sigtype = ZT_SIG_FXSKS;
+ break;
+ case ZAP_ANALOG_START_LOOP:
+ cc.sigtype = ZT_SIG_FXSLS;
+ break;
+ case ZAP_ANALOG_START_GROUND:
+ cc.sigtype = ZT_SIG_FXSGS;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (ioctl(CONTROL_FD, codes.CHANCONFIG, &cc)) {
+ zap_log(ZAP_LOG_WARNING, "this ioctl fails on older zaptel but is harmless if you used ztcfg\n[device %s chan %d fd %d (%s)]\n", chanpath, x, CONTROL_FD, strerror(errno));
+ }
+ }
+
+ if (type == ZAP_CHAN_TYPE_CAS) {
+ struct zt_chanconfig cc;
+ memset(&cc, 0, sizeof(cc));
+ cc.chan = cc.master = x;
+ cc.sigtype = ZT_SIG_CAS;
+ cc.idlebits = cas_bits;
+ if (ioctl(CONTROL_FD, codes.CHANCONFIG, &cc)) {
+ zap_log(ZAP_LOG_ERROR, "failure configuring device %s as OpenZAP device %d:%d fd:%d err:%s", chanpath, zchan->span_id, zchan->chan_id, sockfd, strerror(errno));
+ close(sockfd);
+ continue;
+ }
+ }
+
+ if (zchan->type != ZAP_CHAN_TYPE_DQ921 && zchan->type != ZAP_CHAN_TYPE_DQ931) {
+ len = zt_globals.codec_ms * 8;
+ if (ioctl(zchan->sockfd, codes.SET_BLOCKSIZE, &len)) {
+ zap_log(ZAP_LOG_ERROR, "failure configuring device %s as OpenZAP device %d:%d fd:%d err:%s\n",
+ chanpath, zchan->span_id, zchan->chan_id, sockfd, strerror(errno));
+ close(sockfd);
+ continue;
+ }
+
+ zchan->packet_len = len;
+ zchan->effective_interval = zchan->native_interval = zchan->packet_len / 8;
+
+ if (zchan->effective_codec == ZAP_CODEC_SLIN) {
+ zchan->packet_len *= 2;
+ }
+ }
+
+ if (ioctl(sockfd, codes.GET_PARAMS, &ztp) < 0) {
+ zap_log(ZAP_LOG_ERROR, "failure configuring device %s as OpenZAP device %d:%d fd:%d\n", chanpath, zchan->span_id, zchan->chan_id, sockfd);
+ close(sockfd);
+ continue;
+ }
+
+ if (zchan->type == ZAP_CHAN_TYPE_DQ921) {
+ if (
+ (ztp.sig_type != ZT_SIG_HDLCRAW) &&
+ (ztp.sig_type != ZT_SIG_HDLCFCS) &&
+ (ztp.sig_type != ZT_SIG_HARDHDLC)
+ ) {
+ zap_log(ZAP_LOG_ERROR, "Failure configuring device %s as OpenZAP device %d:%d fd:%d, hardware signaling is not HDLC, fix your Zap/DAHDI configuration!\n", chanpath, zchan->span_id, zchan->chan_id, sockfd);
+ close(sockfd);
+ continue;
+ }
+ }
+
+ zap_log(ZAP_LOG_INFO, "configuring device %s channel %d as OpenZAP device %d:%d fd:%d\n", chanpath, x, zchan->span_id, zchan->chan_id, sockfd);
+
+ zchan->rate = 8000;
+ zchan->physical_span_id = ztp.span_no;
+ zchan->physical_chan_id = ztp.chan_no;
+
+ if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO || type == ZAP_CHAN_TYPE_EM || type == ZAP_CHAN_TYPE_B) {
+ if (ztp.g711_type == ZT_G711_ALAW) {
+ zchan->native_codec = zchan->effective_codec = ZAP_CODEC_ALAW;
+ } else if (ztp.g711_type == ZT_G711_MULAW) {
+ zchan->native_codec = zchan->effective_codec = ZAP_CODEC_ULAW;
+ } else {
+ int type;
+
+ if (zchan->span->trunk_type == ZAP_TRUNK_E1) {
+ type = ZAP_CODEC_ALAW;
+ } else {
+ type = ZAP_CODEC_ULAW;
+ }
+
+ zchan->native_codec = zchan->effective_codec = type;
+
+ }
+ }
+
+ ztp.wink_time = zt_globals.wink_ms;
+ ztp.flash_time = zt_globals.flash_ms;
+
+ if (ioctl(sockfd, codes.SET_PARAMS, &ztp) < 0) {
+ zap_log(ZAP_LOG_ERROR, "failure configuring device %s as OpenZAP device %d:%d fd:%d\n", chanpath, zchan->span_id, zchan->chan_id, sockfd);
+ close(sockfd);
+ continue;
+ }
+
+ if (!zap_strlen_zero(name)) {
+ zap_copy_string(zchan->chan_name, name, sizeof(zchan->chan_name));
+ }
+ if (!zap_strlen_zero(number)) {
+ zap_copy_string(zchan->chan_number, number, sizeof(zchan->chan_number));
+ }
+ configured++;
+ } else {
+ zap_log(ZAP_LOG_ERROR, "failure configuring device %s\n", chanpath);
+ }
+ }
+
+
+
+ return configured;
+}
+
+/**
+ * \brief Initialises an openzap zaptel span from a configuration string
+ * \param span Openzap span
+ * \param str Configuration string
+ * \param type Openzap span type
+ * \param name Openzap span name
+ * \param number Openzap span number
+ * \return Success or failure
+ */
+static ZIO_CONFIGURE_SPAN_FUNCTION(zt_configure_span)
+{
+
+ int items, i;
+ char *mydata, *item_list[10];
+ char *ch, *mx;
+ unsigned char cas_bits = 0;
+ int channo;
+ int top = 0;
+ unsigned configured = 0;
+
+ assert(str != NULL);
+
+
+ mydata = strdup(str);
+ assert(mydata != NULL);
+
+
+ items = zap_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
+
+ for(i = 0; i < items; i++) {
+ ch = item_list[i];
+
+ if (!(ch)) {
+ zap_log(ZAP_LOG_ERROR, "Invalid input\n");
+ continue;
+ }
+
+ channo = atoi(ch);
+
+ if (channo < 0) {
+ zap_log(ZAP_LOG_ERROR, "Invalid channel number %d\n", channo);
+ continue;
+ }
+
+ if ((mx = strchr(ch, '-'))) {
+ mx++;
+ top = atoi(mx) + 1;
+ } else {
+ top = channo + 1;
+ }
+
+
+ if (top < 0) {
+ zap_log(ZAP_LOG_ERROR, "Invalid range number %d\n", top);
+ continue;
+ }
+ if (ZAP_CHAN_TYPE_CAS == type && zap_config_get_cas_bits(ch, &cas_bits)) {
+ zap_log(ZAP_LOG_ERROR, "Failed to get CAS bits in CAS channel\n");
+ continue;
+ }
+ configured += zt_open_range(span, channo, top, type, name, number, cas_bits);
+
+ }
+
+ free(mydata);
+
+ return configured;
+
+}
+
+/**
+ * \brief Process configuration variable for a zaptel profile
+ * \param category Wanpipe profile name
+ * \param var Variable name
+ * \param val Variable value
+ * \param lineno Line number from configuration file
+ * \return Success
+ */
+static ZIO_CONFIGURE_FUNCTION(zt_configure)
+{
+
+ int num;
+ float fnum;
+
+ if (!strcasecmp(category, "defaults")) {
+ if (!strcasecmp(var, "codec_ms")) {
+ num = atoi(val);
+ if (num < 10 || num > 60) {
+ zap_log(ZAP_LOG_WARNING, "invalid codec ms at line %d\n", lineno);
+ } else {
+ zt_globals.codec_ms = num;
+ }
+ } else if (!strcasecmp(var, "wink_ms")) {
+ num = atoi(val);
+ if (num < 50 || num > 3000) {
+ zap_log(ZAP_LOG_WARNING, "invalid wink ms at line %d\n", lineno);
+ } else {
+ zt_globals.wink_ms = num;
+ }
+ } else if (!strcasecmp(var, "flash_ms")) {
+ num = atoi(val);
+ if (num < 50 || num > 3000) {
+ zap_log(ZAP_LOG_WARNING, "invalid flash ms at line %d\n", lineno);
+ } else {
+ zt_globals.flash_ms = num;
+ }
+ } else if (!strcasecmp(var, "echo_cancel_level")) {
+ num = atoi(val);
+ if (num < 0 || num > 256) {
+ zap_log(ZAP_LOG_WARNING, "invalid echo can val at line %d\n", lineno);
+ } else {
+ zt_globals.eclevel = num;
+ }
+ } else if (!strcasecmp(var, "echo_train_level")) {
+ if (zt_globals.eclevel < 1) {
+ zap_log(ZAP_LOG_WARNING, "can't set echo train level without setting echo cancel level first at line %d\n", lineno);
+ } else {
+ num = atoi(val);
+ if (num < 0 || num > 256) {
+ zap_log(ZAP_LOG_WARNING, "invalid echo can val at line %d\n", lineno);
+ } else {
+ zt_globals.etlevel = num;
+ }
+ }
+ } else if (!strcasecmp(var, "rxgain")) {
+ fnum = (float)atof(val);
+ if (fnum < -100.0 || fnum > 100.0) {
+ zap_log(ZAP_LOG_WARNING, "invalid rxgain val at line %d\n", lineno);
+ } else {
+ zt_globals.rxgain = fnum;
+ zap_log(ZAP_LOG_INFO, "Setting rxgain val to %f\n", fnum);
+ }
+
+ } else if (!strcasecmp(var, "txgain")) {
+ fnum = (float)atof(val);
+ if (fnum < -100.0 || fnum > 100.0) {
+ zap_log(ZAP_LOG_WARNING, "invalid txgain val at line %d\n", lineno);
+ } else {
+ zt_globals.txgain = fnum;
+ zap_log(ZAP_LOG_INFO, "Setting txgain val to %f\n", fnum);
+ }
+
+ }
+ }
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Opens a zaptel channel
+ * \param zchan Channel to open
+ * \return Success or failure
+ */
+static ZIO_OPEN_FUNCTION(zt_open)
+{
+ zap_channel_set_feature(zchan, ZAP_CHANNEL_FEATURE_INTERVAL);
+
+ if (zchan->type == ZAP_CHAN_TYPE_DQ921 || zchan->type == ZAP_CHAN_TYPE_DQ931) {
+ zchan->native_codec = zchan->effective_codec = ZAP_CODEC_NONE;
+ } else {
+ int blocksize = zt_globals.codec_ms * (zchan->rate / 1000);
+ int err;
+ if ((err = ioctl(zchan->sockfd, codes.SET_BLOCKSIZE, &blocksize))) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
+ return ZAP_FAIL;
+ } else {
+ zchan->effective_interval = zchan->native_interval;
+ zchan->packet_len = blocksize;
+ zchan->native_codec = zchan->effective_codec;
+ }
+
+ if (zchan->type == ZAP_CHAN_TYPE_B) {
+ int one = 1;
+ if (ioctl(zchan->sockfd, codes.AUDIOMODE, &one)) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
+ zap_log(ZAP_LOG_ERROR, "%s\n", zchan->last_error);
+ return ZAP_FAIL;
+ }
+ }
+
+ if (zt_globals.rxgain || zt_globals.txgain) {
+ struct zt_gains gains;
+ memset(&gains, 0, sizeof(gains));
+
+ gains.chan_no = zchan->physical_chan_id;
+ zt_build_gains(&gains, zt_globals.rxgain, zt_globals.txgain, zchan->native_codec);
+
+ if(zt_globals.rxgain)
+ zap_log(ZAP_LOG_INFO, "Setting rxgain to %f on channel %d\n", zt_globals.rxgain, gains.chan_no);
+
+ if(zt_globals.txgain)
+ zap_log(ZAP_LOG_INFO, "Setting txgain to %f on channel %d\n", zt_globals.txgain, gains.chan_no);
+
+ if (ioctl(zchan->sockfd, codes.SETGAINS, &gains) < 0) {
+ zap_log(ZAP_LOG_ERROR, "failure configuring device %s as OpenZAP device %d:%d fd:%d\n", chanpath, zchan->span_id, zchan->chan_id, zchan->sockfd);
+ }
+ }
+
+ if (zt_globals.eclevel >= 0) {
+ int len = zt_globals.eclevel;
+
+ if (len) {
+ zap_log(ZAP_LOG_INFO, "Setting echo cancel to %d taps for %d:%d\n", len, zchan->span_id, zchan->chan_id);
+ } else {
+ zap_log(ZAP_LOG_INFO, "Disable echo cancel for %d:%d\n", zchan->span_id, zchan->chan_id);
+ }
+
+ if (ioctl(zchan->sockfd, codes.ECHOCANCEL, &len)) {
+ zap_log(ZAP_LOG_WARNING, "Echo cancel not available for %d:%d\n", zchan->span_id, zchan->chan_id);
+ } else if (zt_globals.etlevel >= 0) {
+ len = zt_globals.etlevel;
+ if (ioctl(zchan->sockfd, codes.ECHOTRAIN, &len)) {
+ zap_log(ZAP_LOG_WARNING, "Echo training not available for %d:%d\n", zchan->span_id, zchan->chan_id);
+ }
+ }
+ }
+
+ }
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Closes zaptel channel
+ * \param zchan Channel to close
+ * \return Success
+ */
+static ZIO_CLOSE_FUNCTION(zt_close)
+{
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Executes an Openzap command on a zaptel channel
+ * \param zchan Channel to execute command on
+ * \param command Openzap command to execute
+ * \param obj Object (unused)
+ * \return Success or failure
+ */
+static ZIO_COMMAND_FUNCTION(zt_command)
+{
+ zt_params_t ztp;
+ int err = 0;
+
+ memset(&ztp, 0, sizeof(ztp));
+
+ switch(command) {
+ case ZAP_COMMAND_ENABLE_ECHOCANCEL:
+ {
+ int level = ZAP_COMMAND_OBJ_INT;
+ err = ioctl(zchan->sockfd, codes.ECHOCANCEL, &level);
+ ZAP_COMMAND_OBJ_INT = level;
+ }
+ case ZAP_COMMAND_DISABLE_ECHOCANCEL:
+ {
+ int level = 0;
+ err = ioctl(zchan->sockfd, codes.ECHOCANCEL, &level);
+ ZAP_COMMAND_OBJ_INT = level;
+ }
+ break;
+ case ZAP_COMMAND_ENABLE_ECHOTRAIN:
+ {
+ int level = ZAP_COMMAND_OBJ_INT;
+ err = ioctl(zchan->sockfd, codes.ECHOTRAIN, &level);
+ ZAP_COMMAND_OBJ_INT = level;
+ }
+ case ZAP_COMMAND_DISABLE_ECHOTRAIN:
+ {
+ int level = 0;
+ err = ioctl(zchan->sockfd, codes.ECHOTRAIN, &level);
+ ZAP_COMMAND_OBJ_INT = level;
+ }
+ break;
+ case ZAP_COMMAND_OFFHOOK:
+ {
+ int command = ZT_OFFHOOK;
+ if (ioctl(zchan->sockfd, codes.HOOK, &command)) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "OFFHOOK Failed");
+ return ZAP_FAIL;
+ }
+ zap_set_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
+ }
+ break;
+ case ZAP_COMMAND_ONHOOK:
+ {
+ int command = ZT_ONHOOK;
+ if (ioctl(zchan->sockfd, codes.HOOK, &command)) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "ONHOOK Failed");
+ return ZAP_FAIL;
+ }
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
+ }
+ break;
+ case ZAP_COMMAND_FLASH:
+ {
+ int command = ZT_FLASH;
+ if (ioctl(zchan->sockfd, codes.HOOK, &command)) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "FLASH Failed");
+ return ZAP_FAIL;
+ }
+ }
+ break;
+ case ZAP_COMMAND_WINK:
+ {
+ int command = ZT_WINK;
+ if (ioctl(zchan->sockfd, codes.HOOK, &command)) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "WINK Failed");
+ return ZAP_FAIL;
+ }
+ }
+ break;
+ case ZAP_COMMAND_GENERATE_RING_ON:
+ {
+ int command = ZT_RING;
+ if (ioctl(zchan->sockfd, codes.HOOK, &command)) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring Failed");
+ return ZAP_FAIL;
+ }
+ zap_set_flag_locked(zchan, ZAP_CHANNEL_RINGING);
+ }
+ break;
+ case ZAP_COMMAND_GENERATE_RING_OFF:
+ {
+ int command = ZT_RINGOFF;
+ if (ioctl(zchan->sockfd, codes.HOOK, &command)) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring-off failed");
+ return ZAP_FAIL;
+ }
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_RINGING);
+ }
+ break;
+ case ZAP_COMMAND_GET_INTERVAL:
+ {
+
+ if (!(err = ioctl(zchan->sockfd, codes.GET_BLOCKSIZE, &zchan->packet_len))) {
+ zchan->native_interval = zchan->packet_len / 8;
+ if (zchan->effective_codec == ZAP_CODEC_SLIN) {
+ zchan->packet_len *= 2;
+ }
+ ZAP_COMMAND_OBJ_INT = zchan->native_interval;
+ }
+ }
+ break;
+ case ZAP_COMMAND_SET_INTERVAL:
+ {
+ int interval = ZAP_COMMAND_OBJ_INT;
+ int len = interval * 8;
+
+ if (!(err = ioctl(zchan->sockfd, codes.SET_BLOCKSIZE, &len))) {
+ zchan->packet_len = len;
+ zchan->effective_interval = zchan->native_interval = zchan->packet_len / 8;
+
+ if (zchan->effective_codec == ZAP_CODEC_SLIN) {
+ zchan->packet_len *= 2;
+ }
+ }
+ }
+ break;
+ case ZAP_COMMAND_SET_CAS_BITS:
+ {
+ int bits = ZAP_COMMAND_OBJ_INT;
+ err = ioctl(zchan->sockfd, codes.SETTXBITS, &bits);
+ }
+ break;
+ case ZAP_COMMAND_GET_CAS_BITS:
+ {
+ err = ioctl(zchan->sockfd, codes.GETRXBITS, &zchan->rx_cas_bits);
+ if (!err) {
+ ZAP_COMMAND_OBJ_INT = zchan->rx_cas_bits;
+ }
+ }
+ break;
+ case ZAP_COMMAND_FLUSH_TX_BUFFERS:
+ {
+ int flushmode = ZT_FLUSH_WRITE;
+ err = ioctl(zchan->sockfd, codes.FLUSH, &flushmode);
+ }
+ break;
+ case ZAP_COMMAND_FLUSH_RX_BUFFERS:
+ {
+ int flushmode = ZT_FLUSH_READ;
+ err = ioctl(zchan->sockfd, codes.FLUSH, &flushmode);
+ }
+ break;
+ case ZAP_COMMAND_FLUSH_BUFFERS:
+ {
+ int flushmode = ZT_FLUSH_BOTH;
+ err = ioctl(zchan->sockfd, codes.FLUSH, &flushmode);
+ }
+ break;
+ default:
+ err = ZAP_NOTIMPL;
+ break;
+ };
+
+ if (err && err != ZAP_NOTIMPL) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
+ return ZAP_FAIL;
+ }
+
+
+ return err == 0 ? ZAP_SUCCESS : err;
+}
+
+/**
+ * \brief Gets alarms from a zaptel Channel
+ * \param zchan Channel to get alarms from
+ * \return Success or failure
+ */
+static ZIO_GET_ALARMS_FUNCTION(zt_get_alarms)
+{
+ struct zt_spaninfo info;
+
+ memset(&info, 0, sizeof(info));
+ info.span_no = zchan->physical_span_id;
+
+ if (ioctl(CONTROL_FD, codes.SPANSTAT, &info)) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "ioctl failed (%s)", strerror(errno));
+ snprintf(zchan->span->last_error, sizeof(zchan->span->last_error), "ioctl failed (%s)", strerror(errno));
+ return ZAP_FAIL;
+ }
+
+ zchan->alarm_flags = info.alarms;
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Waits for an event on a zaptel channel
+ * \param zchan Channel to open
+ * \param flags Type of event to wait for
+ * \param to Time to wait (in ms)
+ * \return Success, failure or timeout
+ */
+static ZIO_WAIT_FUNCTION(zt_wait)
+{
+ int32_t inflags = 0;
+ int result;
+ struct pollfd pfds[1];
+
+ if (*flags & ZAP_READ) {
+ inflags |= POLLIN;
+ }
+
+ if (*flags & ZAP_WRITE) {
+ inflags |= POLLOUT;
+ }
+
+ if (*flags & ZAP_EVENTS) {
+ inflags |= POLLPRI;
+ }
+
+
+ memset(&pfds[0], 0, sizeof(pfds[0]));
+ pfds[0].fd = zchan->sockfd;
+ pfds[0].events = inflags;
+ result = poll(pfds, 1, to);
+ *flags = 0;
+
+ if (pfds[0].revents & POLLERR) {
+ result = -1;
+ }
+
+ if (result > 0) {
+ inflags = pfds[0].revents;
+ }
+
+ *flags = ZAP_NO_FLAGS;
+
+ if (result < 0){
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "Poll failed");
+ return ZAP_FAIL;
+ }
+
+ if (result == 0) {
+ return ZAP_TIMEOUT;
+ }
+
+ if (inflags & POLLIN) {
+ *flags |= ZAP_READ;
+ }
+
+ if (inflags & POLLOUT) {
+ *flags |= ZAP_WRITE;
+ }
+
+ if (inflags & POLLPRI) {
+ *flags |= ZAP_EVENTS;
+ }
+
+ return ZAP_SUCCESS;
+
+}
+
+/**
+ * \brief Checks for events on a zaptel span
+ * \param span Span to check for events
+ * \param ms Time to wait for event
+ * \return Success if event is waiting or failure if not
+ */
+ZIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event)
+{
+ struct pollfd pfds[ZAP_MAX_CHANNELS_SPAN];
+ uint32_t i, j = 0, k = 0;
+ int r;
+
+ for(i = 1; i <= span->chan_count; i++) {
+ memset(&pfds[j], 0, sizeof(pfds[j]));
+ pfds[j].fd = span->channels[i]->sockfd;
+ pfds[j].events = POLLPRI;
+ j++;
+ }
+
+ r = poll(pfds, j, ms);
+
+ if (r == 0) {
+ return ZAP_TIMEOUT;
+ } else if (r < 0 || (pfds[i-1].revents & POLLERR)) {
+ snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+ return ZAP_FAIL;
+ }
+
+ for(i = 1; i <= span->chan_count; i++) {
+ if (pfds[i-1].revents & POLLPRI) {
+ zap_set_flag(span->channels[i], ZAP_CHANNEL_EVENT);
+ span->channels[i]->last_event_time = zap_current_time_in_ms();
+ k++;
+ }
+ }
+
+ if (!k) {
+ snprintf(span->last_error, sizeof(span->last_error), "no matching descriptor");
+ }
+
+ return k ? ZAP_SUCCESS : ZAP_FAIL;
+}
+
+/**
+ * \brief Retrieves an event from a zaptel span
+ * \param span Span to retrieve event from
+ * \param event Openzap event to return
+ * \return Success or failure
+ */
+ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
+{
+ uint32_t i, event_id = 0;
+ zap_oob_event_t zt_event_id = 0;
+
+ for(i = 1; i <= span->chan_count; i++) {
+ if (zap_test_flag(span->channels[i], ZAP_CHANNEL_EVENT)) {
+ zap_clear_flag(span->channels[i], ZAP_CHANNEL_EVENT);
+ if (ioctl(span->channels[i]->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
+ snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+ return ZAP_FAIL;
+ }
+
+ switch(zt_event_id) {
+ case ZT_EVENT_RINGEROFF:
+ {
+ return ZAP_FAIL;
+ }
+ break;
+ case ZT_EVENT_RINGERON:
+ {
+ return ZAP_FAIL;
+ }
+ break;
+ case ZT_EVENT_RINGBEGIN:
+ {
+ event_id = ZAP_OOB_RING_START;
+ }
+ break;
+ case ZT_EVENT_ONHOOK:
+ {
+ event_id = ZAP_OOB_ONHOOK;
+ }
+ break;
+ case ZT_EVENT_WINKFLASH:
+ {
+ if (span->channels[i]->state == ZAP_CHANNEL_STATE_DOWN || span->channels[i]->state == ZAP_CHANNEL_STATE_DIALING) {
+ event_id = ZAP_OOB_WINK;
+ } else {
+ event_id = ZAP_OOB_FLASH;
+ }
+ }
+ break;
+ case ZT_EVENT_RINGOFFHOOK:
+ {
+ if (span->channels[i]->type == ZAP_CHAN_TYPE_FXS || (span->channels[i]->type == ZAP_CHAN_TYPE_EM && span->channels[i]->state != ZAP_CHANNEL_STATE_UP)) {
+ zap_set_flag_locked(span->channels[i], ZAP_CHANNEL_OFFHOOK);
+ event_id = ZAP_OOB_OFFHOOK;
+ } else if (span->channels[i]->type == ZAP_CHAN_TYPE_FXO) {
+ event_id = ZAP_OOB_RING_START;
+ }
+ }
+ break;
+ case ZT_EVENT_ALARM:
+ {
+ zap_sigmsg_t sigmsg;
+ zap_channel_t *zchan = span->channels[i];
+ event_id = ZAP_OOB_ALARM_TRAP;
+ memset(&sigmsg, 0, sizeof(sigmsg));
+ sigmsg.chan_id = zchan->chan_id;
+ sigmsg.span_id = zchan->span_id;
+ sigmsg.channel = zchan;
+ sigmsg.event_id = ZAP_SIGEVENT_ALARM_TRAP;
+ zap_span_send_signal(zchan->span, &sigmsg);
+ }
+ break;
+ case ZT_EVENT_NOALARM:
+ {
+ zap_sigmsg_t sigmsg;
+ zap_channel_t *zchan = span->channels[i];
+ event_id = ZAP_OOB_ALARM_CLEAR;
+ memset(&sigmsg, 0, sizeof(sigmsg));
+ sigmsg.chan_id = zchan->chan_id;
+ sigmsg.span_id = zchan->span_id;
+ sigmsg.channel = zchan;
+ sigmsg.event_id = ZAP_SIGEVENT_ALARM_CLEAR;
+ zap_span_send_signal(zchan->span, &sigmsg);
+ }
+ break;
+ case ZT_EVENT_BITSCHANGED:
+ {
+ event_id = ZAP_OOB_CAS_BITS_CHANGE;
+ int bits = 0;
+ int err = ioctl(span->channels[i]->sockfd, codes.GETRXBITS, &bits);
+ if (err) {
+ return ZAP_FAIL;
+ }
+ span->channels[i]->rx_cas_bits = bits;
+ }
+ break;
+ default:
+ {
+ zap_log(ZAP_LOG_WARNING, "Unhandled event %d for %d:%d\n", zt_event_id, span->span_id, i);
+ event_id = ZAP_OOB_INVALID;
+ }
+ break;
+ }
+
+ span->channels[i]->last_event_time = 0;
+ span->event_header.e_type = ZAP_EVENT_OOB;
+ span->event_header.enum_id = event_id;
+ span->event_header.channel = span->channels[i];
+ *event = &span->event_header;
+ return ZAP_SUCCESS;
+ }
+ }
+
+ return ZAP_FAIL;
+
+}
+
+/**
+ * \brief Reads data from a zaptel channel
+ * \param zchan Channel to read from
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success, failure or timeout
+ */
+static ZIO_READ_FUNCTION(zt_read)
+{
+ zap_ssize_t r = 0;
+ int errs = 0;
+
+ while (errs++ < 30) {
+ if ((r = read(zchan->sockfd, data, *datalen)) > 0) {
+ break;
+ }
+ zap_sleep(10);
+ if (r == 0) {
+ errs--;
+ }
+ }
+
+ if (r > 0) {
+ *datalen = r;
+ if (zchan->type == ZAP_CHAN_TYPE_DQ921) {
+ *datalen -= 2;
+ }
+ return ZAP_SUCCESS;
+ }
+
+ return r == 0 ? ZAP_TIMEOUT : ZAP_FAIL;
+}
+
+/**
+ * \brief Writes data to a zaptel channel
+ * \param zchan Channel to write to
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success or failure
+ */
+static ZIO_WRITE_FUNCTION(zt_write)
+{
+ zap_ssize_t w = 0;
+ zap_size_t bytes = *datalen;
+
+ if (zchan->type == ZAP_CHAN_TYPE_DQ921) {
+ memset(data+bytes, 0, 2);
+ bytes += 2;
+ }
+
+ w = write(zchan->sockfd, data, bytes);
+
+ if (w >= 0) {
+ *datalen = w;
+ return ZAP_SUCCESS;
+ }
+
+ return ZAP_FAIL;
+}
+
+/**
+ * \brief Destroys a zaptel Channel
+ * \param zchan Channel to destroy
+ * \return Success
+ */
+static ZIO_CHANNEL_DESTROY_FUNCTION(zt_channel_destroy)
+{
+ close(zchan->sockfd);
+ zchan->sockfd = ZT_INVALID_SOCKET;
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Global Openzap IO interface for zaptel
+ */
+static zap_io_interface_t zt_interface;
+
+/**
+ * \brief Loads zaptel IO module
+ * \param zio Openzap IO interface
+ * \return Success or failure
+ */
+static ZIO_IO_LOAD_FUNCTION(zt_init)
+{
+ assert(zio != NULL);
+ struct stat statbuf;
+ memset(&zt_interface, 0, sizeof(zt_interface));
+ memset(&zt_globals, 0, sizeof(zt_globals));
+
+ if (!stat(zt_ctlpath, &statbuf)) {
+ zap_log(ZAP_LOG_NOTICE, "Using Zaptel control device\n");
+ ctlpath = zt_ctlpath;
+ chanpath = zt_chanpath;
+ memcpy(&codes, &zt_ioctl_codes, sizeof(codes));
+ } else if (!stat(dahdi_ctlpath, &statbuf)) {
+ zap_log(ZAP_LOG_NOTICE, "Using DAHDI control device\n");
+ ctlpath = dahdi_ctlpath;
+ chanpath = dahdi_chanpath;
+ memcpy(&codes, &dahdi_ioctl_codes, sizeof(codes));
+ } else {
+ zap_log(ZAP_LOG_ERROR, "No DAHDI or Zap control device found in /dev/\n");
+ return ZAP_FAIL;
+ }
+ if ((CONTROL_FD = open(ctlpath, O_RDWR)) < 0) {
+ zap_log(ZAP_LOG_ERROR, "Cannot open control device %s: %s\n", ctlpath, strerror(errno));
+ return ZAP_FAIL;
+ }
+
+ zt_globals.codec_ms = 20;
+ zt_globals.wink_ms = 150;
+ zt_globals.flash_ms = 750;
+ zt_globals.eclevel = 0;
+ zt_globals.etlevel = 0;
+
+ zt_interface.name = "zt";
+ zt_interface.configure = zt_configure;
+ zt_interface.configure_span = zt_configure_span;
+ zt_interface.open = zt_open;
+ zt_interface.close = zt_close;
+ zt_interface.command = zt_command;
+ zt_interface.wait = zt_wait;
+ zt_interface.read = zt_read;
+ zt_interface.write = zt_write;
+ zt_interface.poll_event = zt_poll_event;
+ zt_interface.next_event = zt_next_event;
+ zt_interface.channel_destroy = zt_channel_destroy;
+ zt_interface.get_alarms = zt_get_alarms;
+ *zio = &zt_interface;
+
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Unloads zaptel IO module
+ * \return Success
+ */
+static ZIO_IO_UNLOAD_FUNCTION(zt_destroy)
+{
+ close(CONTROL_FD);
+ memset(&zt_interface, 0, sizeof(zt_interface));
+ return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Openzap zaptel IO module definition
+ */
+zap_module_t zap_module = {
+ "zt",
+ zt_init,
+ zt_destroy,
+};
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#ifndef ZAP_ZT_H
+#define ZAP_ZT_H
+#include "openzap.h"
+#include <sys/ioctl.h>
+#include <poll.h>
+
+#ifdef __sun
+#include <unistd.h>
+#include <sys/ioccom.h>
+#include <stropts.h>
+#endif
+
+/* Hardware interface structures and defines */
+/* Based on documentation of the structures required for the hardware interface */
+/* from http://wiki.freeswitch.org/wiki/Zapata_zaptel_interface */
+
+/* Structures */
+
+/* Used with ioctl: ZT_GET_PARAMS and ZT_SET_PARAMS */
+struct zt_params {
+ int chan_no; /* Channel Number */
+ int span_no; /* Span Number */
+ int chan_position; /* Channel Position */
+ int sig_type; /* Signal Type (read-only) */
+ int sig_cap; /* Signal Cap (read-only) */
+ int receive_offhook; /* Receive is offhook (read-only) */
+ int receive_bits; /* Number of bits in receive (read-only) */
+ int transmit_bits; /* Number of bits in transmit (read-only) */
+ int transmit_hook_sig; /* Transmit Hook Signal (read-only) */
+ int receive_hook_sig; /* Receive Hook Signal (read-only) */
+ int g711_type; /* Member of zt_g711_t (read-only) */
+ int idlebits; /* bits for the idle state (read-only) */
+ char chan_name[40]; /* Channel Name */
+ int prewink_time;
+ int preflash_time;
+ int wink_time;
+ int flash_time;
+ int start_time;
+ int receive_wink_time;
+ int receive_flash_time;
+ int debounce_time;
+ int pulse_break_time;
+ int pulse_make_time;
+ int pulse_after_time;
+ /* latest version of this struct include chan_alarms field */
+ uint32_t chan_alarms;
+};
+
+typedef struct zt_params zt_params_t;
+
+/* Used with ioctl: ZT_CONFLINK, ZT_GETCONF and ZT_SETCONF */
+struct zt_confinfo {
+ int chan_no; /* Channel Number, 0 for current */
+ int conference_number;
+ int conference_mode;
+};
+
+/* Used with ioctl: ZT_GETGAINS and ZT_SETGAINS */
+struct zt_gains {
+ int chan_no; /* Channel Number, 0 for current */
+ unsigned char receive_gain[256]; /* Receive gain table */
+ unsigned char transmit_gain[256]; /* Transmit gain table */
+};
+
+/* Used with ioctl: ZT_SPANSTAT */
+struct zt_spaninfo {
+ int span_no; /* span number (-1 to use name) */
+ char name[20]; /* Name of span */
+ char description[40]; /* Description of span */
+ int alarms; /* alarms status */
+ int transmit_level; /* Transmit level */
+ int receive_level; /* Receive level */
+ int bpv_count; /* Current BPV count */
+ int crc4_count; /* Current CRC4 error count */
+ int ebit_count; /* Current E-bit error count */
+ int fas_count; /* Current FAS error count */
+ int irq_misses; /* Current IRQ misses */
+ int sync_src; /* Span # of sync source (0 = free run) */
+ int configured_chan_count; /* Count of channels configured on the span */
+ int channel_count; /* Total count of channels on the span */
+ int span_count; /* Total count of zaptel spans on the system*/
+ /* end v1 of the struct */
+ /* as long as we don't use the fields below we should be ok regardless of the zaptel/dahdi version */
+ int lbo; /* Line Build Out */
+ int lineconfig; /* framing/coding */
+ /* end of v2 of the struct */
+ char lboname[40]; /* Line Build Out in text form */
+ char location[40]; /* span's device location in system */
+ char manufacturer[40]; /* manufacturer of span's device */
+ char devicetype[40]; /* span's device type */
+ int irq; /* span's device IRQ */
+ int linecompat; /* signaling modes possible on this span */
+ char spantype[6]; /* type of span in text form */
+};
+
+struct zt_maintinfo {
+ int span_no; /* span number */
+ int command; /* Maintenance mode to set (from zt_maintenance_mode_t) */
+};
+
+struct zt_lineconfig {
+/* Used in ZT_SPANCONFIG */
+ int span; /* Which span number (0 to use name) */
+ char name[20]; /* Name of span to use */
+ int lbo; /* line build-outs */
+ int lineconfig; /* line config parameters (framing, coding) */
+ int sync; /* what level of sync source we are */
+};
+
+struct zt_chanconfig {
+/* Used in ZT_CHANCONFIG */
+ int chan; /* Channel we're applying this to (0 to use name) */
+ char name[40]; /* Name of channel to use */
+ int sigtype; /* Signal type */
+ int deflaw; /* Default law (ZT_LAW_DEFAULT, ZT_LAW_MULAW, or ZT_LAW_ALAW */
+ int master; /* Master channel if sigtype is ZT_SLAVE */
+ int idlebits; /* Idle bits (if this is a CAS channel) or channel to monitor (if this is DACS channel) */
+ char netdev_name[16]; /* name for the hdlc network device */
+};
+
+struct zt_bufferinfo {
+/* used in ZT_SET_BUFINFO and ZT_GET_BUFINFO */
+ int txbufpolicy; /* Policy for handling receive buffers */
+ int rxbufpolicy; /* Policy for handling receive buffers */
+ int numbufs; /* How many buffers to use */
+ int bufsize; /* How big each buffer is */
+ int readbufs; /* How many read buffers are full (read-only) */
+ int writebufs; /* How many write buffers are full (read-only) */
+};
+
+/* Enumerations */
+
+/* Values in zt_params structure for member g711_type */
+typedef enum {
+ ZT_G711_DEFAULT = 0, /* Default mulaw/alaw from the span */
+ ZT_G711_MULAW = 1,
+ ZT_G711_ALAW = 2
+} zt_g711_t;
+
+typedef enum {
+ ZT_EVENT_NONE = 0,
+ ZT_EVENT_ONHOOK = 1,
+ ZT_EVENT_RINGOFFHOOK = 2,
+ ZT_EVENT_WINKFLASH = 3,
+ ZT_EVENT_ALARM = 4,
+ ZT_EVENT_NOALARM = 5,
+ ZT_EVENT_ABORT = 6,
+ ZT_EVENT_OVERRUN = 7,
+ ZT_EVENT_BADFCS = 8,
+ ZT_EVENT_DIALCOMPLETE = 9,
+ ZT_EVENT_RINGERON = 10,
+ ZT_EVENT_RINGEROFF = 11,
+ ZT_EVENT_HOOKCOMPLETE = 12,
+ ZT_EVENT_BITSCHANGED = 13,
+ ZT_EVENT_PULSE_START = 14,
+ ZT_EVENT_TIMER_EXPIRED = 15,
+ ZT_EVENT_TIMER_PING = 16,
+ ZT_EVENT_POLARITY = 17,
+ ZT_EVENT_RINGBEGIN = 18
+} zt_event_t;
+
+typedef enum {
+ ZT_FLUSH_READ = 1,
+ ZT_FLUSH_WRITE = 2,
+ ZT_FLUSH_BOTH = (ZT_FLUSH_READ | ZT_FLUSH_WRITE),
+ ZT_FLUSH_EVENT = 4,
+ ZT_FLUSH_ALL = (ZT_FLUSH_READ | ZT_FLUSH_WRITE | ZT_FLUSH_EVENT)
+} zt_flush_t;
+
+typedef enum {
+ ZT_IOMUX_READ = 1,
+ ZT_IOMUX_WRITE = 2,
+ ZT_IOMUX_WRITEEMPTY = 4,
+ ZT_IOMUX_SIGEVENT = 8,
+ ZT_IOMUX_NOWAIT = 256
+} zt_iomux_t;
+
+typedef enum {
+ ZT_ONHOOK = 0,
+ ZT_OFFHOOK = 1,
+ ZT_WINK = 2,
+ ZT_FLASH = 3,
+ ZT_START = 4,
+ ZT_RING = 5,
+ ZT_RINGOFF = 6
+} zt_hookstate_t;
+
+typedef enum {
+ ZT_MAINT_NONE = 0, /* Normal Mode */
+ ZT_MAINT_LOCALLOOP = 1, /* Local Loopback */
+ ZT_MAINT_REMOTELOOP = 2, /* Remote Loopback */
+ ZT_MAINT_LOOPUP = 3, /* Send Loopup Code */
+ ZT_MAINT_LOOPDOWN = 4, /* Send Loopdown Code */
+ ZT_MAINT_LOOPSTOP = 5 /* Stop Sending Loop Codes */
+} zt_maintenance_mode_t;
+
+typedef enum {
+/* Signalling type */
+ZT_SIG_NONE = 0, /* chan not configured. */
+
+ZT_SIG_FXSLS = ((1 << 0) | (1 << 13)), /* FXS, Loopstart */
+ZT_SIG_FXSGS = ((1 << 1) | (1 << 13)), /* FXS, Groundstart */
+ZT_SIG_FXSKS = ((1 << 2) | (1 << 13)), /* FXS, Kewlstart */
+ZT_SIG_FXOLS = ((1 << 3) | (1 << 12)), /* FXO, Loopstart */
+ZT_SIG_FXOGS = ((1 << 4) | (1 << 12)), /* FXO, Groupstart */
+ZT_SIG_FXOKS = ((1 << 5) | (1 << 12)), /* FXO, Kewlstart */
+ZT_SIG_EM = (1 << 6), /* E&M */
+ZT_SIG_CLEAR = (1 << 7),
+ZT_SIG_HDLCRAW = ((1 << 8) | ZT_SIG_CLEAR),
+ZT_SIG_HDLCFCS = ((1 << 9) | ZT_SIG_HDLCRAW),
+ZT_SIG_CAS = (1 << 15),
+ZT_SIG_HARDHDLC = ((1 << 19) | ZT_SIG_CLEAR),
+} zt_sigtype_t;
+
+typedef enum {
+ZT_DBIT = 1,
+ZT_CBIT = 2,
+ZT_BBIT = 4,
+ZT_ABIT = 8
+} zt_cas_bit_t;
+
+/* Defines */
+
+#define ZT_MAX_BLOCKSIZE 8192
+#define ZT_DEFAULT_MTU_MRU 2048
+
+/* ioctl defines */
+
+#define ZT_CODE 'J'
+#define DAHDI_CODE 0xDA
+
+
+#define ZT_GET_BLOCKSIZE _IOR (ZT_CODE, 1, int) /* Get Transfer Block Size. */
+#define ZT_SET_BLOCKSIZE _IOW (ZT_CODE, 2, int) /* Set Transfer Block Size. */
+#define ZT_FLUSH _IOW (ZT_CODE, 3, int) /* Flush Buffer(s) and stop I/O */
+#define ZT_SYNC _IOW (ZT_CODE, 4, int) /* Wait for Write to Finish */
+#define ZT_GET_PARAMS _IOR (ZT_CODE, 5, struct zt_params) /* Get channel parameters */
+#define ZT_SET_PARAMS _IOW (ZT_CODE, 6, struct zt_params) /* Set channel parameters */
+#define ZT_HOOK _IOW (ZT_CODE, 7, int) /* Set Hookswitch Status */
+#define ZT_GETEVENT _IOR (ZT_CODE, 8, int) /* Get Signalling Event */
+#define ZT_IOMUX _IOWR (ZT_CODE, 9, int) /* Wait for something to happen (IO Mux) */
+#define ZT_SPANSTAT _IOWR (ZT_CODE, 10, struct zt_spaninfo) /* Get Span Status */
+#define ZT_MAINT _IOW (ZT_CODE, 11, struct zt_maintinfo)/* Set Maintenance Mode for a span */
+#define ZT_GETCONF _IOWR (ZT_CODE, 12, struct zt_confinfo) /* Get Conference Mode */
+#define ZT_SETCONF _IOWR (ZT_CODE, 13, struct zt_confinfo) /* Set Conference Mode */
+#define ZT_CONFLINK _IOW (ZT_CODE, 14, struct zt_confinfo) /* Setup or Remove Conference Link */
+#define ZT_CONFDIAG _IOR (ZT_CODE, 15, int) /* Display Conference Diagnostic Information on Console */
+
+#define ZT_GETGAINS _IOWR (ZT_CODE, 16, struct zt_gains) /* Get Channel audio gains */
+#define ZT_SETGAINS _IOWR (ZT_CODE, 17, struct zt_gains) /* Set Channel audio gains */
+#define ZT_SPANCONFIG _IOW (ZT_CODE, 18, struct zt_lineconfig)/* Set Line (T1) Configurations and start system */
+#define ZT_CHANCONFIG _IOW (ZT_CODE, 19, struct zt_chanconfig)/* Set Channel Configuration */
+#define ZT_SET_BUFINFO _IOW (ZT_CODE, 27, struct zt_bufferinfo)/* Set buffer policy */
+#define ZT_GET_BUFINFO _IOR (ZT_CODE, 28, struct zt_bufferinfo)/* Get current buffer info */
+#define ZT_AUDIOMODE _IOW (ZT_CODE, 32, int) /* Set a clear channel into audio mode */
+#define ZT_ECHOCANCEL _IOW (ZT_CODE, 33, int) /* Control Echo Canceller */
+#define ZT_HDLCRAWMODE _IOW (ZT_CODE, 36, int) /* Set a clear channel into HDLC w/out FCS checking/calculation mode */
+#define ZT_HDLCFCSMODE _IOW (ZT_CODE, 37, int) /* Set a clear channel into HDLC w/ FCS mode */
+
+/* Specify a channel on /dev/zap/chan -- must be done before any other ioctl's and is only valid on /dev/zap/chan */
+#define ZT_SPECIFY _IOW (ZT_CODE, 38, int)
+
+/* Temporarily set the law on a channel to ZT_LAW_DEFAULT, ZT_LAW_ALAW, or ZT_LAW_MULAW. Is reset on close. */
+#define ZT_SETLAW _IOW (ZT_CODE, 39, int)
+
+/* Temporarily set the channel to operate in linear mode when non-zero or default law if 0 */
+#define ZT_SETLINEAR _IOW (ZT_CODE, 40, int)
+
+#define ZT_GETCONFMUTE _IOR (ZT_CODE, 49, int) /* Get Conference to mute mode */
+#define ZT_ECHOTRAIN _IOW (ZT_CODE, 50, int) /* Control Echo Trainer */
+
+/* Set/Get CAS bits */
+#define ZT_SETTXBITS _IOW (ZT_CODE, 43, int)
+#define ZT_GETRXBITS _IOR (ZT_CODE, 45, int)
+
+#define DAHDI_GET_BLOCKSIZE _IOR (DAHDI_CODE, 1, int) /* Get Transfer Block Size. */
+#define DAHDI_SET_BLOCKSIZE _IOW (DAHDI_CODE, 1, int) /* Set Transfer Block Size. */
+#define DAHDI_FLUSH _IOW (DAHDI_CODE, 3, int) /* Flush Buffer(s) and stop I/O */
+#define DAHDI_SYNC _IO (DAHDI_CODE, 4) /* Wait for Write to Finish */
+#define DAHDI_GET_PARAMS _IOR (DAHDI_CODE, 5, struct zt_params) /* Get channel parameters */
+#define DAHDI_SET_PARAMS _IOW (DAHDI_CODE, 5, struct zt_params) /* Set channel parameters */
+#define DAHDI_HOOK _IOW (DAHDI_CODE, 7, int) /* Set Hookswitch Status */
+#define DAHDI_GETEVENT _IOR (DAHDI_CODE, 8, int) /* Get Signalling Event */
+#define DAHDI_IOMUX _IOWR (DAHDI_CODE, 9, int) /* Wait for something to happen (IO Mux) */
+#define DAHDI_SPANSTAT _IOWR (DAHDI_CODE, 10, struct zt_spaninfo) /* Get Span Status */
+#define DAHDI_MAINT _IOW (DAHDI_CODE, 11, struct zt_maintinfo) /* Set Maintenance Mode for a span */
+#define DAHDI_GETCONF _IOR (DAHDI_CODE, 12, struct zt_confinfo) /* Get Conference Mode */
+#define DAHDI_SETCONF _IOW (DAHDI_CODE, 12, struct zt_confinfo) /* Set Conference Mode */
+#define DAHDI_CONFLINK _IOW (DAHDI_CODE, 14, struct zt_confinfo) /* Setup or Remove Conference Link */
+#define DAHDI_CONFDIAG _IOR (DAHDI_CODE, 15, int) /* Display Conference Diagnostic Information on Console */
+
+#define DAHDI_GETGAINS _IOR (DAHDI_CODE, 16, struct zt_gains) /* Get Channel audio gains */
+#define DAHDI_SETGAINS _IOW (DAHDI_CODE, 16, struct zt_gains) /* Set Channel audio gains */
+#define DAHDI_SPANCONFIG _IOW (DAHDI_CODE, 18, struct zt_lineconfig)/* Set Line (T1) Configurations and start system */
+#define DAHDI_CHANCONFIG _IOW (DAHDI_CODE, 19, struct zt_chanconfig)/* Set Channel Configuration */
+#define DAHDI_SET_BUFINFO _IOW (DAHDI_CODE, 27, struct zt_bufferinfo)/* Set buffer policy */
+#define DAHDI_GET_BUFINFO _IOR (DAHDI_CODE, 27, struct zt_bufferinfo)/* Get current buffer info */
+#define DAHDI_AUDIOMODE _IOW (DAHDI_CODE, 32, int) /* Set a clear channel into audio mode */
+#define DAHDI_ECHOCANCEL _IOW (DAHDI_CODE, 33, int) /* Control Echo Canceller */
+#define DAHDI_HDLCRAWMODE _IOW (DAHDI_CODE, 36, int) /* Set a clear channel into HDLC w/out FCS checking/calculation mode */
+#define DAHDI_HDLCFCSMODE _IOW (DAHDI_CODE, 37, int) /* Set a clear channel into HDLC w/ FCS mode */
+
+/* Specify a channel on /dev/dahdi/chan -- must be done before any other ioctl's and is only valid on /dev/dahdi/chan */
+#define DAHDI_SPECIFY _IOW (DAHDI_CODE, 38, int)
+
+/* Temporarily set the law on a channel to DAHDI_LAW_DEFAULT, DAHDI_LAW_ALAW, or DAHDI_LAW_MULAW. Is reset on close. */
+#define DAHDI_SETLAW _IOW (DAHDI_CODE, 39, int)
+
+/* Temporarily set the channel to operate in linear mode when non-zero or default law if 0 */
+#define DAHDI_SETLINEAR _IOW (DAHDI_CODE, 40, int)
+
+#define DAHDI_GETCONFMUTE _IOR (DAHDI_CODE, 49, int) /* Get Conference to mute mode */
+#define DAHDI_ECHOTRAIN _IOW (DAHDI_CODE, 50, int) /* Control Echo Trainer */
+
+/* Set/Get CAS bits */
+#define DAHDI_SETTXBITS _IOW (DAHDI_CODE, 43, int)
+#define DAHDI_GETRXBITS _IOR (DAHDI_CODE, 43, int)
+
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/priserver.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/priserver.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/priserver.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,328 @@
+/*****************************************************************************
+ * priserver.c Refactoring of pritest.c
+ *
+ * Author(s): Anthony Minessale II <anthmct@yahoo.com>
+ * Nenad Corbic <ncorbic@sangoma.com>
+ *
+ * Copyright: (c) 2005 Anthony Minessale II
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ * ============================================================================
+ */
+
+#include "openzap.h"
+#include <sangoma_pri.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+typedef struct {
+ int pid;
+ q931_call call;
+ void *pri;
+ int ready;
+}call_info_t;
+
+
+#define SANGOMA_MAX_CHAN_PER_SPAN 32
+
+static call_info_t pidmap[SANGOMA_MAX_CHAN_PER_SPAN];
+
+ZIO_EVENT_CB_FUNCTION(my_zap_event_handler)
+{
+ if (event->e_type = ZAP_EVENT_DTMF) {
+ char *dtmf = event->data;
+ printf("DTMF %s\n", dtmf);
+ }
+}
+
+/* Stupid runtime process to play a file to a b channel*/
+#define BYTES 320
+#define MAX_BYTES 1000
+
+static int ready = 1;
+
+static void handle_SIGINT(int sig)
+{
+ if (sig) {
+ ready = 0;
+ }
+
+ return;
+}
+
+static void launch_channel(struct sangoma_pri *spri, int channo)
+{
+ pid_t pid;
+ int fd = 0, file = 0, inlen = 0, outlen = 0;
+ unsigned char inframe[MAX_BYTES], outframe[MAX_BYTES];
+ fd_set readfds;
+ int mtu_mru=BYTES / 2;
+ int err;
+ zap_channel_t *chan;
+ zap_codec_t codec = ZAP_CODEC_SLIN;
+ unsigned ms = 20;
+ unsigned int lead = 50;
+ int ifd = -1;
+ zap_tone_type_t tt = ZAP_TONE_DTMF;
+ char dtmf[] = "1234567890";
+ int loops = 0;
+
+ pid = fork();
+
+ if (pid) {
+ pidmap[channo-1].pid = pid;
+ printf("-- Launching process %d to handle channel %d\n", pid, channo);
+ return;
+ }
+
+ signal(SIGINT, handle_SIGINT);
+
+ //ifd = open("/nfs/sounds/ptest.raw", O_WRONLY|O_CREAT|O_TRUNC, 777);
+
+ memset(inframe, 0, MAX_BYTES);
+ memset(outframe, 0, MAX_BYTES);
+
+ if (zap_channel_open(spri->span, channo, &chan) != ZAP_SUCCESS) {
+ printf("DEBUG cant open fd!\n");
+ }
+
+
+
+#if 1
+ if (zap_channel_command(chan, ZAP_COMMAND_SET_CODEC, &codec) != ZAP_SUCCESS) {
+ printf("Critical Error: Failed to set driver codec!\n");
+ zap_channel_close(&chan);
+ exit(-1);
+ }
+#endif
+
+#if 1
+ if (zap_channel_command(chan, ZAP_COMMAND_ENABLE_DTMF_DETECT, &tt) != ZAP_SUCCESS) {
+ printf("Critical Error: Failed to set dtmf detect!\n");
+ zap_channel_close(&chan);
+ exit(-1);
+ }
+ zap_channel_set_event_callback(chan, my_zap_event_handler);
+#endif
+
+
+ if (zap_channel_command(chan, ZAP_COMMAND_SET_INTERVAL, &ms) != ZAP_SUCCESS) {
+ printf("Critical Error: Failed to set codec interval!\n");
+ zap_channel_close(&chan);
+ exit(-1);
+ }
+
+ file = open("sound.raw", O_RDONLY);
+ if (file < 0){
+ printf("Critical Error: Failed to open sound file!\n");
+ zap_channel_close(&chan);
+ exit(-1);
+ }
+
+
+ while(ready) {
+ zap_wait_flag_t flags = ZAP_READ;
+ zap_size_t len;
+ loops++;
+
+ if (lead) {
+ lead--;
+ }
+
+ if (!lead && loops == 300) {
+#if 1
+ if (zap_channel_command(chan, ZAP_COMMAND_SEND_DTMF, dtmf) != ZAP_SUCCESS) {
+ printf("Critical Error: Failed to send dtmf\n");
+ zap_channel_close(&chan);
+ exit(-1);
+ }
+#endif
+
+ }
+
+ if (zap_channel_wait(chan, &flags, 2000) != ZAP_SUCCESS) {
+ printf("wait FAIL! [%s]\n", chan->last_error);
+ break;
+ }
+
+ if (flags & ZAP_READ) {
+ len = MAX_BYTES;
+ if (zap_channel_read(chan, inframe, &len) == ZAP_SUCCESS) {
+ //printf("READ: %d\n", len);
+ //write(ifd, inframe, len);
+ if(!lead && (outlen = read(file, outframe, len)) <= 0) {
+ break;
+ }
+
+ } else {
+ printf("READ FAIL! %d [%s]\n", len, chan->last_error);
+ break;
+ }
+ if (lead) {
+ continue;
+ }
+ zap_channel_write(chan, outframe, sizeof(outframe), &len);
+ } else {
+ printf("BREAK");
+ break;
+ }
+ }
+
+ printf("loop done\n");
+
+ //sangoma_get_full_cfg(fd, &tdm_api);
+ close(file);
+ //close(ifd);
+
+ pri_hangup(spri->pri, channo, 16);
+ if (zap_channel_close(&chan) != ZAP_SUCCESS) {
+ printf("Critical Error: Failed to close channel [%s]\n", chan->last_error);
+ }
+
+ printf("Call Handler: Process Finished\n");
+ exit(0);
+}
+
+
+/* Event Handlers */
+
+static int on_info(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event)
+{
+ printf( "number is: %s\n", event->ring.callednum);
+ if(strlen(event->ring.callednum) > 3) {
+ printf( "final number is: %s\n", event->ring.callednum);
+ pri_answer(spri->pri, event->ring.call, 0, 1);
+ }
+ return 0;
+}
+
+static int on_hangup(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event)
+{
+ //pri_hangup(spri->pri, event->hangup.call, event->hangup.cause);
+ printf("-- Hanging up channel %d\n", event->hangup.channel);
+ if(pidmap[event->hangup.channel-1].pid) {
+ pri_hangup(spri->pri, event->hangup.call, 16);
+ pri_destroycall(spri->pri, event->hangup.call);
+ kill(pidmap[event->hangup.channel-1].pid, SIGINT);
+ pidmap[event->hangup.channel-1].pid = 0;
+ }
+ return 0;
+}
+
+static int on_ring(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event)
+{
+ printf("-- Ring on channel %d (from %s to %s), answering...\n", event->ring.channel, event->ring.callingnum, event->ring.callednum);
+ pri_answer(spri->pri, event->ring.call, event->ring.channel, 1);
+ memcpy(&pidmap[event->ring.channel-1].call, event->ring.call, sizeof(q931_call));
+ pidmap[event->ring.channel-1].pri=spri->pri;
+ pidmap[event->ring.channel-1].call = *event->ring.call;
+ launch_channel(spri, event->ring.channel);
+ return 0;
+}
+
+static int on_restart(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event)
+{
+ printf("-- Restarting channel %d\n", event->restart.channel);
+ return 0;
+}
+
+static int on_anything(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event)
+{
+ printf("%s: Caught Event %d (%s)\n", __FUNCTION__, event_type, sangoma_pri_event_str(event_type));
+ return 0;
+}
+
+/* Generic Reaper */
+static void chan_ended(int sig)
+{
+ int status;
+ int x;
+ struct rusage rusage;
+ pid_t pid;
+ pid = wait4(-1, &status, WNOHANG, &rusage);
+
+ printf("-- PID %d ended\n", pid);
+
+ for (x=0;x<SANGOMA_MAX_CHAN_PER_SPAN;x++) {
+ if (pid == pidmap[x].pid) {
+ pidmap[x].pid = 0;
+ if (pidmap[x].pri){
+ int err=pri_hangup(pidmap[x].pri, &pidmap[x].call, 16);
+ //pri_destroycall(pidmap[x].pri, &pidmap[x].call);
+ printf("Hanging up on PID %i Err=%i\n",pid,err);
+ }
+
+ pidmap[x].pri=NULL;
+ signal(SIGCHLD, chan_ended);
+ return;
+ }
+ }
+
+ if (pid > -1) {
+ fprintf(stderr, "--!! Unknown PID %d exited\n", pid);
+ signal(SIGCHLD, chan_ended);
+ return;
+ }
+}
+
+/* Our Program */
+int main(int argc, char *argv[])
+{
+ struct sangoma_pri spri;
+ int debug = 0;
+ if (argv[1]) {
+ debug = atoi(argv[1]);
+ }
+
+ zap_global_set_default_logger(ZAP_LOG_LEVEL_DEBUG);
+ if (zap_global_init() != ZAP_SUCCESS) {
+ fprintf(stderr, "Error loading OpenZAP\n");
+ exit(-1);
+ }
+
+ printf("OpenZAP loaded\n");
+
+
+ debug = PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE;
+ printf("WTF %d\n", debug);
+
+ if (sangoma_init_pri(&spri,
+ 1, // span
+ 24, // dchan
+ SANGOMA_PRI_SWITCH_DMS100,
+ SANGOMA_PRI_CPE,
+ debug) < 0) {
+ return -1;
+ }
+ //spri.pri->debug = (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE);
+
+ //pri_set_debug(&spri.pri, (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE));
+
+ SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_ANY, on_anything);
+ SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_RING, on_ring);
+ SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_HANGUP, on_hangup);
+ SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_HANGUP_REQ, on_hangup);
+ SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_INFO_RECEIVED, on_info);
+ SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_RESTART, on_restart);
+
+ signal(SIGCHLD, chan_ended);
+ sangoma_run_pri(&spri);
+ return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/sangoma_pri.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/sangoma_pri.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/sangoma_pri.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,251 @@
+/*****************************************************************************
+ * sangoma_pri.c libpri Sangoma integration
+ *
+ * Author(s): Anthony Minessale II <anthmct@yahoo.com>
+ * Nenad Corbic <ncorbic@sangoma.com>
+ *
+ * Copyright: (c) 2005 Anthony Minessale II
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ * ============================================================================
+ */
+
+#include "openzap.h"
+#include <sangoma_pri.h>
+#ifndef HAVE_GETTIMEOFDAY
+
+#ifdef WIN32
+#include <mmsystem.h>
+
+static __inline int gettimeofday(struct timeval *tp, void *nothing)
+{
+#ifdef WITHOUT_MM_LIB
+ SYSTEMTIME st;
+ time_t tt;
+ struct tm tmtm;
+ /* mktime converts local to UTC */
+ GetLocalTime (&st);
+ tmtm.tm_sec = st.wSecond;
+ tmtm.tm_min = st.wMinute;
+ tmtm.tm_hour = st.wHour;
+ tmtm.tm_mday = st.wDay;
+ tmtm.tm_mon = st.wMonth - 1;
+ tmtm.tm_year = st.wYear - 1900; tmtm.tm_isdst = -1;
+ tt = mktime (&tmtm);
+ tp->tv_sec = tt;
+ tp->tv_usec = st.wMilliseconds * 1000;
+#else
+ /**
+ ** The earlier time calculations using GetLocalTime
+ ** had a time resolution of 10ms.The timeGetTime, part
+ ** of multimedia apis offer a better time resolution
+ ** of 1ms.Need to link against winmm.lib for this
+ **/
+ unsigned long Ticks = 0;
+ unsigned long Sec =0;
+ unsigned long Usec = 0;
+ Ticks = timeGetTime();
+
+ Sec = Ticks/1000;
+ Usec = (Ticks - (Sec*1000))*1000;
+ tp->tv_sec = Sec;
+ tp->tv_usec = Usec;
+#endif /* WITHOUT_MM_LIB */
+ (void)nothing;
+ return 0;
+}
+#endif /* WIN32 */
+#endif /* HAVE_GETTIMEOFDAY */
+
+static struct sangoma_pri_event_list SANGOMA_PRI_EVENT_LIST[] = {
+ {0, SANGOMA_PRI_EVENT_ANY, "ANY"},
+ {1, SANGOMA_PRI_EVENT_DCHAN_UP, "DCHAN_UP"},
+ {2, SANGOMA_PRI_EVENT_DCHAN_DOWN, "DCHAN_DOWN"},
+ {3, SANGOMA_PRI_EVENT_RESTART, "RESTART"},
+ {4, SANGOMA_PRI_EVENT_CONFIG_ERR, "CONFIG_ERR"},
+ {5, SANGOMA_PRI_EVENT_RING, "RING"},
+ {6, SANGOMA_PRI_EVENT_HANGUP, "HANGUP"},
+ {7, SANGOMA_PRI_EVENT_RINGING, "RINGING"},
+ {8, SANGOMA_PRI_EVENT_ANSWER, "ANSWER"},
+ {9, SANGOMA_PRI_EVENT_HANGUP_ACK, "HANGUP_ACK"},
+ {10, SANGOMA_PRI_EVENT_RESTART_ACK, "RESTART_ACK"},
+ {11, SANGOMA_PRI_EVENT_FACNAME, "FACNAME"},
+ {12, SANGOMA_PRI_EVENT_INFO_RECEIVED, "INFO_RECEIVED"},
+ {13, SANGOMA_PRI_EVENT_PROCEEDING, "PROCEEDING"},
+ {14, SANGOMA_PRI_EVENT_SETUP_ACK, "SETUP_ACK"},
+ {15, SANGOMA_PRI_EVENT_HANGUP_REQ, "HANGUP_REQ"},
+ {16, SANGOMA_PRI_EVENT_NOTIFY, "NOTIFY"},
+ {17, SANGOMA_PRI_EVENT_PROGRESS, "PROGRESS"},
+ {18, SANGOMA_PRI_EVENT_KEYPAD_DIGIT, "KEYPAD_DIGIT"}
+};
+
+#define LINE "--------------------------------------------------------------------------------"
+
+char *sangoma_pri_event_str(sangoma_pri_event_t event_id)
+{
+ return SANGOMA_PRI_EVENT_LIST[event_id].name;
+}
+
+static int __pri_sangoma_read(struct pri *pri, void *buf, int buflen)
+{
+ struct sangoma_pri *spri = (struct sangoma_pri *) pri->userdata;
+ zap_size_t len = buflen;
+ int res;
+ char bb[4096] = "";
+
+
+ if (zap_channel_read(spri->zdchan, buf, &len) != ZAP_SUCCESS) {
+ printf("D-READ FAIL! [%s]\n", spri->zdchan->last_error);
+ return 0;
+ }
+ res = (int)len;
+ memset(&((unsigned char*)buf)[res],0,2);
+ res+=2;
+
+ //print_bits(buf, res-2, bb, sizeof(bb), 1, 0);
+ //zap_log(ZAP_LOG_DEBUG, "READ %d\n%s\n%s\n\n", res-2, LINE, bb);
+
+ return res;
+}
+
+static int __pri_sangoma_write(struct pri *pri, void *buf, int buflen)
+{
+ struct sangoma_pri *spri = (struct sangoma_pri *) pri->userdata;
+ int res;
+ zap_size_t len = buflen -2;
+ char bb[4096] = "";
+
+ if (zap_channel_write(spri->zdchan, buf, buflen, &len) != ZAP_SUCCESS) {
+ printf("D-WRITE FAIL! [%s]\n", spri->zdchan->last_error);
+ return 0;
+ }
+
+ //print_bits(buf, (int)buflen-2, bb, sizeof(bb), 1, 0);
+ //zap_log(ZAP_LOG_DEBUG, "WRITE %d\n%s\n%s\n\n", (int)buflen-2, LINE, bb);
+
+ return (int) buflen;
+}
+
+int sangoma_init_pri(struct sangoma_pri *spri, int span, int dchan, int swtype, int node, int debug)
+{
+ int ret = -1;
+ zap_socket_t dfd = 0;
+
+ memset(spri, 0, sizeof(struct sangoma_pri));
+
+ if (zap_channel_open(span, dchan, &spri->zdchan) != ZAP_SUCCESS) {
+ fprintf(stderr, "Unable to open DCHAN %d for span %d (%s)\n", dchan, span, strerror(errno));
+ } else {
+ if ((spri->pri = pri_new_cb(spri->zdchan->sockfd, node, swtype, __pri_sangoma_read, __pri_sangoma_write, spri))){
+ spri->span = span;
+ pri_set_debug(spri->pri, debug);
+ ret = 0;
+ } else {
+ fprintf(stderr, "Unable to create PRI\n");
+ }
+ }
+ return ret;
+}
+
+
+int sangoma_one_loop(struct sangoma_pri *spri)
+{
+ fd_set rfds, efds;
+ struct timeval now = {0,0}, *next;
+ pri_event *event;
+ int sel;
+
+ if (spri->on_loop) {
+ spri->on_loop(spri);
+ }
+
+ FD_ZERO(&rfds);
+ FD_ZERO(&efds);
+
+#ifdef _MSC_VER
+ //Windows macro for FD_SET includes a warning C4127: conditional expression is constant
+#pragma warning(push)
+#pragma warning(disable:4127)
+#endif
+
+ FD_SET(spri->pri->fd, &rfds);
+ FD_SET(spri->pri->fd, &efds);
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+ if ((next = pri_schedule_next(spri->pri))) {
+ gettimeofday(&now, NULL);
+ now.tv_sec = next->tv_sec - now.tv_sec;
+ now.tv_usec = next->tv_usec - now.tv_usec;
+ if (now.tv_usec < 0) {
+ now.tv_usec += 1000000;
+ now.tv_sec -= 1;
+ }
+ if (now.tv_sec < 0) {
+ now.tv_sec = 0;
+ now.tv_usec = 0;
+ }
+ }
+
+ sel = select(spri->pri->fd + 1, &rfds, NULL, &efds, next ? &now : NULL);
+ event = NULL;
+
+ if (!sel) {
+ event = pri_schedule_run(spri->pri);
+ } else if (sel > 0) {
+ event = pri_check_event(spri->pri);
+ }
+
+ if (event) {
+ event_handler handler;
+ /* 0 is catchall event handler */
+ if ((handler = spri->eventmap[event->e] ? spri->eventmap[event->e] : spri->eventmap[0] ? spri->eventmap[0] : NULL)) {
+ handler(spri, event->e, event);
+ } else {
+ fprintf(stderr,"No event handler found for event %d.\n", event->e);
+ }
+ }
+
+ return sel;
+}
+
+int sangoma_run_pri(struct sangoma_pri *spri)
+{
+ int ret = 0;
+
+ for (;;){
+ ret=sangoma_one_loop(spri);
+ if (ret < 0){
+
+#ifndef WIN32 //This needs to be adressed fror WIN32 still
+ if (errno == EINTR){
+ /* Igonore an interrupted system call */
+ continue;
+ }
+#endif
+ printf("Error = %i\n",ret);
+ perror("Sangoma Run Pri: ");
+ break;
+ }
+ }
+
+ return ret;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/openzap/src/sangoma_pri.h (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/sangoma_pri.h (rev 0)
+++ freeswitch/trunk/libs/openzap/src/sangoma_pri.h 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,100 @@
+/*****************************************************************************
+ * libsangoma.c AFT T1/E1: HDLC API Code Library
+ *
+ * Author(s): Anthony Minessale II <anthmct@yahoo.com>
+ * Nenad Corbic <ncorbic@sangoma.com>
+ *
+ * Copyright: (c) 2005 Anthony Minessale II
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ * ============================================================================
+ */
+
+#ifndef _SANGOMA_PRI_H
+#define _SANGOMA_PRI_H
+#include <libpri.h>
+#include <pri_internal.h>
+
+
+#define SANGOMA_MAX_CHAN_PER_SPAN 32
+
+typedef enum {
+ SANGOMA_PRI_EVENT_ANY = 0,
+ SANGOMA_PRI_EVENT_DCHAN_UP = PRI_EVENT_DCHAN_UP,
+ SANGOMA_PRI_EVENT_DCHAN_DOWN = PRI_EVENT_DCHAN_DOWN,
+ SANGOMA_PRI_EVENT_RESTART = PRI_EVENT_RESTART,
+ SANGOMA_PRI_EVENT_CONFIG_ERR = PRI_EVENT_CONFIG_ERR,
+ SANGOMA_PRI_EVENT_RING = PRI_EVENT_RING,
+ SANGOMA_PRI_EVENT_HANGUP = PRI_EVENT_HANGUP,
+ SANGOMA_PRI_EVENT_RINGING = PRI_EVENT_RINGING,
+ SANGOMA_PRI_EVENT_ANSWER = PRI_EVENT_ANSWER,
+ SANGOMA_PRI_EVENT_HANGUP_ACK = PRI_EVENT_HANGUP_ACK,
+ SANGOMA_PRI_EVENT_RESTART_ACK = PRI_EVENT_RESTART_ACK,
+ SANGOMA_PRI_EVENT_FACNAME = PRI_EVENT_FACNAME,
+ SANGOMA_PRI_EVENT_INFO_RECEIVED = PRI_EVENT_INFO_RECEIVED,
+ SANGOMA_PRI_EVENT_PROCEEDING = PRI_EVENT_PROCEEDING,
+ SANGOMA_PRI_EVENT_SETUP_ACK = PRI_EVENT_SETUP_ACK,
+ SANGOMA_PRI_EVENT_HANGUP_REQ = PRI_EVENT_HANGUP_REQ,
+ SANGOMA_PRI_EVENT_NOTIFY = PRI_EVENT_NOTIFY,
+ SANGOMA_PRI_EVENT_PROGRESS = PRI_EVENT_PROGRESS,
+ SANGOMA_PRI_EVENT_KEYPAD_DIGIT = PRI_EVENT_KEYPAD_DIGIT
+} sangoma_pri_event_t;
+
+typedef enum {
+ SANGOMA_PRI_NETWORK = PRI_NETWORK,
+ SANGOMA_PRI_CPE = PRI_CPE
+} sangoma_pri_node_t;
+
+typedef enum {
+ SANGOMA_PRI_SWITCH_UNKNOWN = PRI_SWITCH_UNKNOWN,
+ SANGOMA_PRI_SWITCH_NI2 = PRI_SWITCH_NI2,
+ SANGOMA_PRI_SWITCH_DMS100 = PRI_SWITCH_DMS100,
+ SANGOMA_PRI_SWITCH_LUCENT5E = PRI_SWITCH_LUCENT5E,
+ SANGOMA_PRI_SWITCH_ATT4ESS = PRI_SWITCH_ATT4ESS,
+ SANGOMA_PRI_SWITCH_EUROISDN_E1 = PRI_SWITCH_EUROISDN_E1,
+ SANGOMA_PRI_SWITCH_EUROISDN_T1 = PRI_SWITCH_EUROISDN_T1,
+ SANGOMA_PRI_SWITCH_NI1 = PRI_SWITCH_NI1,
+ SANGOMA_PRI_SWITCH_GR303_EOC = PRI_SWITCH_GR303_EOC,
+ SANGOMA_PRI_SWITCH_GR303_TMC = PRI_SWITCH_GR303_TMC,
+ SANGOMA_PRI_SWITCH_QSIG = PRI_SWITCH_QSIG
+} sangoma_pri_switch_t;
+
+typedef enum {
+ SANGOMA_PRI_READY = (1 << 0)
+} sangoma_pri_flag_t;
+
+struct sangoma_pri;
+typedef int (*event_handler)(struct sangoma_pri *, sangoma_pri_event_t, pri_event *);
+typedef int (*loop_handler)(struct sangoma_pri *);
+#define MAX_EVENT 18
+
+struct sangoma_pri {
+ struct pri *pri;
+ int span;
+ int dchan;
+ unsigned int flags;
+ void *private_info;
+ event_handler eventmap[MAX_EVENT+1];
+ loop_handler on_loop;
+ zap_channel_t *zdchan;
+};
+
+struct sangoma_pri_event_list {
+ int event_id;
+ int pri_event;
+ char *name;
+};
+
+
+
+#define SANGOMA_MAP_PRI_EVENT(spri, event, func) spri.eventmap[event] = func;
+
+char *sangoma_pri_event_str(sangoma_pri_event_t event_id);
+int sangoma_one_loop(struct sangoma_pri *spri);
+int sangoma_init_pri(struct sangoma_pri *spri, int span, int dchan, int swtype, int node, int debug);
+int sangoma_run_pri(struct sangoma_pri *spri);
+
+#endif
Added: freeswitch/trunk/libs/openzap/src/ss7/README (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/ss7/README (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ss7/README 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3 @@
+SS7 Coming soon
+
+-Shane Burrell-
Added: freeswitch/trunk/libs/openzap/src/testanalog.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/testanalog.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/testanalog.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,133 @@
+#include "openzap.h"
+
+
+static void *test_call(zap_thread_t *me, void *obj)
+{
+ zap_channel_t *chan = (zap_channel_t *) obj;
+ uint8_t frame[1024];
+ zap_size_t len;
+ char *number = strdup("5551212");
+
+ zap_sleep(10 * 1000);
+
+ zap_log(ZAP_LOG_DEBUG, "answer call and start echo test\n");
+
+ zap_set_state_locked(chan, ZAP_CHANNEL_STATE_UP);
+ zap_channel_command(chan, ZAP_COMMAND_SEND_DTMF, number);
+
+ while (chan->state == ZAP_CHANNEL_STATE_UP) {
+ zap_wait_flag_t flags = ZAP_READ;
+
+ if (zap_channel_wait(chan, &flags, -1) == ZAP_FAIL) {
+ break;
+ }
+ len = sizeof(frame);
+ if (flags & ZAP_READ) {
+ if (zap_channel_read(chan, frame, &len) == ZAP_SUCCESS) {
+ //zap_log(ZAP_LOG_DEBUG, "WRITE %d\n", len);
+ zap_channel_write(chan, frame, sizeof(frame), &len);
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (chan->state == ZAP_CHANNEL_STATE_UP) {
+ zap_set_state_locked(chan, ZAP_CHANNEL_STATE_BUSY);
+ }
+
+ zap_log(ZAP_LOG_DEBUG, "call over\n");
+ free(number);
+ return NULL;
+}
+
+static ZIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+ zap_log(ZAP_LOG_DEBUG, "got sig [%s]\n", zap_signal_event2str(sigmsg->event_id));
+
+ switch(sigmsg->event_id) {
+ case ZAP_SIGEVENT_START:
+ zap_set_state_locked(sigmsg->channel, ZAP_CHANNEL_STATE_RING);
+ zap_log(ZAP_LOG_DEBUG, "launching thread and indicating ring\n");
+ zap_thread_create_detached(test_call, sigmsg->channel);
+ break;
+ default:
+ break;
+ }
+
+ return ZAP_SUCCESS;
+}
+
+static int R = 0;
+#if 0
+static void handle_SIGINT(int sig)
+{
+ if (sig);
+ R = 0;
+ return;
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+ zap_span_t *span;
+ int span_id;
+ int digit_timeout = 2000;
+ int max_dialstr = 11;
+
+ if (argc < 2) {
+ printf("usage %s <spanno>\n", argv[0]);
+ exit(-1);
+ }
+
+ span_id = atoi(argv[1]);
+
+ zap_global_set_default_logger(ZAP_LOG_LEVEL_DEBUG);
+
+ if (zap_global_init() != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error loading OpenZAP\n");
+ exit(-1);
+ }
+
+ zap_log(ZAP_LOG_DEBUG, "OpenZAP loaded\n");
+
+ if (zap_span_find(span_id, &span) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error finding OpenZAP span\n");
+ goto done;
+ }
+
+
+ if (zap_configure_span("analog", span, on_signal,
+ "tonemap", "us",
+ "digit_timeout", &digit_timeout,
+ "max_dialstr", &max_dialstr,
+ TAG_END
+ ) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error configuring OpenZAP span\n");
+ goto done;
+ }
+ zap_span_start(span);
+
+ R = 1;
+
+ while(zap_running() && R) {
+ zap_sleep(1 * 1000);
+ }
+
+done:
+
+ zap_global_destroy();
+ return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
Added: freeswitch/trunk/libs/openzap/src/testapp.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/testapp.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/testapp.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,83 @@
+#include "openzap.h"
+
+int main(int argc, char *argv[])
+{
+ zap_global_set_default_logger(ZAP_LOG_LEVEL_DEBUG);
+ zap_channel_t *chan;
+ unsigned ms = 20;
+ zap_codec_t codec = ZAP_CODEC_SLIN;
+ unsigned runs = 1;
+
+
+ if (zap_global_init() != ZAP_SUCCESS) {
+ fprintf(stderr, "Error loading OpenZAP\n");
+ exit(-1);
+ }
+
+ printf("OpenZAP loaded\n");
+
+ top:
+ //if (zap_channel_open_any("wanpipe", 0, ZAP_TOP_DOWN, &chan) == ZAP_SUCCESS) {
+ if (zap_channel_open(1, 1, &chan) == ZAP_SUCCESS) {
+ int x = 0;
+ printf("opened channel %d:%d\n", chan->span_id, chan->chan_id);
+
+#if 1
+ if (zap_channel_command(chan, ZAP_COMMAND_SET_INTERVAL, &ms) == ZAP_SUCCESS) {
+ ms = 0;
+ zap_channel_command(chan, ZAP_COMMAND_GET_INTERVAL, &ms);
+ printf("interval set to %u\n", ms);
+ } else {
+ printf("set interval failed [%s]\n", chan->last_error);
+ }
+#endif
+ if (zap_channel_command(chan, ZAP_COMMAND_SET_CODEC, &codec) == ZAP_SUCCESS) {
+ codec = 1;
+ zap_channel_command(chan, ZAP_COMMAND_GET_CODEC, &codec);
+ printf("codec set to %u\n", codec);
+ } else {
+ printf("set codec failed [%s]\n", chan->last_error);
+ }
+
+ for(x = 0; x < 25; x++) {
+ unsigned char buf[2048];
+ zap_size_t len = sizeof(buf);
+ zap_wait_flag_t flags = ZAP_READ;
+
+ if (zap_channel_wait(chan, &flags, -1) == ZAP_FAIL) {
+ printf("wait FAIL! %u [%s]\n", (unsigned)len, chan->last_error);
+ }
+ if (flags & ZAP_READ) {
+ if (zap_channel_read(chan, buf, &len) == ZAP_SUCCESS) {
+ printf("READ: %u\n", (unsigned)len);
+ } else {
+ printf("READ FAIL! %u [%s]\n", (unsigned)len, chan->last_error);
+ break;
+ }
+ } else {
+ printf("wait fail [%s]\n", chan->last_error);
+ }
+ }
+ zap_channel_close(&chan);
+ } else {
+ printf("open fail [%s]\n", chan->last_error);
+ }
+
+ if(--runs) {
+ goto top;
+ }
+
+ zap_global_destroy();
+ return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/testboost.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/testboost.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/testboost.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,75 @@
+#include "openzap.h"
+
+static ZIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+ return ZAP_FAIL;
+}
+
+static int R = 0;
+#if 0
+static void handle_SIGINT(int sig)
+{
+ if (sig);
+ R = 0;
+ return;
+}
+#endif
+int main(int argc, char *argv[])
+{
+ zap_span_t *span;
+ int local_port, remote_port;
+
+ local_port = remote_port = 53000;
+
+ zap_global_set_default_logger(ZAP_LOG_LEVEL_DEBUG);
+
+ if (argc < 2) {
+ printf("umm no\n");
+ exit(-1);
+ }
+
+ if (zap_global_init() != ZAP_SUCCESS) {
+ fprintf(stderr, "Error loading OpenZAP\n");
+ exit(-1);
+ }
+
+ printf("OpenZAP loaded\n");
+
+ if (zap_span_find(atoi(argv[1]), &span) != ZAP_SUCCESS) {
+ fprintf(stderr, "Error finding OpenZAP span\n");
+ goto done;
+ }
+
+ if (zap_configure_span("ss7_boost", span, on_signal,
+ "local_ip", "127.0.0.65",
+ "local_port", &local_port,
+ "remote_ip", "127.0.0.66",
+ "remote_port", &remote_port,
+ TAG_END) == ZAP_SUCCESS) {
+ zap_span_start(span);
+ } else {
+ fprintf(stderr, "Error starting SS7_BOOST\n");
+ goto done;
+ }
+
+ while(zap_running() && R) {
+ zap_sleep(1 * 1000);
+ }
+
+ done:
+
+ zap_global_destroy();
+
+ return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/testcid.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/testcid.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/testcid.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,108 @@
+#include "openzap.h"
+zap_status_t my_write_sample(int16_t *buf, zap_size_t buflen, void *user_data);
+
+struct helper {
+ int fd;
+ int wrote;
+};
+
+zap_status_t my_write_sample(int16_t *buf, zap_size_t buflen, void *user_data)
+{
+ struct helper *foo = (struct helper *) user_data;
+ size_t len;
+ len = write(foo->fd, buf, buflen * 2);
+ if (!len) return ZAP_FAIL;
+ foo->wrote += buflen * 2;
+ return ZAP_SUCCESS;
+}
+
+int main(int argc, char *argv[])
+{
+ struct zap_fsk_modulator fsk_trans;
+ zap_fsk_data_state_t fsk_data = {0};
+ int fd = -1;
+ int16_t buf[160] = {0};
+ ssize_t len = 0;
+ size_t type, mlen;
+ char *sp;
+ char str[128] = "";
+ char fbuf[256];
+ uint8_t databuf[1024] = "";
+ struct helper foo = {0};
+ // int x, bytes, start_bits = 180, stop_bits = 5, sbits = 300;
+ char time_str[9];
+ struct tm tm;
+ time_t now;
+
+ if (argc < 2) {
+ int x;
+ const char *url = "sip:cool@rad.com";
+
+ if ((fd = open("tone.raw", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
+ fprintf(stderr, "File Error! [%s]\n", strerror(errno));
+ exit(-1);
+ }
+
+
+ time(&now);
+ localtime_r(&now, &tm);
+ strftime(time_str, sizeof(time_str), "%m%d%H%M", &tm);
+
+ zap_fsk_data_init(&fsk_data, databuf, sizeof(databuf));
+#if 1
+
+ zap_fsk_data_add_mdmf(&fsk_data, MDMF_DATETIME, (uint8_t *)time_str, strlen(time_str));
+ //zap_fsk_data_add_mdmf(&fsk_data, MDMF_DATETIME, "06091213", 8);
+ zap_fsk_data_add_mdmf(&fsk_data, MDMF_PHONE_NUM, (uint8_t *)"14149361212", 7);
+ zap_fsk_data_add_mdmf(&fsk_data, MDMF_PHONE_NAME, (uint8_t *)"Fred Smith", 10);
+ for(x = 0; x < 0; x++)
+ zap_fsk_data_add_mdmf(&fsk_data, MDMF_ALT_ROUTE, (uint8_t *)url, strlen(url));
+#else
+ zap_fsk_data_add_sdmf(&fsk_data, "06061234", "0");
+ //zap_fsk_data_add_sdmf(&state, "06061234", "5551212");
+#endif
+ zap_fsk_data_add_checksum(&fsk_data);
+
+ foo.fd = fd;
+
+
+ zap_fsk_modulator_init(&fsk_trans, FSK_BELL202, 8000, &fsk_data, -14, 180, 5, 300, my_write_sample, &foo);
+ zap_fsk_modulator_send_all((&fsk_trans));
+
+ printf("%u %d %d\n", (unsigned) fsk_data.dlen, foo.wrote, fsk_trans.est_bytes);
+
+ if (fd > -1) {
+ close (fd);
+ }
+
+ return 0;
+ }
+
+ if (zap_fsk_demod_init(&fsk_data, 8000, (uint8_t *)fbuf, sizeof(fbuf))) {
+ printf("wtf\n");
+ return 0;
+ }
+
+ if ((fd = open(argv[1], O_RDONLY)) < 0) {
+ fprintf(stderr, "cant open file %s\n", argv[1]);
+ exit (-1);
+ }
+
+ while((len = read(fd, buf, sizeof(buf))) > 0) {
+ if (zap_fsk_demod_feed(&fsk_data, buf, len / 2) != ZAP_SUCCESS) {
+ break;
+ }
+ }
+
+ while(zap_fsk_data_parse(&fsk_data, &type, &sp, &mlen) == ZAP_SUCCESS) {
+ zap_copy_string(str, sp, mlen+1);
+ *(str+mlen) = '\0';
+ zap_clean_string(str);
+ printf("TYPE %u (%s) LEN %u VAL [%s]\n", (unsigned)type, zap_mdmf_type2str(type), (unsigned)mlen, str);
+ }
+
+ zap_fsk_demod_destroy(&fsk_data);
+
+ close(fd);
+ return 0;
+}
Added: freeswitch/trunk/libs/openzap/src/testisdn.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/testisdn.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/testisdn.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,74 @@
+#include "openzap.h"
+#include <signal.h>
+
+
+static ZIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+ return ZAP_FAIL;
+}
+
+static int R = 0;
+static void handle_SIGINT(int sig)
+{
+ if (sig);
+ R = 0;
+ return;
+}
+
+int main(int argc, char *argv[])
+{
+ zap_span_t *span;
+
+ zap_global_set_default_logger(ZAP_LOG_LEVEL_DEBUG);
+
+ if (argc < 2) {
+ printf("umm no\n");
+ exit(-1);
+ }
+
+ if (zap_global_init() != ZAP_SUCCESS) {
+ fprintf(stderr, "Error loading OpenZAP\n");
+ exit(-1);
+ }
+
+ printf("OpenZAP loaded\n");
+
+ if (zap_span_find(atoi(argv[1]), &span) != ZAP_SUCCESS) {
+ fprintf(stderr, "Error finding OpenZAP span\n");
+ goto done;
+ }
+
+ if (zap_configure_span("isdn", span, on_signal,
+ "mode", "te",
+ "dialect", "national",
+ TAG_END) == ZAP_SUCCESS) {
+ zap_span_start(span);
+ } else {
+ fprintf(stderr, "Error starting ISDN D-Channel\n");
+ goto done;
+ }
+
+ signal(SIGINT, handle_SIGINT);
+ R = 1;
+ while(R) {
+ zap_sleep(1 * 1000);
+ }
+
+ done:
+
+ zap_global_destroy();
+
+ return 1;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/testm3ua.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/testm3ua.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/testm3ua.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,60 @@
+/*
+ * testm3ua.c
+ * openzap
+ *
+ * Created by Shane Burrell on 4/8/08.
+ * Copyright 2008 __MyCompanyName__. All rights reserved.
+ *
+ */
+
+#include "testm3ua.h"
+#include "openzap.h"
+#include "zap_m3ua.h"
+
+static ZIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+ return ZAP_FAIL;
+}
+
+int main(int argc, char *argv[])
+{
+ zap_span_t *span;
+ //m3ua_data_t *data;
+
+ zap_global_set_default_logger(ZAP_LOG_LEVEL_DEBUG);
+
+ if (argc < 5) {
+ printf("more args needed\n");
+ exit(-1);
+ }
+
+ if (zap_global_init() != ZAP_SUCCESS) {
+ fprintf(stderr, "Error loading OpenZAP\n");
+ exit(-1);
+ }
+
+ printf("OpenZAP loaded\n");
+
+ if (zap_span_find(atoi(argv[1]), &span) != ZAP_SUCCESS) {
+ fprintf(stderr, "Error finding OpenZAP span\n");
+ goto done;
+ }
+
+
+ if (zap_m3ua_configure_span(span) == ZAP_SUCCESS) {
+ //data = span->signal_data;
+ zap_m3ua_start(span);
+ } else {
+ fprintf(stderr, "Error starting M3UA\n");
+ goto done;
+ }
+
+ //while(zap_test_flag(data, ZAP_M3UA_RUNNING)) {
+ // zap_sleep(1 * 1000);
+ //}
+
+ done:
+
+ zap_global_destroy();
+
+}
Added: freeswitch/trunk/libs/openzap/src/testpri.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/testpri.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/testpri.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,162 @@
+#include "openzap.h"
+#include <signal.h>
+
+static int THREADS[4][31] = { {0} };
+static int R = 0;
+static int T = 0;
+static zap_mutex_t *mutex = NULL;
+
+
+static void *channel_run(zap_thread_t *me, void *obj)
+{
+ zap_channel_t *zchan = obj;
+ int fd = -1;
+ short buf[160];
+
+ zap_mutex_lock(mutex);
+ T++;
+ zap_mutex_unlock(mutex);
+
+ zap_set_state_locked_wait(zchan, ZAP_CHANNEL_STATE_UP);
+
+ if ((fd = open("test.raw", O_RDONLY, 0)) < 0) {
+ goto end;
+ }
+
+ while(R == 1 && THREADS[zchan->span_id][zchan->chan_id] == 1) {
+ ssize_t bytes = read(fd, buf, sizeof(buf));
+ size_t bbytes;
+
+ if (bytes <= 0) {
+ break;
+ }
+
+ bbytes = (size_t) bytes;
+
+ zio_slin2alaw(buf, sizeof(buf), &bbytes);
+
+ if (zap_channel_write(zchan, buf, sizeof(buf), &bbytes) != ZAP_SUCCESS) {
+ break;
+ }
+ }
+
+ close(fd);
+
+ end:
+
+ zap_set_state_locked_wait(zchan, ZAP_CHANNEL_STATE_HANGUP);
+
+ THREADS[zchan->span_id][zchan->chan_id] = 0;
+
+ zap_mutex_lock(mutex);
+ T = 0;
+ zap_mutex_unlock(mutex);
+
+ return NULL;
+}
+
+static ZIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+ zap_log(ZAP_LOG_DEBUG, "got sig %d:%d [%s]\n", sigmsg->channel->span_id, sigmsg->channel->chan_id, zap_signal_event2str(sigmsg->event_id));
+
+ switch(sigmsg->event_id) {
+
+ case ZAP_SIGEVENT_STOP:
+ THREADS[sigmsg->channel->span_id][sigmsg->channel->chan_id] = -1;
+ break;
+
+ case ZAP_SIGEVENT_START:
+ if (!THREADS[sigmsg->channel->span_id][sigmsg->channel->chan_id]) {
+ THREADS[sigmsg->channel->span_id][sigmsg->channel->chan_id] = 1;
+ zap_thread_create_detached(channel_run, sigmsg->channel);
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ return ZAP_SUCCESS;
+}
+
+
+static void handle_SIGINT(int sig)
+{
+ if (sig);
+
+ zap_mutex_lock(mutex);
+ R = 0;
+ zap_mutex_unlock(mutex);
+
+ return;
+}
+
+int main(int argc, char *argv[])
+{
+ zap_span_t *span;
+ zap_mutex_create(&mutex);
+
+ zap_global_set_default_logger(ZAP_LOG_LEVEL_DEBUG);
+
+ if (argc < 2) {
+ printf("umm no\n");
+ exit(-1);
+ }
+
+ if (zap_global_init() != ZAP_SUCCESS) {
+ fprintf(stderr, "Error loading OpenZAP\n");
+ exit(-1);
+ }
+
+ printf("OpenZAP loaded\n");
+
+ if (zap_span_find(atoi(argv[1]), &span) != ZAP_SUCCESS) {
+ fprintf(stderr, "Error finding OpenZAP span\n");
+ goto done;
+ }
+
+
+
+ if (zap_configure_span(
+ "libpri", span, on_signal,
+ "node", "cpe",
+ "switch", "euroisdn",
+ "dp", "unknown",
+ "l1", "alaw",
+ "debug", NULL,
+ "opts", 0,
+ TAG_END) == ZAP_SUCCESS) {
+
+
+ zap_span_start(span);
+ } else {
+ fprintf(stderr, "Error starting ISDN D-Channel\n");
+ goto done;
+ }
+
+ signal(SIGINT, handle_SIGINT);
+ zap_mutex_lock(mutex);
+ R = 1;
+ zap_mutex_unlock(mutex);
+ while(R || T) {
+ zap_sleep(1 * 1000);
+ }
+
+ done:
+
+ zap_global_destroy();
+
+ return 1;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/testr2.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/testr2.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/testr2.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,86 @@
+#include "openzap.h"
+#include <signal.h>
+
+static int R = 0;
+static zap_mutex_t *mutex = NULL;
+
+static ZIO_SIGNAL_CB_FUNCTION(on_r2_signal)
+{
+ zap_log(ZAP_LOG_DEBUG, "Got R2 channel sig [%s] in channel\n", zap_signal_event2str(sigmsg->event_id), sigmsg->channel->physical_chan_id);
+ return ZAP_SUCCESS;
+}
+
+static void handle_SIGINT(int sig)
+{
+ zap_mutex_lock(mutex);
+ R = 0;
+ zap_mutex_unlock(mutex);
+ return;
+}
+
+int main(int argc, char *argv[])
+{
+ zap_span_t *span;
+ zap_mutex_create(&mutex);
+
+ zap_global_set_default_logger(ZAP_LOG_LEVEL_DEBUG);
+
+ if (argc < 2) {
+ printf("umm no\n");
+ exit(-1);
+ }
+
+ if (zap_global_init() != ZAP_SUCCESS) {
+ fprintf(stderr, "Error loading OpenZAP\n");
+ exit(-1);
+ }
+
+ printf("OpenZAP loaded\n");
+
+ if (zap_span_find(atoi(argv[1]), &span) != ZAP_SUCCESS) {
+ fprintf(stderr, "Error finding OpenZAP span\n");
+ goto done;
+ }
+
+
+
+ if (zap_configure_span("r2", span, on_r2_signal,
+ "variant", "mx",
+ "max_ani", 10,
+ "max_dnis", 4,
+ "logging", "all",
+ TAG_END) == ZAP_SUCCESS) {
+
+
+ zap_span_start(span);
+ } else {
+ fprintf(stderr, "Error starting R2 span\n");
+ goto done;
+ }
+
+ signal(SIGINT, handle_SIGINT);
+ zap_mutex_lock(mutex);
+ R = 1;
+ zap_mutex_unlock(mutex);
+ while(R) {
+ zap_sleep(1 * 1000);
+ }
+
+ done:
+
+ zap_global_destroy();
+
+ return 1;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/testtones.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/testtones.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/testtones.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,76 @@
+#include "openzap.h"
+
+struct ttmp {
+ int fd;
+};
+
+static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+ struct ttmp *tmp = ts->user_data;
+ int wrote;
+ size_t len;
+
+ wrote = teletone_mux_tones(ts, map);
+ len = write(tmp->fd, ts->buffer, wrote * 2);
+
+ if (!len) return -1;
+
+ return 0;
+}
+
+#if 1
+int main(int argc, char *argv[])
+{
+ teletone_generation_session_t ts;
+ struct ttmp tmp;
+
+ if (argc < 3) {
+ fprintf(stderr, "Arg Error! <file> <tones>\n");
+ exit(-1);
+ }
+
+ if ((tmp.fd = open(argv[1], O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
+ fprintf(stderr, "File Error! [%s]\n", strerror(errno));
+ exit(-1);
+ }
+
+ teletone_init_session(&ts, 0, teletone_handler, &tmp);
+ ts.rate = 8000;
+ ts.debug = 1;
+ ts.debug_stream = stdout;
+ teletone_run(&ts, argv[2]);
+ close(tmp.fd);
+
+ return 0;
+}
+#else
+int32_t main(int argc, char *argv[])
+{
+ int32_t j, i, fd = -1;
+ int32_t rate = 8000;
+ /* SIT tones and durations */
+ float tones[] = { 913.8, 1370.6, 1776.7, 0 };
+ int32_t durations[] = {274, 274, 380, 0};
+ teletone_dds_state_t dds = {0};
+ int16_t sample;
+ size_t len = 1;
+
+ if (argc < 2 || (fd = open(argv[1], O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
+ fprintf(stderr, "File Error!\n", strerror(errno));
+ exit(-1);
+ }
+
+ for (j = 0; tones[j] && durations[j]; j++) {
+
+ teletone_dds_state_set_tone(&dds, tones[j], rate, -50);
+
+ for(i = 0; (i < durations[j] * rate / 1000) && len != 0; i++) {
+ sample = teletone_dds_modulate_sample(&dds) * 20;
+ len = write(fd, &sample, sizeof(sample));
+ }
+
+ }
+
+ close(fd);
+}
+#endif
Added: freeswitch/trunk/libs/openzap/src/uart.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/uart.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/uart.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,124 @@
+
+/*
+ * uart.c
+ *
+ * Copyright (c) 2005 Robert Krten. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * This module contains a simple 8-bit UART, which performs a callback
+ * with the decoded byte value.
+ *
+ * 2005 06 11 R. Krten created
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "uart.h"
+
+/*
+ * dsp_uart_attr_init
+ *
+ * Initializes the attributes structure; this must be done before the
+ * attributes structure is used.
+*/
+
+void dsp_uart_attr_init (dsp_uart_attr_t *attr)
+{
+ memset (attr, 0, sizeof (*attr));
+}
+
+/*
+ * dsp_uart_attr_get_bytehandler
+ * dsp_uart_attr_set_bytehandler
+ *
+ * These functions get and set their respective elements from the
+ * attributes structure. If an error code is returned, it is just
+ * zero == ok, -1 == fail.
+*/
+
+bytehandler_func_t dsp_uart_attr_get_bytehandler(dsp_uart_attr_t *attr, void **bytehandler_arg)
+{
+ *bytehandler_arg = attr->bytehandler_arg;
+ return attr->bytehandler;
+}
+
+void dsp_uart_attr_set_bytehandler(dsp_uart_attr_t *attr, bytehandler_func_t bytehandler, void *bytehandler_arg)
+{
+ attr->bytehandler = bytehandler;
+ attr->bytehandler_arg = bytehandler_arg;
+}
+
+dsp_uart_handle_t *dsp_uart_create(dsp_uart_attr_t *attr)
+{
+ dsp_uart_handle_t *handle;
+
+ handle = malloc(sizeof (*handle));
+ if (handle) {
+ memset(handle, 0, sizeof (*handle));
+
+ /* fill the attributes member */
+ memcpy(&handle->attr, attr, sizeof (*attr));
+ }
+ return handle;
+}
+
+void dsp_uart_destroy(dsp_uart_handle_t **handle)
+{
+ if (*handle) {
+ free(*handle);
+ *handle = NULL;
+ }
+}
+
+
+void dsp_uart_bit_handler(void *x, int bit)
+{
+ dsp_uart_handle_t *handle = (dsp_uart_handle_t *) x;
+
+ if (!handle->have_start) {
+ if (bit) {
+ return; /* waiting for start bit (0) */
+ }
+ handle->have_start = 1;
+ handle->data = 0;
+ handle->nbits = 0;
+ return;
+ }
+
+ handle->data >>= 1;
+ handle->data |= 0x80 * !!bit;
+ handle->nbits++;
+
+ if (handle->nbits == 8) {
+ handle->attr.bytehandler(handle->attr.bytehandler_arg, handle->data);
+ handle->nbits = 0;
+ handle->data = 0;
+ handle->have_start = 0;
+ }
+/* might consider handling errors in the future... */
+}
+
Added: freeswitch/trunk/libs/openzap/src/zap_buffer.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/zap_buffer.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/zap_buffer.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#include "openzap.h"
+#include "zap_buffer.h"
+
+static unsigned buffer_id = 0;
+
+struct zap_buffer {
+ unsigned char *data;
+ unsigned char *head;
+ zap_size_t used;
+ zap_size_t actually_used;
+ zap_size_t datalen;
+ zap_size_t max_len;
+ zap_size_t blocksize;
+ unsigned id;
+ int loops;
+};
+
+
+OZ_DECLARE(zap_status_t) zap_buffer_create(zap_buffer_t **buffer, zap_size_t blocksize, zap_size_t start_len, zap_size_t max_len)
+{
+ zap_buffer_t *new_buffer;
+
+ new_buffer = malloc(sizeof(*new_buffer));
+ if (new_buffer) {
+ memset(new_buffer, 0, sizeof(*new_buffer));
+
+ if (start_len) {
+ new_buffer->data = malloc(start_len);
+ if (!new_buffer->data) {
+ free(new_buffer);
+ return ZAP_MEMERR;
+ }
+ memset(new_buffer->data, 0, start_len);
+ }
+
+ new_buffer->max_len = max_len;
+ new_buffer->datalen = start_len;
+ new_buffer->id = buffer_id++;
+ new_buffer->blocksize = blocksize;
+ new_buffer->head = new_buffer->data;
+
+ *buffer = new_buffer;
+ return ZAP_SUCCESS;
+ }
+
+ return ZAP_MEMERR;
+}
+
+OZ_DECLARE(zap_size_t) zap_buffer_len(zap_buffer_t *buffer)
+{
+
+ assert(buffer != NULL);
+
+ return buffer->datalen;
+
+}
+
+
+OZ_DECLARE(zap_size_t) zap_buffer_freespace(zap_buffer_t *buffer)
+{
+ assert(buffer != NULL);
+
+
+ if (buffer->max_len) {
+ return (zap_size_t) (buffer->max_len - buffer->used);
+ }
+ return 1000000;
+
+}
+
+OZ_DECLARE(zap_size_t) zap_buffer_inuse(zap_buffer_t *buffer)
+{
+ assert(buffer != NULL);
+
+ return buffer->used;
+}
+
+OZ_DECLARE(zap_size_t) zap_buffer_seek(zap_buffer_t *buffer, zap_size_t datalen)
+{
+ zap_size_t reading = 0;
+
+ assert(buffer != NULL);
+
+ if (buffer->used < 1) {
+ buffer->used = 0;
+ return 0;
+ } else if (buffer->used >= datalen) {
+ reading = datalen;
+ } else {
+ reading = buffer->used;
+ }
+
+ buffer->used = buffer->actually_used - reading;
+ buffer->head = buffer->data + reading;
+
+ return reading;
+}
+
+OZ_DECLARE(zap_size_t) zap_buffer_toss(zap_buffer_t *buffer, zap_size_t datalen)
+{
+ zap_size_t reading = 0;
+
+ assert(buffer != NULL);
+
+ if (buffer->used < 1) {
+ buffer->used = 0;
+ return 0;
+ } else if (buffer->used >= datalen) {
+ reading = datalen;
+ } else {
+ reading = buffer->used;
+ }
+
+ buffer->used -= reading;
+ buffer->head += reading;
+
+ return buffer->used;
+}
+
+OZ_DECLARE(void) zap_buffer_set_loops(zap_buffer_t *buffer, int loops)
+{
+ buffer->loops = loops;
+}
+
+OZ_DECLARE(zap_size_t) zap_buffer_read_loop(zap_buffer_t *buffer, void *data, zap_size_t datalen)
+{
+ zap_size_t len;
+ if ((len = zap_buffer_read(buffer, data, datalen)) < datalen) {
+ if (buffer->loops == 0) {
+ return len;
+ }
+ buffer->head = buffer->data;
+ buffer->used = buffer->actually_used;
+ len = zap_buffer_read(buffer, (char*)data + len, datalen - len);
+ buffer->loops--;
+ }
+ return len;
+}
+
+OZ_DECLARE(zap_size_t) zap_buffer_read(zap_buffer_t *buffer, void *data, zap_size_t datalen)
+{
+ zap_size_t reading = 0;
+
+ assert(buffer != NULL);
+ assert(data != NULL);
+
+
+ if (buffer->used < 1) {
+ buffer->used = 0;
+ return 0;
+ } else if (buffer->used >= datalen) {
+ reading = datalen;
+ } else {
+ reading = buffer->used;
+ }
+
+ memcpy(data, buffer->head, reading);
+ buffer->used -= reading;
+ buffer->head += reading;
+
+ /* if (buffer->id == 4) printf("%u o %d = %d\n", buffer->id, (unsigned)reading, (unsigned)buffer->used); */
+ return reading;
+}
+
+OZ_DECLARE(zap_size_t) zap_buffer_write(zap_buffer_t *buffer, const void *data, zap_size_t datalen)
+{
+ zap_size_t freespace, actual_freespace;
+
+ assert(buffer != NULL);
+ assert(data != NULL);
+ assert(buffer->data != NULL);
+
+ if (!datalen) {
+ return buffer->used;
+ }
+
+ actual_freespace = buffer->datalen - buffer->actually_used;
+ if (actual_freespace < datalen && (!buffer->max_len || (buffer->used + datalen <= buffer->max_len))) {
+ memmove(buffer->data, buffer->head, buffer->used);
+ buffer->head = buffer->data;
+ buffer->actually_used = buffer->used;
+ }
+
+ freespace = buffer->datalen - buffer->used;
+
+ /*
+ if (buffer->data != buffer->head) {
+ memmove(buffer->data, buffer->head, buffer->used);
+ buffer->head = buffer->data;
+ }
+ */
+
+ if (freespace < datalen) {
+ zap_size_t new_size, new_block_size;
+ void *data;
+
+ new_size = buffer->datalen + datalen;
+ new_block_size = buffer->datalen + buffer->blocksize;
+
+ if (new_block_size > new_size) {
+ new_size = new_block_size;
+ }
+ buffer->head = buffer->data;
+ data = realloc(buffer->data, new_size);
+ if (!data) {
+ return 0;
+ }
+ buffer->data = data;
+ buffer->head = buffer->data;
+ buffer->datalen = new_size;
+ }
+
+
+ freespace = buffer->datalen - buffer->used;
+
+ if (freespace < datalen) {
+ return 0;
+ } else {
+ memcpy(buffer->head + buffer->used, data, datalen);
+ buffer->used += datalen;
+ buffer->actually_used += datalen;
+ }
+ /* if (buffer->id == 4) printf("%u i %d = %d\n", buffer->id, (unsigned)datalen, (unsigned)buffer->used); */
+
+ return buffer->used;
+}
+
+OZ_DECLARE(void) zap_buffer_zero(zap_buffer_t *buffer)
+{
+ assert(buffer != NULL);
+ assert(buffer->data != NULL);
+
+ buffer->used = 0;
+ buffer->actually_used = 0;
+ buffer->head = buffer->data;
+}
+
+OZ_DECLARE(zap_size_t) zap_buffer_zwrite(zap_buffer_t *buffer, const void *data, zap_size_t datalen)
+{
+ zap_size_t w;
+
+ if (!(w = zap_buffer_write(buffer, data, datalen))) {
+ zap_buffer_zero(buffer);
+ return zap_buffer_write(buffer, data, datalen);
+ }
+
+ return w;
+}
+
+OZ_DECLARE(void) zap_buffer_destroy(zap_buffer_t **buffer)
+{
+ if (*buffer) {
+ free((*buffer)->data);
+ free(*buffer);
+ }
+
+ *buffer = NULL;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/zap_callerid.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/zap_callerid.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/zap_callerid.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,307 @@
+#include "openzap.h"
+#include "fsk.h"
+#include "uart.h"
+
+
+
+static void fsk_byte_handler (void *x, int data)
+{
+ zap_fsk_data_state_t *state = (zap_fsk_data_state_t *) x;
+ uint8_t byte = (uint8_t)data;
+
+ top:
+
+ if (state->init == 3) {
+ return;
+ }
+
+ if (state->dlen) {
+ goto add_byte;
+ }
+
+ if (state->bpos == 1) {
+ state->blen = byte;
+
+ if ((uint32_t)(state->dlen = state->bpos + byte + 2) > state->bufsize) {
+ state->dlen = state->bufsize;
+ }
+ goto top;
+ }
+
+ add_byte:
+
+ if (state->bpos <= state->dlen) {
+ state->buf[state->bpos++] = byte;
+ } else {
+ state->init = 3;
+ }
+}
+
+OZ_DECLARE(zap_status_t) zap_fsk_data_init(zap_fsk_data_state_t *state, uint8_t *data, uint32_t datalen)
+{
+ memset(state, 0, sizeof(*state));
+ state->buf = data;
+ state->bufsize = datalen;
+ state->bpos = 2;
+
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_fsk_data_add_sdmf(zap_fsk_data_state_t *state, const char *date, char *number)
+{
+ size_t dlen = strlen(date);
+ size_t nlen = strlen(number);
+
+ state->buf[0] = ZAP_CID_TYPE_SDMF;
+ memcpy(&state->buf[state->bpos], date, dlen);
+ state->bpos += dlen;
+ memcpy(&state->buf[state->bpos], number, nlen);
+ state->bpos += nlen;
+
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_fsk_data_add_mdmf(zap_fsk_data_state_t *state, zap_mdmf_type_t type, const uint8_t *data, uint32_t datalen)
+{
+ state->buf[0] = ZAP_CID_TYPE_MDMF;
+ state->buf[state->bpos++] = type;
+ state->buf[state->bpos++] = (uint8_t)datalen;
+ memcpy(&state->buf[state->bpos], data, datalen);
+ state->bpos += datalen;
+ return ZAP_SUCCESS;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_fsk_data_add_checksum(zap_fsk_data_state_t *state)
+{
+ uint32_t i;
+ uint8_t check = 0;
+
+ state->buf[1] = (uint8_t)(state->bpos - 2);
+
+ for (i = 0; i < state->bpos; i++) {
+ check = check + state->buf[i];
+ }
+
+ state->checksum = state->buf[state->bpos] = (uint8_t)(256 - check);
+ state->bpos++;
+
+ state->dlen = state->bpos;
+ state->blen = state->buf[1];
+
+ return ZAP_SUCCESS;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_fsk_data_parse(zap_fsk_data_state_t *state, zap_size_t *type, char **data, zap_size_t *len)
+{
+
+ zap_size_t i;
+ int sum = 0;
+
+ top:
+
+ if (state->checksum != 0 || state->ppos >= state->dlen - 1) {
+ return ZAP_FAIL;
+ }
+
+ if (!state->ppos) {
+ for(i = 0; i < state->bpos; i++) {
+ sum += state->buf[i];
+ }
+ state->checksum = sum % 256;
+ state->ppos = 2;
+
+ if (state->buf[0] != ZAP_CID_TYPE_MDMF && state->buf[0] != ZAP_CID_TYPE_SDMF) {
+ state->checksum = -1;
+ }
+ goto top;
+ }
+
+ if (state->buf[0] == ZAP_CID_TYPE_SDMF) {
+ /* convert sdmf to mdmf so we don't need 2 parsers */
+ if (state->ppos == 2) {
+ *type = MDMF_DATETIME;
+ *len = 8;
+ } else {
+ if (state->buf[state->ppos] == 'P' || state->buf[state->ppos] == 'O') {
+ *type = MDMF_NO_NUM;
+ *len = 1;
+ } else {
+ *type = MDMF_PHONE_NUM;
+ *len = state->blen - 8;
+ }
+ }
+ *data = (char *)&state->buf[state->ppos];
+ state->ppos += *len;
+ return ZAP_SUCCESS;
+ } else if (state->buf[0] == ZAP_CID_TYPE_MDMF) {
+ *type = state->buf[state->ppos++];
+ *len = state->buf[state->ppos++];
+ *data = (char *)&state->buf[state->ppos];
+ state->ppos += *len;
+ return ZAP_SUCCESS;
+ }
+
+ return ZAP_FAIL;
+}
+
+OZ_DECLARE(zap_status_t) zap_fsk_demod_feed(zap_fsk_data_state_t *state, int16_t *data, zap_size_t samples)
+{
+ uint32_t x;
+ int16_t *sp = data;
+
+ if (state->init == 3) {
+ return ZAP_FAIL;
+ }
+
+ for (x = 0; x < samples; x++) {
+ dsp_fsk_sample (state->fsk1200_handle, (double) *sp++ / 32767.0);
+ if (state->dlen && state->bpos >= state->dlen) {
+ state->init = 3;
+ return ZAP_FAIL;
+ }
+ }
+
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_fsk_demod_destroy(zap_fsk_data_state_t *state)
+{
+ dsp_fsk_destroy(&state->fsk1200_handle);
+ memset(state, 0, sizeof(*state));
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(int) zap_fsk_demod_init(zap_fsk_data_state_t *state, int rate, uint8_t *buf, zap_size_t bufsize)
+{
+
+ dsp_fsk_attr_t fsk1200_attr;
+
+ if (state->fsk1200_handle) {
+ dsp_fsk_destroy(&state->fsk1200_handle);
+ }
+
+ memset(state, 0, sizeof(*state));
+ memset(buf, 0, bufsize);
+ state->buf = buf;
+ state->bufsize = bufsize;
+
+ dsp_fsk_attr_init (&fsk1200_attr);
+ dsp_fsk_attr_set_samplerate (&fsk1200_attr, rate);
+ dsp_fsk_attr_set_bytehandler (&fsk1200_attr, fsk_byte_handler, state);
+ state->fsk1200_handle = dsp_fsk_create (&fsk1200_attr);
+
+ if (state->fsk1200_handle == NULL) {
+ return ZAP_FAIL;
+ }
+
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_size_t) zap_fsk_modulator_generate_bit(zap_fsk_modulator_t *fsk_trans, int8_t bit, int16_t *buf, zap_size_t buflen)
+{
+ zap_size_t i;
+
+ for(i = 0 ; i < buflen; i++) {
+ fsk_trans->bit_accum += fsk_trans->bit_factor;
+ if (fsk_trans->bit_accum >= ZAP_FSK_MOD_FACTOR) {
+ fsk_trans->bit_accum -= (ZAP_FSK_MOD_FACTOR + fsk_trans->bit_factor);
+ break;
+ }
+
+ buf[i] = teletone_dds_state_modulate_sample(&fsk_trans->dds, bit);
+ }
+
+ return i;
+}
+
+
+OZ_DECLARE(int32_t) zap_fsk_modulator_generate_carrier_bits(zap_fsk_modulator_t *fsk_trans, uint32_t bits)
+{
+ uint32_t i = 0;
+ zap_size_t r = 0;
+ int8_t bit = 1;
+
+ for (i = 0; i < bits; i++) {
+ if ((r = zap_fsk_modulator_generate_bit(fsk_trans, bit, fsk_trans->sample_buffer, sizeof(fsk_trans->sample_buffer) / 2))) {
+ if (fsk_trans->write_sample_callback(fsk_trans->sample_buffer, r, fsk_trans->user_data) != ZAP_SUCCESS) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ return i;
+}
+
+
+OZ_DECLARE(void) zap_fsk_modulator_generate_chan_sieze(zap_fsk_modulator_t *fsk_trans)
+{
+ uint32_t i = 0;
+ zap_size_t r = 0;
+ int8_t bit = 0;
+
+ for (i = 0; i < fsk_trans->chan_sieze_bits; i++) {
+ if ((r = zap_fsk_modulator_generate_bit(fsk_trans, bit, fsk_trans->sample_buffer, sizeof(fsk_trans->sample_buffer) / 2))) {
+ if (fsk_trans->write_sample_callback(fsk_trans->sample_buffer, r, fsk_trans->user_data) != ZAP_SUCCESS) {
+ break;
+ }
+ } else {
+ break;
+ }
+ bit = !bit;
+ }
+
+
+}
+
+
+OZ_DECLARE(void) zap_fsk_modulator_send_data(zap_fsk_modulator_t *fsk_trans)
+{
+ zap_size_t r = 0;
+ int8_t bit = 0;
+
+ while((bit = zap_bitstream_get_bit(&fsk_trans->bs)) > -1) {
+ if ((r = zap_fsk_modulator_generate_bit(fsk_trans, bit, fsk_trans->sample_buffer, sizeof(fsk_trans->sample_buffer) / 2))) {
+ if (fsk_trans->write_sample_callback(fsk_trans->sample_buffer, r, fsk_trans->user_data) != ZAP_SUCCESS) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+}
+
+
+OZ_DECLARE(zap_status_t) zap_fsk_modulator_init(zap_fsk_modulator_t *fsk_trans,
+ fsk_modem_types_t modem_type,
+ uint32_t sample_rate,
+ zap_fsk_data_state_t *fsk_data,
+ float db_level,
+ uint32_t carrier_bits_start,
+ uint32_t carrier_bits_stop,
+ uint32_t chan_sieze_bits,
+ zap_fsk_write_sample_t write_sample_callback,
+ void *user_data)
+{
+ memset(fsk_trans, 0, sizeof(*fsk_trans));
+ fsk_trans->modem_type = modem_type;
+ teletone_dds_state_set_tone(&fsk_trans->dds, fsk_modem_definitions[fsk_trans->modem_type].freq_space, sample_rate, 0);
+ teletone_dds_state_set_tone(&fsk_trans->dds, fsk_modem_definitions[fsk_trans->modem_type].freq_mark, sample_rate, 1);
+ fsk_trans->bit_factor = (uint32_t)((fsk_modem_definitions[fsk_trans->modem_type].baud_rate * ZAP_FSK_MOD_FACTOR) / (float)sample_rate);
+ fsk_trans->samples_per_bit = (uint32_t) (sample_rate / fsk_modem_definitions[fsk_trans->modem_type].baud_rate);
+ fsk_trans->est_bytes = (int32_t)(((fsk_data->dlen * 10) + carrier_bits_start + carrier_bits_stop + chan_sieze_bits) * ((fsk_trans->samples_per_bit + 1) * 2));
+ fsk_trans->bit_accum = 0;
+ fsk_trans->fsk_data = fsk_data;
+ teletone_dds_state_set_tx_level(&fsk_trans->dds, db_level);
+ zap_bitstream_init(&fsk_trans->bs, fsk_trans->fsk_data->buf, (uint32_t)fsk_trans->fsk_data->dlen, ZAP_ENDIAN_BIG, 1);
+ fsk_trans->carrier_bits_start = carrier_bits_start;
+ fsk_trans->carrier_bits_stop = carrier_bits_stop;
+ fsk_trans->chan_sieze_bits = chan_sieze_bits;
+ fsk_trans->write_sample_callback = write_sample_callback;
+ fsk_trans->user_data = user_data;
+ return ZAP_SUCCESS;
+}
+
Added: freeswitch/trunk/libs/openzap/src/zap_config.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/zap_config.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/zap_config.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#include "openzap.h"
+#include "zap_config.h"
+
+int zap_config_open_file(zap_config_t *cfg, const char *file_path)
+{
+ FILE *f;
+ const char *path = NULL;
+ char path_buf[1024];
+
+ if (file_path[0] == '/') {
+ path = file_path;
+ } else {
+ snprintf(path_buf, sizeof(path_buf), "%s%s%s", ZAP_CONFIG_DIR, ZAP_PATH_SEPARATOR, file_path);
+ path = path_buf;
+ }
+
+ if (!path) {
+ return 0;
+ }
+
+ memset(cfg, 0, sizeof(*cfg));
+ cfg->lockto = -1;
+ zap_log(ZAP_LOG_DEBUG, "Configuration file is %s.\n", path);
+ f = fopen(path, "r");
+
+ if (!f) {
+ if (file_path[0] != '/') {
+ int last = -1;
+ char *var, *val;
+
+ snprintf(path_buf, sizeof(path_buf), "%s%sopenzap.conf", ZAP_CONFIG_DIR, ZAP_PATH_SEPARATOR);
+ path = path_buf;
+
+ if ((f = fopen(path, "r")) == 0) {
+ return 0;
+ }
+
+ cfg->file = f;
+ zap_set_string(cfg->path, path);
+
+ while (zap_config_next_pair(cfg, &var, &val)) {
+ if ((cfg->sectno != last) && !strcmp(cfg->section, file_path)) {
+ cfg->lockto = cfg->sectno;
+ return 1;
+ }
+ }
+
+ zap_config_close_file(cfg);
+ memset(cfg, 0, sizeof(*cfg));
+ return 0;
+ }
+
+ return 0;
+ } else {
+ cfg->file = f;
+ zap_set_string(cfg->path, path);
+ return 1;
+ }
+}
+
+void zap_config_close_file(zap_config_t *cfg)
+{
+
+ if (cfg->file) {
+ fclose(cfg->file);
+ }
+
+ memset(cfg, 0, sizeof(*cfg));
+}
+
+
+
+int zap_config_next_pair(zap_config_t *cfg, char **var, char **val)
+{
+ int ret = 0;
+ char *p, *end;
+
+ *var = *val = NULL;
+
+ if (!cfg->path) {
+ return 0;
+ }
+
+ for (;;) {
+ cfg->lineno++;
+
+ if (!fgets(cfg->buf, sizeof(cfg->buf), cfg->file)) {
+ ret = 0;
+ break;
+ }
+ *var = cfg->buf;
+
+ if (**var == '[' && (end = strchr(*var, ']')) != 0) {
+ *end = '\0';
+ (*var)++;
+ if (**var == '+') {
+ (*var)++;
+ zap_copy_string(cfg->section, *var, sizeof(cfg->section));
+ cfg->sectno++;
+
+ if (cfg->lockto > -1 && cfg->sectno != cfg->lockto) {
+ break;
+ }
+ cfg->catno = 0;
+ cfg->lineno = 0;
+ *var = (char *) "";
+ *val = (char *) "";
+ return 1;
+ } else {
+ zap_copy_string(cfg->category, *var, sizeof(cfg->category));
+ cfg->catno++;
+ }
+ continue;
+ }
+
+
+
+ if (**var == '#' || **var == ';' || **var == '\n' || **var == '\r') {
+ continue;
+ }
+
+ if (!strncmp(*var, "__END__", 7)) {
+ break;
+ }
+
+
+ if ((end = strchr(*var, ';')) && *(end+1) == *end) {
+ *end = '\0';
+ end--;
+ } else if ((end = strchr(*var, '\n')) != 0) {
+ if (*(end - 1) == '\r') {
+ end--;
+ }
+ *end = '\0';
+ }
+
+ p = *var;
+ while ((*p == ' ' || *p == '\t') && p != end) {
+ *p = '\0';
+ p++;
+ }
+ *var = p;
+
+
+ if ((*val = strchr(*var, '=')) == 0) {
+ ret = -1;
+ /* log_printf(0, server.log, "Invalid syntax on %s: line %d\n", cfg->path, cfg->lineno); */
+ continue;
+ } else {
+ p = *val - 1;
+ *(*val) = '\0';
+ (*val)++;
+ if (*(*val) == '>') {
+ *(*val) = '\0';
+ (*val)++;
+ }
+
+ while ((*p == ' ' || *p == '\t') && p != *var) {
+ *p = '\0';
+ p--;
+ }
+
+ p = *val;
+ while ((*p == ' ' || *p == '\t') && p != end) {
+ *p = '\0';
+ p++;
+ }
+ *val = p;
+ ret = 1;
+ break;
+ }
+ }
+
+
+ return ret;
+
+}
+
+OZ_DECLARE (int) zap_config_get_cas_bits(char *strvalue, unsigned char *outbits)
+{
+ char cas_bits[5];
+ unsigned char bit = 0x8;
+ int x = 0;
+ char *double_colon = strchr(strvalue, ':');
+ if (!double_colon) {
+ zap_log(ZAP_LOG_ERROR, "No CAS bits specified: %s, :xxxx definition expected, where x is 1 or 0\n", strvalue);
+ return -1;
+ }
+ double_colon++;
+ *outbits = 0;
+ cas_bits[4] = 0;
+ if (sscanf(double_colon, "%c%c%c%c", &cas_bits[0], &cas_bits[1], &cas_bits[2], &cas_bits[3]) != 4) {
+ zap_log(ZAP_LOG_ERROR, "Invalid CAS bits specified: '%s', :xxxx definition expected, where x is 1 or 0\n", double_colon);
+ return -1;
+ }
+ zap_log(ZAP_LOG_DEBUG, "CAS bits specification found: %s\n", cas_bits);
+ for (; cas_bits[x]; x++) {
+ if ('1' == cas_bits[x]) {
+ *outbits |= bit;
+ } else if ('0' != cas_bits[x]) {
+ zap_log(ZAP_LOG_ERROR, "Invalid CAS pattern specified: %s, just 0 or 1 allowed for each bit\n");
+ return -1;
+ }
+ bit >>= 1;
+ }
+ return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/zap_cpu_monitor.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/zap_cpu_monitor.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/zap_cpu_monitor.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2009, Sangoma Technologies
+ * Moises Silva <moy@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:
+ * David Yat Sin <dyatsin@sangoma.com>
+ *
+ */
+
+#ifdef WIN32
+#define _WIN32_WINNT 0x0501 // To make GetSystemTimes visible in windows.h
+#include <windows.h>
+#else /* LINUX */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#endif
+
+#include "openzap.h"
+#include "zap_cpu_monitor.h"
+struct zap_cpu_monitor_stats
+{
+ /* bool, just used to retrieve the values for the first time and not calculate the percentage of idle time */
+ int valid_last_times;
+
+ /* last calculated percentage of idle time */
+ double last_percentage_of_idle_time;
+
+#ifdef __linux__
+ /* all of these are the Linux jiffies last retrieved count */
+ unsigned long long last_user_time;
+ unsigned long long last_system_time;
+ unsigned long long last_idle_time;
+
+ unsigned long long last_nice_time;
+ unsigned long long last_irq_time;
+ unsigned long long last_soft_irq_time;
+ unsigned long long last_io_wait_time;
+ unsigned long long last_steal_time;
+
+ /* /proc/stat file descriptor used to retrieve the counters */
+ int procfd;
+ int initd;
+#elif defined (WIN32) || defined (WIN64)
+ __int64 i64LastUserTime;
+ __int64 i64LastKernelTime;
+ __int64 i64LastIdleTime;
+#else
+/* Unsupported */
+#endif
+};
+
+#ifdef __linux__
+static zap_status_t zap_cpu_read_stats(struct zap_cpu_monitor_stats *p,
+ unsigned long long *user,
+ unsigned long long *nice,
+ unsigned long long *system,
+ unsigned long long *idle,
+ unsigned long long *iowait,
+ unsigned long long *irq,
+ unsigned long long *softirq,
+ unsigned long long *steal)
+{
+// the output of proc should not change that often from one kernel to other
+// see fs/proc/proc_misc.c or fs/proc/stat.c in the Linux kernel for more details
+// also man 5 proc is useful
+#define CPU_ELEMENTS 8 // change this if you change the format string
+#define CPU_INFO_FORMAT "cpu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu"
+ static const char procfile[] = "/proc/stat";
+ int rc = 0;
+ int myerrno = 0;
+ int elements = 0;
+ const char *cpustr = NULL;
+ char statbuff[1024];
+
+ if (!p->initd) {
+ p->procfd = open(procfile, O_RDONLY, 0);
+ if(p->procfd == -1) {
+ zap_log(ZAP_LOG_ERROR, "Failed to open CPU statistics file %s: %s\n", procfile, strerror(myerrno));
+ return ZAP_FAIL;
+ }
+ p->initd = 1;
+ } else {
+ lseek(p->procfd, 0L, SEEK_SET);
+ }
+
+ rc = read(p->procfd, statbuff, sizeof(statbuff) - 1);
+ if (rc <= 0) {
+ myerrno = errno;
+ zap_log(ZAP_LOG_ERROR, "Failed to read CPU statistics file %s: %s\n", procfile, strerror(myerrno));
+ return ZAP_FAIL;
+ }
+
+ cpustr = strstr(statbuff, "cpu ");
+ if (!cpustr) {
+ zap_log(ZAP_LOG_ERROR, "wrong format for Linux proc cpu statistics: missing cpu string\n");
+ return ZAP_FAIL;
+ }
+
+ elements = sscanf(cpustr, CPU_INFO_FORMAT, user, nice, system, idle, iowait, irq, softirq, steal);
+ if (elements != CPU_ELEMENTS) {
+ zap_log(ZAP_LOG_ERROR, "wrong format for Linux proc cpu statistics: expected %d elements, but just found %d\n", CPU_ELEMENTS, elements);
+ return ZAP_FAIL;
+ }
+ return ZAP_SUCCESS;
+}
+#endif
+
+#ifdef __linux__
+OZ_DECLARE(zap_status_t) zap_cpu_get_system_idle_time (struct zap_cpu_monitor_stats *p, double *idle_percentage)
+{
+ unsigned long long user, nice, system, idle, iowait, irq, softirq, steal;
+ unsigned long long usertime, kerneltime, idletime, totaltime, halftime;
+
+ if (zap_cpu_read_stats(p, &user, &nice, &system, &idle, &iowait, &irq, &softirq, &steal)) {
+ zap_log(ZAP_LOG_ERROR, "Failed to retrieve Linux CPU statistics\n");
+ return ZAP_FAIL;
+ }
+
+ if (!p->valid_last_times) {
+ // we dont strictly need to save all of them but I feel code is more clear if we do
+ p->valid_last_times = 1;
+ p->last_user_time = user;
+ p->last_nice_time = nice;
+ p->last_system_time = system;
+ p->last_irq_time = irq;
+ p->last_soft_irq_time = softirq;
+ p->last_io_wait_time = iowait;
+ p->last_steal_time = steal;
+ p->last_idle_time = idle;
+ p->last_percentage_of_idle_time = 100.0;
+ *idle_percentage = p->last_percentage_of_idle_time;
+ return ZAP_SUCCESS;
+ }
+
+ usertime = (user - p->last_user_time) + (nice - p->last_nice_time);
+ kerneltime = (system - p->last_system_time) + (irq - p->last_irq_time) + (softirq - p->last_soft_irq_time);
+ kerneltime += (iowait - p->last_io_wait_time);
+ kerneltime += (steal - p->last_steal_time);
+ idletime = (idle - p->last_idle_time);
+
+ totaltime = usertime + kerneltime + idletime;
+
+ if (totaltime <= 0) {
+ // this may happen if not enough time has elapsed and the jiffies counters are the same than the last time we checked
+ // jiffies depend on timer interrupts which depend on the number of HZ compile time setting of the kernel
+ // typical configs set HZ to 100 (that means, 100 jiffies updates per second, that is one each 10ms)
+ // avoid an arithmetic exception and return the same values
+ *idle_percentage = p->last_percentage_of_idle_time;
+ return ZAP_SUCCESS;
+ }
+
+ halftime = totaltime / 2UL;
+
+ p->last_percentage_of_idle_time = ((100 * idletime + halftime) / totaltime);
+ *idle_percentage = p->last_percentage_of_idle_time;
+
+ p->last_user_time = user;
+ p->last_nice_time = nice;
+ p->last_system_time = system;
+ p->last_irq_time = irq;
+ p->last_soft_irq_time = softirq;
+ p->last_io_wait_time = iowait;
+ p->last_steal_time = steal;
+ p->last_idle_time = idle;
+
+ return ZAP_SUCCESS;
+}
+
+#elif defined (WIN32) || defined (WIN64)
+OZ_DECLARE(zap_status_t) zap_cpu_get_system_idle_time(struct zap_cpu_monitor_stats *p, double *idle_percentage)
+{
+ FILETIME idleTime;
+ FILETIME kernelTime;
+ FILETIME userTime;
+
+ if (!::GetSystemTimes(&idleTime, &kernelTime, &userTime)) {
+ return false;
+ }
+
+ __int64 i64UserTime = (__int64)userTime.dwLowDateTime | ((__int64)userTime.dwHighDateTime << 32);
+
+ __int64 i64KernelTime = (__int64)kernelTime.dwLowDateTime | ((__int64)kernelTime.dwHighDateTime << 32);
+
+ __int64 i64IdleTime = (__int64)idleTime.dwLowDateTime | ((__int64)idleTime.dwHighDateTime << 32);
+
+ if (p->valid_last_times) {
+ __int64 i64User = i64UserTime - p->i64LastUserTime;
+ __int64 i64Kernel = i64KernelTime - p->i64LastKernelTime;
+ __int64 i64Idle = i64IdleTime - p->i64LastIdleTime;
+ __int64 i64System = i64User + i64Kernel;
+ *idle_percentage = 100.0 * i64Idle / i64System;
+ } else {
+ *idle_percentage = 100.0;
+ p->valid_last_times = 1;
+ }
+
+ /* Remember current value for the next call */
+ p->i64LastUserTime = i64UserTime;
+ p->i64LastKernelTime = i64KernelTime;
+ p->i64LastIdleTime = i64IdleTime;
+
+ /* Success */
+ return ZAP_SUCCESS;
+}
+#else
+/* Unsupported */
+OZ_DECLARE(zap_status_t) zap_cpu_get_system_idle_time(struct zap_cpu_monitor_stats *p, double *idle_percentage)
+{
+ return ZAP_FAIL;
+}
+#endif
+
+OZ_DECLARE(struct zap_cpu_monitor_stats*) zap_new_cpu_monitor(void)
+{
+ return calloc(1, sizeof(struct zap_cpu_monitor_stats));
+}
+
+OZ_DECLARE(void) zap_delete_cpu_monitor(struct zap_cpu_monitor_stats *p)
+{
+#ifdef __linux__
+ close(p->procfd);
+#endif
+ free(p);
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/zap_dso.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/zap_dso.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/zap_dso.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,115 @@
+/*
+ * Cross Platform dso/dll load abstraction
+ * Copyright(C) 2008 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer.
+ *
+ */
+
+#include "zap_dso.h"
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef WIN32
+#include <windows.h>
+#include <stdio.h>
+
+
+void zap_dso_destroy(zap_dso_lib_t *lib) {
+ if (lib && *lib) {
+ FreeLibrary(*lib);
+ *lib = NULL;
+ }
+}
+
+zap_dso_lib_t zap_dso_open(const char *path, char **err) {
+ HINSTANCE lib;
+
+ lib = LoadLibraryEx(path, NULL, 0);
+
+ if (!lib) {
+ LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ }
+
+ if (!lib) {
+ DWORD error = GetLastError();
+ char tmp[80];
+ sprintf(tmp, "dll open error [%ul]\n", error);
+ *err = _strdup(tmp);
+ }
+
+ return lib;
+}
+
+void* zap_dso_func_sym(zap_dso_lib_t lib, const char *sym, char **err) {
+ FARPROC func = GetProcAddress(lib, sym);
+ if (!func) {
+ DWORD error = GetLastError();
+ char tmp[80];
+ sprintf(tmp, "dll sym error [%ul]\n", error);
+ *err = _strdup(tmp);
+ }
+ return (void *)(intptr_t)func; // this should really be addr - zap_dso_func_data
+}
+
+#else
+
+/*
+** {========================================================================
+** This is an implementation of loadlib based on the dlfcn interface.
+** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
+** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least
+** as an emulation layer on top of native functions.
+** =========================================================================
+*/
+
+
+#include <dlfcn.h>
+
+void zap_dso_destroy(zap_dso_lib_t *lib) {
+ if (lib && *lib) {
+ dlclose(*lib);
+ *lib = NULL;
+ }
+}
+
+zap_dso_lib_t zap_dso_open(const char *path, char **err) {
+ void *lib = dlopen(path, RTLD_NOW | RTLD_LOCAL);
+ if (lib == NULL) {
+ *err = strdup(dlerror());
+ }
+ return lib;
+}
+
+void *zap_dso_func_sym(zap_dso_lib_t lib, const char *sym, char **err) {
+ void *func = dlsym(lib, sym);
+ if (!func) {
+ *err = strdup(dlerror());
+ }
+ return func;
+}
+#endif
+
+/* }====================================================== */
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4
+ */
Added: freeswitch/trunk/libs/openzap/src/zap_io.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/zap_io.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/zap_io.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3526 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#ifndef WIN32
+#endif
+#include "openzap.h"
+#include <stdarg.h>
+#ifdef WIN32
+#include <io.h>
+#endif
+#ifdef ZAP_PIKA_SUPPORT
+#include "zap_pika.h"
+#endif
+#include "zap_cpu_monitor.h"
+
+static int time_is_init = 0;
+
+static void time_init(void)
+{
+#ifdef WIN32
+ timeBeginPeriod(1);
+#endif
+ time_is_init = 1;
+}
+
+static void time_end(void)
+{
+#ifdef WIN32
+ timeEndPeriod(1);
+#endif
+ time_is_init = 0;
+}
+
+
+OZ_DECLARE(zap_time_t) zap_current_time_in_ms(void)
+{
+#ifdef WIN32
+ return timeGetTime();
+#else
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return ((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
+#endif
+}
+
+typedef struct {
+ uint8_t running;
+ uint8_t alarm;
+ uint32_t interval;
+ uint8_t alarm_action_flags;
+ uint8_t set_alarm_threshold;
+ uint8_t reset_alarm_threshold;
+ zap_interrupt_t *interrupt;
+} cpu_monitor_t;
+
+static struct {
+ zap_hash_t *interface_hash;
+ zap_hash_t *module_hash;
+ zap_hash_t *span_hash;
+ zap_mutex_t *mutex;
+ zap_mutex_t *span_mutex;
+ uint32_t span_index;
+ uint32_t running;
+ zap_span_t *spans;
+ cpu_monitor_t cpu_monitor;
+} globals;
+
+static uint8_t zap_cpu_monitor_disabled = 0;
+
+enum zap_enum_cpu_alarm_action_flags
+{
+ ZAP_CPU_ALARM_ACTION_WARN = (1 << 0),
+ ZAP_CPU_ALARM_ACTION_REJECT = (1 << 1)
+};
+
+/* enum lookup funcs */
+ZAP_ENUM_NAMES(TONEMAP_NAMES, TONEMAP_STRINGS)
+ZAP_STR2ENUM(zap_str2zap_tonemap, zap_tonemap2str, zap_tonemap_t, TONEMAP_NAMES, ZAP_TONEMAP_INVALID)
+
+ZAP_ENUM_NAMES(OOB_NAMES, OOB_STRINGS)
+ZAP_STR2ENUM(zap_str2zap_oob_event, zap_oob_event2str, zap_oob_event_t, OOB_NAMES, ZAP_OOB_INVALID)
+
+ZAP_ENUM_NAMES(TRUNK_TYPE_NAMES, TRUNK_STRINGS)
+ZAP_STR2ENUM(zap_str2zap_trunk_type, zap_trunk_type2str, zap_trunk_type_t, TRUNK_TYPE_NAMES, ZAP_TRUNK_NONE)
+
+ZAP_ENUM_NAMES(START_TYPE_NAMES, START_TYPE_STRINGS)
+ZAP_STR2ENUM(zap_str2zap_analog_start_type, zap_analog_start_type2str, zap_analog_start_type_t, START_TYPE_NAMES, ZAP_ANALOG_START_NA)
+
+ZAP_ENUM_NAMES(SIGNAL_NAMES, SIGNAL_STRINGS)
+ZAP_STR2ENUM(zap_str2zap_signal_event, zap_signal_event2str, zap_signal_event_t, SIGNAL_NAMES, ZAP_SIGEVENT_INVALID)
+
+ZAP_ENUM_NAMES(CHANNEL_STATE_NAMES, CHANNEL_STATE_STRINGS)
+ZAP_STR2ENUM(zap_str2zap_channel_state, zap_channel_state2str, zap_channel_state_t, CHANNEL_STATE_NAMES, ZAP_CHANNEL_STATE_INVALID)
+
+ZAP_ENUM_NAMES(MDMF_TYPE_NAMES, MDMF_STRINGS)
+ZAP_STR2ENUM(zap_str2zap_mdmf_type, zap_mdmf_type2str, zap_mdmf_type_t, MDMF_TYPE_NAMES, MDMF_INVALID)
+
+ZAP_ENUM_NAMES(CHAN_TYPE_NAMES, CHAN_TYPE_STRINGS)
+ZAP_STR2ENUM(zap_str2zap_chan_type, zap_chan_type2str, zap_chan_type_t, CHAN_TYPE_NAMES, ZAP_CHAN_TYPE_COUNT)
+
+static zap_status_t zap_cpu_monitor_start(void);
+static void zap_cpu_monitor_stop(void);
+
+static const char *cut_path(const char *in)
+{
+ const char *p, *ret = in;
+ char delims[] = "/\\";
+ char *i;
+
+ for (i = delims; *i; i++) {
+ p = in;
+ while ((p = strchr(p, *i)) != 0) {
+ ret = ++p;
+ }
+ }
+ return ret;
+}
+
+static void null_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
+{
+ if (file && func && line && level && fmt) {
+ return;
+ }
+ return;
+}
+
+
+static const char *LEVEL_NAMES[] = {
+ "EMERG",
+ "ALERT",
+ "CRIT",
+ "ERROR",
+ "WARNING",
+ "NOTICE",
+ "INFO",
+ "DEBUG",
+ NULL
+};
+
+
+static int zap_log_level = 7;
+
+/* Cpu monitor thread */
+static void *zap_cpu_monitor_run(zap_thread_t *me, void *obj);
+
+static void default_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
+{
+ const char *fp;
+ char data[1024];
+ va_list ap;
+
+ if (level < 0 || level > 7) {
+ level = 7;
+ }
+ if (level > zap_log_level) {
+ return;
+ }
+
+ fp = cut_path(file);
+
+ va_start(ap, fmt);
+
+ vsnprintf(data, sizeof(data), fmt, ap);
+
+
+ fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], file, line, func, data);
+
+ va_end(ap);
+
+}
+
+static zap_status_t zap_set_caller_data(zap_span_t *span, zap_caller_data_t *caller_data)
+{
+ if (!caller_data) {
+ zap_log(ZAP_LOG_CRIT, "Error: trying to set caller data, but no caller_data!\n");
+ return ZAP_FAIL;
+ }
+
+ if (caller_data->cid_num.plan == ZAP_NPI_INVALID) {
+ caller_data->cid_num.plan = span->default_caller_data.cid_num.plan;
+ }
+
+ if (caller_data->cid_num.type == ZAP_TON_INVALID) {
+ caller_data->cid_num.type = span->default_caller_data.cid_num.type;
+ }
+
+ if (caller_data->ani.plan == ZAP_NPI_INVALID) {
+ caller_data->ani.plan = span->default_caller_data.ani.plan;
+ }
+
+ if (caller_data->ani.type == ZAP_TON_INVALID) {
+ caller_data->ani.type = span->default_caller_data.ani.type;
+ }
+
+ if (caller_data->rdnis.plan == ZAP_NPI_INVALID) {
+ caller_data->rdnis.plan = span->default_caller_data.rdnis.plan;
+ }
+
+ if (caller_data->rdnis.type == ZAP_NPI_INVALID) {
+ caller_data->rdnis.type = span->default_caller_data.rdnis.type;
+ }
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_set_caller_data(zap_channel_t *zchan, zap_caller_data_t *caller_data)
+{
+ zap_status_t err = ZAP_SUCCESS;
+ if (!zchan) {
+ zap_log(ZAP_LOG_CRIT, "Error: trying to set caller data, but no zchan!\n");
+ return ZAP_FAIL;
+ }
+ if ((err = zap_set_caller_data(zchan->span, caller_data)) != ZAP_SUCCESS) {
+ return err;
+ }
+ zchan->caller_data = *caller_data;
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE_DATA zap_logger_t zap_log = null_logger;
+
+OZ_DECLARE(void) zap_global_set_logger(zap_logger_t logger)
+{
+ if (logger) {
+ zap_log = logger;
+ } else {
+ zap_log = null_logger;
+ }
+}
+
+OZ_DECLARE(void) zap_global_set_default_logger(int level)
+{
+ if (level < 0 || level > 7) {
+ level = 7;
+ }
+
+ zap_log = default_logger;
+ zap_log_level = level;
+}
+
+OZ_DECLARE_NONSTD(int) zap_hash_equalkeys(void *k1, void *k2)
+{
+ return strcmp((char *) k1, (char *) k2) ? 0 : 1;
+}
+
+OZ_DECLARE_NONSTD(uint32_t) zap_hash_hashfromstring(void *ky)
+{
+ unsigned char *str = (unsigned char *) ky;
+ uint32_t hash = 0;
+ int c;
+
+ while ((c = *str++)) {
+ hash = c + (hash << 6) + (hash << 16) - hash;
+ }
+
+ return hash;
+}
+
+
+static zap_status_t zap_span_destroy(zap_span_t *span)
+{
+ zap_status_t status = ZAP_FAIL;
+
+ if (zap_test_flag(span, ZAP_SPAN_CONFIGURED)) {
+ if (span->stop) {
+ span->stop(span);
+ }
+ if (span->zio && span->zio->span_destroy) {
+ zap_log(ZAP_LOG_INFO, "Destroying span %u type (%s)\n", span->span_id, span->type);
+ status = span->zio->span_destroy(span);
+ zap_safe_free(span->type);
+ zap_safe_free(span->dtmf_hangup);
+ }
+ }
+
+ return status;
+}
+
+static zap_status_t zap_channel_destroy(zap_channel_t *zchan)
+{
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_CONFIGURED)) {
+
+ while (zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
+ zap_log(ZAP_LOG_INFO, "Waiting for thread to exit on channel %u:%u\n", zchan->span_id, zchan->chan_id);
+ zap_sleep(500);
+ }
+
+ zap_mutex_lock(zchan->pre_buffer_mutex);
+ zap_buffer_destroy(&zchan->pre_buffer);
+ zap_mutex_unlock(zchan->pre_buffer_mutex);
+
+ zap_buffer_destroy(&zchan->digit_buffer);
+ zap_buffer_destroy(&zchan->gen_dtmf_buffer);
+ zap_buffer_destroy(&zchan->dtmf_buffer);
+ zap_buffer_destroy(&zchan->fsk_buffer);
+ zchan->pre_buffer_size = 0;
+
+ hashtable_destroy(zchan->variable_hash);
+
+ zap_safe_free(zchan->dtmf_hangup_buf);
+
+ if (zchan->tone_session.buffer) {
+ teletone_destroy_session(&zchan->tone_session);
+ memset(&zchan->tone_session, 0, sizeof(zchan->tone_session));
+ }
+
+
+ if (zchan->span->zio->channel_destroy) {
+ zap_log(ZAP_LOG_INFO, "Closing channel %s:%u:%u fd:%d\n", zchan->span->type, zchan->span_id, zchan->chan_id, zchan->sockfd);
+ if (zchan->span->zio->channel_destroy(zchan) == ZAP_SUCCESS) {
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_CONFIGURED);
+ } else {
+ zap_log(ZAP_LOG_ERROR, "Error Closing channel %u:%u fd:%d\n", zchan->span_id, zchan->chan_id, zchan->sockfd);
+ }
+ }
+
+ zap_mutex_destroy(&zchan->mutex);
+ zap_mutex_destroy(&zchan->pre_buffer_mutex);
+ }
+
+ return ZAP_SUCCESS;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_channel_get_alarms(zap_channel_t *zchan)
+{
+ zap_status_t status = ZAP_FAIL;
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_CONFIGURED)) {
+ if (zchan->span->zio->get_alarms) {
+ if ((status = zchan->span->zio->get_alarms(zchan)) == ZAP_SUCCESS) {
+ *zchan->last_error = '\0';
+ if (zap_test_alarm_flag(zchan, ZAP_ALARM_RED)) {
+ snprintf(zchan->last_error + strlen(zchan->last_error), sizeof(zchan->last_error) - strlen(zchan->last_error), "RED/");
+ }
+ if (zap_test_alarm_flag(zchan, ZAP_ALARM_YELLOW)) {
+ snprintf(zchan->last_error + strlen(zchan->last_error), sizeof(zchan->last_error) - strlen(zchan->last_error), "YELLOW/");
+ }
+ if (zap_test_alarm_flag(zchan, ZAP_ALARM_BLUE)) {
+ snprintf(zchan->last_error + strlen(zchan->last_error), sizeof(zchan->last_error) - strlen(zchan->last_error), "BLUE/");
+ }
+ if (zap_test_alarm_flag(zchan, ZAP_ALARM_LOOPBACK)) {
+ snprintf(zchan->last_error + strlen(zchan->last_error), sizeof(zchan->last_error) - strlen(zchan->last_error), "LOOP/");
+ }
+ if (zap_test_alarm_flag(zchan, ZAP_ALARM_RECOVER)) {
+ snprintf(zchan->last_error + strlen(zchan->last_error), sizeof(zchan->last_error) - strlen(zchan->last_error), "RECOVER/");
+ }
+ *(zchan->last_error + strlen(zchan->last_error) - 1) = '\0';
+
+ }
+ } else {
+ status = ZAP_NOTIMPL;
+ }
+ }
+
+ return status;
+}
+
+static void zap_span_add(zap_span_t *span)
+{
+ zap_span_t *sp;
+ zap_mutex_lock(globals.span_mutex);
+ for (sp = globals.spans; sp && sp->next; sp = sp->next);
+ if (sp) {
+ sp->next = span;
+ } else {
+ globals.spans = span;
+ }
+ hashtable_insert(globals.span_hash, (void *)span->name, span, HASHTABLE_FLAG_NONE);
+ zap_mutex_unlock(globals.span_mutex);
+}
+
+#if 0
+static void zap_span_del(zap_span_t *span)
+{
+ zap_span_t *last = NULL, *sp;
+
+ zap_mutex_lock(globals.span_mutex);
+ for (sp = globals.spans; sp; sp = sp->next) {
+
+ if (sp == span) {
+ if (last) {
+ last->next = sp->next;
+ } else {
+ globals.spans = sp->next;
+ }
+ hashtable_remove(globals.span_hash, (void *)sp->name);
+ break;
+ }
+
+ last = sp;
+ }
+ zap_mutex_unlock(globals.span_mutex);
+}
+#endif
+
+OZ_DECLARE(zap_status_t) zap_span_stop(zap_span_t *span)
+{
+ if (span->stop) {
+ span->stop(span);
+ return ZAP_SUCCESS;
+ }
+
+ return ZAP_FAIL;
+}
+
+OZ_DECLARE(zap_status_t) zap_span_create(zap_io_interface_t *zio, zap_span_t **span, const char *name)
+{
+ zap_span_t *new_span = NULL;
+ zap_status_t status = ZAP_FAIL;
+
+ assert(zio != NULL);
+
+ zap_mutex_lock(globals.mutex);
+
+ if (globals.span_index < ZAP_MAX_SPANS_INTERFACE) {
+ new_span = malloc(sizeof(*new_span));
+ assert(new_span);
+ memset(new_span, 0, sizeof(*new_span));
+ status = zap_mutex_create(&new_span->mutex);
+ assert(status == ZAP_SUCCESS);
+
+ zap_set_flag(new_span, ZAP_SPAN_CONFIGURED);
+ new_span->span_id = ++globals.span_index;
+ new_span->zio = zio;
+ zap_copy_string(new_span->tone_map[ZAP_TONEMAP_DIAL], "%(1000,0,350,440)", ZAP_TONEMAP_LEN);
+ zap_copy_string(new_span->tone_map[ZAP_TONEMAP_RING], "%(2000,4000,440,480)", ZAP_TONEMAP_LEN);
+ zap_copy_string(new_span->tone_map[ZAP_TONEMAP_BUSY], "%(500,500,480,620)", ZAP_TONEMAP_LEN);
+ zap_copy_string(new_span->tone_map[ZAP_TONEMAP_ATTN], "%(100,100,1400,2060,2450,2600)", ZAP_TONEMAP_LEN);
+ new_span->trunk_type = ZAP_TRUNK_NONE;
+ new_span->data_type = ZAP_TYPE_SPAN;
+
+ zap_mutex_lock(globals.span_mutex);
+ if (!zap_strlen_zero(name) && hashtable_search(globals.span_hash, (void *)name)) {
+ zap_log(ZAP_LOG_WARNING, "name %s is already used, substituting 'span%d' as the name\n", name, new_span->span_id);
+ name = NULL;
+ }
+ zap_mutex_unlock(globals.span_mutex);
+
+ if (!name) {
+ char buf[128] = "";
+ snprintf(buf, sizeof(buf), "span%d", new_span->span_id);
+ name = buf;
+ }
+ new_span->name = strdup(name);
+ zap_span_add(new_span);
+ *span = new_span;
+ status = ZAP_SUCCESS;
+ }
+ zap_mutex_unlock(globals.mutex);
+ return status;
+}
+
+OZ_DECLARE(zap_status_t) zap_span_close_all(void)
+{
+ zap_span_t *span;
+ uint32_t i = 0, j;
+
+ zap_mutex_lock(globals.span_mutex);
+ for (span = globals.spans; span; span = span->next) {
+ if (zap_test_flag(span, ZAP_SPAN_CONFIGURED)) {
+ for(j = 1; j <= span->chan_count && span->channels[j]; j++) {
+ zap_channel_destroy(span->channels[j]);
+ i++;
+ }
+ }
+ }
+ zap_mutex_unlock(globals.span_mutex);
+
+ return i ? ZAP_SUCCESS : ZAP_FAIL;
+}
+
+OZ_DECLARE(zap_status_t) zap_span_load_tones(zap_span_t *span, const char *mapname)
+{
+ zap_config_t cfg;
+ char *var, *val;
+ int x = 0;
+
+ if (!zap_config_open_file(&cfg, "tones.conf")) {
+ snprintf(span->last_error, sizeof(span->last_error), "error loading tones.");
+ return ZAP_FAIL;
+ }
+
+ while (zap_config_next_pair(&cfg, &var, &val)) {
+ int detect = 0;
+
+ if (!strcasecmp(cfg.category, mapname) && var && val) {
+ uint32_t index;
+ char *name = NULL;
+
+ if (!strncasecmp(var, "detect-", 7)) {
+ name = var + 7;
+ detect = 1;
+ } else if (!strncasecmp(var, "generate-", 9)) {
+ name = var + 9;
+ } else {
+ zap_log(ZAP_LOG_WARNING, "Unknown tone name %s\n", var);
+ continue;
+ }
+
+ index = zap_str2zap_tonemap(name);
+
+ if (index >= ZAP_TONEMAP_INVALID || index == ZAP_TONEMAP_NONE) {
+ zap_log(ZAP_LOG_WARNING, "Unknown tone name %s\n", name);
+ } else {
+ if (detect) {
+ char *p = val, *next;
+ int i = 0;
+ do {
+ teletone_process_t this;
+ next = strchr(p, ',');
+ this = (teletone_process_t)atof(p);
+ span->tone_detect_map[index].freqs[i++] = this;
+ if (next) {
+ p = next + 1;
+ }
+ } while (next);
+ zap_log(ZAP_LOG_DEBUG, "added tone detect [%s] = [%s]\n", name, val);
+ } else {
+ zap_log(ZAP_LOG_DEBUG, "added tone generation [%s] = [%s]\n", name, val);
+ zap_copy_string(span->tone_map[index], val, sizeof(span->tone_map[index]));
+ }
+ x++;
+ }
+ }
+ }
+
+ zap_config_close_file(&cfg);
+
+ if (!x) {
+ snprintf(span->last_error, sizeof(span->last_error), "error loading tones.");
+ return ZAP_FAIL;
+ }
+
+ return ZAP_SUCCESS;
+
+}
+
+#define ZAP_SLINEAR_MAX_VALUE 32767
+#define ZAP_SLINEAR_MIN_VALUE -32767
+static void reset_gain_table(unsigned char *gain_table, float new_gain, zap_codec_t codec_gain)
+{
+ /* sample value */
+ uint8_t sv = 0;
+ /* linear gain factor */
+ float lingain = 0;
+ /* linear value for each table sample */
+ float linvalue = 0;
+ /* amplified (or attenuated in case of negative amplification) sample value */
+ int ampvalue = 0;
+
+ /* gain tables are only for alaw and ulaw */
+ if (codec_gain != ZAP_CODEC_ALAW && codec_gain != ZAP_CODEC_ULAW) {
+ zap_log(ZAP_LOG_WARNING, "Not resetting gain table because codec is not ALAW or ULAW but %d\n", codec_gain);
+ return;
+ }
+
+ if (!new_gain) {
+ /* for a 0.0db gain table, each alaw/ulaw sample value is left untouched (0 ==0, 1 == 1, 2 == 2 etc)*/
+ sv = 0;
+ while (1) {
+ gain_table[sv] = (unsigned char)sv;
+ if (sv == (ZAP_GAINS_TABLE_SIZE - 1)) {
+ break;
+ }
+ sv++;
+ }
+ return;
+ }
+
+ /* use the 20log rule to increase the gain: http://en.wikipedia.org/wiki/Gain, http:/en.wikipedia.org/wiki/20_log_rule#Definitions */
+ lingain = (float)pow(10.0f, new_gain/20.0f);
+ sv = 0;
+ while (1) {
+ /* get the linear value for this alaw/ulaw sample value */
+ linvalue = codec_gain == ZAP_CODEC_ALAW ? (float)alaw_to_linear(sv) : (float)ulaw_to_linear(sv);
+
+ /* multiply the linear value and the previously calculated linear gain */
+ ampvalue = (int)(linvalue * lingain);
+
+ /* chop it if goes beyond the limits */
+ if (ampvalue > ZAP_SLINEAR_MAX_VALUE) {
+ ampvalue = ZAP_SLINEAR_MAX_VALUE;
+ }
+
+ if (ampvalue < ZAP_SLINEAR_MIN_VALUE) {
+ ampvalue = ZAP_SLINEAR_MIN_VALUE;
+ }
+ gain_table[sv] = codec_gain == ZAP_CODEC_ALAW ? linear_to_alaw(ampvalue) : linear_to_ulaw(ampvalue);
+ if (sv == (ZAP_GAINS_TABLE_SIZE-1)) {
+ break;
+ }
+ sv++;
+ }
+}
+
+OZ_DECLARE(zap_status_t) zap_span_add_channel(zap_span_t *span, zap_socket_t sockfd, zap_chan_type_t type, zap_channel_t **chan)
+{
+ unsigned i = 0;
+ if (span->chan_count < ZAP_MAX_CHANNELS_SPAN) {
+ zap_channel_t *new_chan = span->channels[++span->chan_count];
+
+ if (!new_chan) {
+ if (!(new_chan = malloc(sizeof(*new_chan)))) {
+ return ZAP_FAIL;
+ }
+ span->channels[span->chan_count] = new_chan;
+ memset(new_chan, 0, sizeof(*new_chan));
+ }
+
+ new_chan->type = type;
+ new_chan->sockfd = sockfd;
+ new_chan->zio = span->zio;
+ new_chan->span_id = span->span_id;
+ new_chan->chan_id = span->chan_count;
+ new_chan->span = span;
+ new_chan->fds[0] = -1;
+ new_chan->fds[1] = -1;
+ new_chan->data_type = ZAP_TYPE_CHANNEL;
+ if (!new_chan->dtmf_on) {
+ new_chan->dtmf_on = ZAP_DEFAULT_DTMF_ON;
+ }
+
+ if (!new_chan->dtmf_off) {
+ new_chan->dtmf_off = ZAP_DEFAULT_DTMF_OFF;
+ }
+
+ zap_mutex_create(&new_chan->mutex);
+ zap_mutex_create(&new_chan->pre_buffer_mutex);
+
+ zap_buffer_create(&new_chan->digit_buffer, 128, 128, 0);
+ zap_buffer_create(&new_chan->gen_dtmf_buffer, 128, 128, 0);
+ new_chan->variable_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys);
+
+ new_chan->dtmf_hangup_buf = calloc (span->dtmf_hangup_len + 1, sizeof (char));
+
+ /* set 0.0db gain table */
+ i = 0;
+ while (1) {
+ new_chan->txgain_table[i] = (unsigned char)i;
+ new_chan->rxgain_table[i] = (unsigned char)i;
+ if (i == (sizeof(new_chan->txgain_table)-1)) {
+ break;
+ }
+ i++;
+ }
+
+ zap_set_flag(new_chan, ZAP_CHANNEL_CONFIGURED | ZAP_CHANNEL_READY);
+ *chan = new_chan;
+ return ZAP_SUCCESS;
+ }
+
+ return ZAP_FAIL;
+}
+
+OZ_DECLARE(zap_status_t) zap_span_find_by_name(const char *name, zap_span_t **span)
+{
+ zap_status_t status = ZAP_FAIL;
+
+ zap_mutex_lock(globals.span_mutex);
+ if (!zap_strlen_zero(name)) {
+ if ((*span = hashtable_search(globals.span_hash, (void *)name))) {
+ status = ZAP_SUCCESS;
+ } else {
+ int span_id = atoi(name);
+
+ zap_span_find(span_id, span);
+ if (*span) {
+ status = ZAP_SUCCESS;
+ }
+ }
+ }
+ zap_mutex_unlock(globals.span_mutex);
+
+ return status;
+}
+
+OZ_DECLARE(zap_status_t) zap_span_find(uint32_t id, zap_span_t **span)
+{
+ zap_span_t *fspan = NULL, *sp;
+
+ if (id > ZAP_MAX_SPANS_INTERFACE) {
+ return ZAP_FAIL;
+ }
+
+ zap_mutex_lock(globals.span_mutex);
+ for (sp = globals.spans; sp; sp = sp->next) {
+ if (sp->span_id == id) {
+ fspan = sp;
+ break;
+ }
+ }
+ zap_mutex_unlock(globals.span_mutex);
+
+ if (!fspan || !zap_test_flag(fspan, ZAP_SPAN_CONFIGURED)) {
+ return ZAP_FAIL;
+ }
+
+ *span = fspan;
+
+ return ZAP_SUCCESS;
+
+}
+
+OZ_DECLARE(zap_status_t) zap_span_set_event_callback(zap_span_t *span, zio_event_cb_t event_callback)
+{
+ zap_mutex_lock(span->mutex);
+ span->event_callback = event_callback;
+ zap_mutex_unlock(span->mutex);
+ return ZAP_SUCCESS;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_span_poll_event(zap_span_t *span, uint32_t ms)
+{
+ assert(span->zio != NULL);
+
+ if (span->zio->poll_event) {
+ return span->zio->poll_event(span, ms);
+ } else {
+ zap_log(ZAP_LOG_ERROR, "poll_event method not implemented in module %s!", span->zio->name);
+ }
+
+ return ZAP_NOTIMPL;
+}
+
+OZ_DECLARE(zap_status_t) zap_span_next_event(zap_span_t *span, zap_event_t **event)
+{
+ assert(span->zio != NULL);
+
+ if (span->zio->next_event) {
+ return span->zio->next_event(span, event);
+ } else {
+ zap_log(ZAP_LOG_ERROR, "next_event method not implemented in module %s!", span->zio->name);
+ }
+
+ return ZAP_NOTIMPL;
+}
+
+static zap_status_t zchan_fsk_write_sample(int16_t *buf, zap_size_t buflen, void *user_data)
+{
+ zap_channel_t *zchan = (zap_channel_t *) user_data;
+ zap_buffer_write(zchan->fsk_buffer, buf, buflen * 2);
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_send_fsk_data(zap_channel_t *zchan, zap_fsk_data_state_t *fsk_data, float db_level)
+{
+ struct zap_fsk_modulator fsk_trans;
+
+ if (!zchan->fsk_buffer) {
+ zap_buffer_create(&zchan->fsk_buffer, 128, 128, 0);
+ } else {
+ zap_buffer_zero(zchan->fsk_buffer);
+ }
+
+ if (zchan->token_count > 1) {
+ zap_fsk_modulator_init(&fsk_trans, FSK_BELL202, zchan->rate, fsk_data, db_level, 80, 5, 0, zchan_fsk_write_sample, zchan);
+ zap_fsk_modulator_send_all((&fsk_trans));
+ } else {
+ zap_fsk_modulator_init(&fsk_trans, FSK_BELL202, zchan->rate, fsk_data, db_level, 180, 5, 300, zchan_fsk_write_sample, zchan);
+ zap_fsk_modulator_send_all((&fsk_trans));
+ zchan->buffer_delay = 3500 / zchan->effective_interval;
+ }
+
+ return ZAP_SUCCESS;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_channel_set_event_callback(zap_channel_t *zchan, zio_event_cb_t event_callback)
+{
+ zap_mutex_lock(zchan->mutex);
+ zchan->event_callback = event_callback;
+ zap_mutex_unlock(zchan->mutex);
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_clear_token(zap_channel_t *zchan, const char *token)
+{
+ zap_status_t status = ZAP_FAIL;
+
+ zap_mutex_lock(zchan->mutex);
+ if (token == NULL) {
+ memset(zchan->tokens, 0, sizeof(zchan->tokens));
+ zchan->token_count = 0;
+ } else if (*token != '\0') {
+ char tokens[ZAP_MAX_TOKENS][ZAP_TOKEN_STRLEN];
+ int32_t i, count = zchan->token_count;
+ memcpy(tokens, zchan->tokens, sizeof(tokens));
+ memset(zchan->tokens, 0, sizeof(zchan->tokens));
+ zchan->token_count = 0;
+
+ for (i = 0; i < count; i++) {
+ if (strcmp(tokens[i], token)) {
+ zap_copy_string(zchan->tokens[zchan->token_count], tokens[i], sizeof(zchan->tokens[zchan->token_count]));
+ zchan->token_count++;
+ }
+ }
+
+ status = ZAP_SUCCESS;
+ }
+ zap_mutex_unlock(zchan->mutex);
+
+ return status;
+}
+
+OZ_DECLARE(void) zap_channel_rotate_tokens(zap_channel_t *zchan)
+{
+ if (zchan->token_count) {
+ memmove(zchan->tokens[1], zchan->tokens[0], zchan->token_count * ZAP_TOKEN_STRLEN);
+ zap_copy_string(zchan->tokens[0], zchan->tokens[zchan->token_count], ZAP_TOKEN_STRLEN);
+ *zchan->tokens[zchan->token_count] = '\0';
+ }
+}
+
+OZ_DECLARE(void) zap_channel_replace_token(zap_channel_t *zchan, const char *old_token, const char *new_token)
+{
+ unsigned int i;
+
+ if (zchan->token_count) {
+ for(i = 0; i < zchan->token_count; i++) {
+ if (!strcmp(zchan->tokens[i], old_token)) {
+ zap_copy_string(zchan->tokens[i], new_token, ZAP_TOKEN_STRLEN);
+ break;
+ }
+ }
+ }
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_add_token(zap_channel_t *zchan, char *token, int end)
+{
+ zap_status_t status = ZAP_FAIL;
+
+ zap_mutex_lock(zchan->mutex);
+ if (zchan->token_count < ZAP_MAX_TOKENS) {
+ if (end) {
+ zap_copy_string(zchan->tokens[zchan->token_count++], token, ZAP_TOKEN_STRLEN);
+ } else {
+ memmove(zchan->tokens[1], zchan->tokens[0], zchan->token_count * ZAP_TOKEN_STRLEN);
+ zap_copy_string(zchan->tokens[0], token, ZAP_TOKEN_STRLEN);
+ zchan->token_count++;
+ }
+ status = ZAP_SUCCESS;
+ }
+ zap_mutex_unlock(zchan->mutex);
+
+ return status;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_channel_complete_state(zap_channel_t *zchan)
+{
+ zap_channel_state_t state = zchan->state;
+
+ if (state == ZAP_CHANNEL_STATE_PROGRESS) {
+ zap_set_flag(zchan, ZAP_CHANNEL_PROGRESS);
+ } else if (state == ZAP_CHANNEL_STATE_UP) {
+ zap_set_flag(zchan, ZAP_CHANNEL_PROGRESS);
+ zap_set_flag(zchan, ZAP_CHANNEL_MEDIA);
+ zap_set_flag(zchan, ZAP_CHANNEL_ANSWERED);
+ } else if (state == ZAP_CHANNEL_STATE_PROGRESS_MEDIA) {
+ zap_set_flag(zchan, ZAP_CHANNEL_PROGRESS);
+ zap_set_flag(zchan, ZAP_CHANNEL_MEDIA);
+ }
+
+ return ZAP_SUCCESS;
+}
+
+static int zap_parse_state_map(zap_channel_t *zchan, zap_channel_state_t state, zap_state_map_t *state_map)
+{
+ int x = 0, ok = 0;
+ zap_state_direction_t direction = zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND) ? ZSD_OUTBOUND : ZSD_INBOUND;
+
+ for(x = 0; x < ZAP_MAP_NODE_SIZE; x++) {
+ int i = 0, proceed = 0;
+ if (!state_map->nodes[x].type) {
+ break;
+ }
+
+ if (state_map->nodes[x].direction != direction) {
+ continue;
+ }
+
+ if (state_map->nodes[x].check_states[0] == ZAP_ANY_STATE) {
+ proceed = 1;
+ } else {
+ for(i = 0; i < ZAP_MAP_MAX; i++) {
+ if (state_map->nodes[x].check_states[i] == zchan->state) {
+ proceed = 1;
+ break;
+ }
+ }
+ }
+
+ if (!proceed) {
+ continue;
+ }
+
+ for(i = 0; i < ZAP_MAP_MAX; i++) {
+ ok = (state_map->nodes[x].type == ZSM_ACCEPTABLE);
+ if (state_map->nodes[x].states[i] == ZAP_END) {
+ break;
+ }
+ if (state_map->nodes[x].states[i] == state) {
+ ok = !ok;
+ goto end;
+ }
+ }
+ }
+ end:
+
+ return ok;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_set_state(zap_channel_t *zchan, zap_channel_state_t state, int lock)
+{
+ int ok = 1;
+
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_READY)) {
+ return ZAP_FAIL;
+ }
+
+ if (zap_test_flag(zchan->span, ZAP_SPAN_SUSPENDED)) {
+ if (state != ZAP_CHANNEL_STATE_RESTART && state != ZAP_CHANNEL_STATE_DOWN) {
+ return ZAP_FAIL;
+ }
+ }
+
+ if (lock) {
+ zap_mutex_lock(zchan->mutex);
+ }
+
+ if (zchan->span->state_map) {
+ ok = zap_parse_state_map(zchan, state, zchan->span->state_map);
+ goto end;
+ }
+
+ switch(zchan->state) {
+ case ZAP_CHANNEL_STATE_HANGUP:
+ case ZAP_CHANNEL_STATE_TERMINATING:
+ {
+ ok = 0;
+ switch(state) {
+ case ZAP_CHANNEL_STATE_DOWN:
+ case ZAP_CHANNEL_STATE_BUSY:
+ case ZAP_CHANNEL_STATE_RESTART:
+ ok = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_UP:
+ {
+ ok = 1;
+ switch(state) {
+ case ZAP_CHANNEL_STATE_PROGRESS:
+ case ZAP_CHANNEL_STATE_PROGRESS_MEDIA:
+ case ZAP_CHANNEL_STATE_RING:
+ ok = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_DOWN:
+ {
+ ok = 0;
+
+ switch(state) {
+ case ZAP_CHANNEL_STATE_DIALTONE:
+ case ZAP_CHANNEL_STATE_COLLECT:
+ case ZAP_CHANNEL_STATE_DIALING:
+ case ZAP_CHANNEL_STATE_RING:
+ case ZAP_CHANNEL_STATE_PROGRESS_MEDIA:
+ case ZAP_CHANNEL_STATE_PROGRESS:
+ case ZAP_CHANNEL_STATE_GET_CALLERID:
+ case ZAP_CHANNEL_STATE_GENRING:
+ ok = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_BUSY:
+ {
+ switch(state) {
+ case ZAP_CHANNEL_STATE_UP:
+ ok = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_RING:
+ {
+ switch(state) {
+ case ZAP_CHANNEL_STATE_UP:
+ ok = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ end:
+
+ if (state == zchan->state) {
+ ok = 0;
+ }
+
+
+ if (ok) {
+ zap_set_flag(zchan, ZAP_CHANNEL_STATE_CHANGE);
+ zap_set_flag_locked(zchan->span, ZAP_SPAN_STATE_CHANGE);
+ zchan->last_state = zchan->state;
+ zchan->state = state;
+ }
+
+ if (lock) {
+ zap_mutex_unlock(zchan->mutex);
+ }
+
+ return ok ? ZAP_SUCCESS : ZAP_FAIL;
+}
+
+OZ_DECLARE(zap_status_t) zap_span_channel_use_count(zap_span_t *span, uint32_t *count)
+{
+ uint32_t j;
+
+ *count = 0;
+
+ if (!span || !zap_test_flag(span, ZAP_SPAN_CONFIGURED)) {
+ return ZAP_FAIL;
+ }
+
+ for(j = 1; j <= span->chan_count && span->channels[j]; j++) {
+ if (span->channels[j]) {
+ if (zap_test_flag(span->channels[j], ZAP_CHANNEL_INUSE)) {
+ (*count)++;
+ }
+ }
+ }
+
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_open_any(uint32_t span_id, zap_direction_t direction, zap_caller_data_t *caller_data, zap_channel_t **zchan)
+{
+ zap_status_t status = ZAP_FAIL;
+ zap_channel_t *check;
+ uint32_t i, j, count;
+ zap_span_t *span = NULL;
+ uint32_t span_max;
+
+ if (span_id) {
+ zap_span_find(span_id, &span);
+
+ if (!span || !zap_test_flag(span, ZAP_SPAN_CONFIGURED)) {
+ zap_log(ZAP_LOG_CRIT, "SPAN NOT DEFINED!\n");
+ *zchan = NULL;
+ return ZAP_FAIL;
+ }
+
+ zap_span_channel_use_count(span, &count);
+
+ if (count >= span->chan_count) {
+ zap_log(ZAP_LOG_CRIT, "All circuits are busy.\n");
+ *zchan = NULL;
+ return ZAP_FAIL;
+ }
+
+ if (span->channel_request && !span->suggest_chan_id) {
+ zap_set_caller_data(span, caller_data);
+ return span->channel_request(span, 0, direction, caller_data, zchan);
+ }
+
+ span_max = span_id;
+ j = span_id;
+ } else {
+ zap_log(ZAP_LOG_CRIT, "No span supplied\n");
+ *zchan = NULL;
+ return ZAP_FAIL;
+ }
+
+ zap_mutex_lock(span->mutex);
+
+ if (direction == ZAP_TOP_DOWN) {
+ i = 1;
+ } else {
+ i = span->chan_count;
+ }
+
+ for(;;) {
+
+ if (direction == ZAP_TOP_DOWN) {
+ if (i > span->chan_count) {
+ break;
+ }
+ } else {
+ if (i == 0) {
+ break;
+ }
+ }
+
+ if (!(check = span->channels[i])) {
+ status = ZAP_FAIL;
+ break;
+ }
+
+ if (zap_test_flag(check, ZAP_CHANNEL_READY) &&
+ !zap_test_flag(check, ZAP_CHANNEL_INUSE) &&
+ !zap_test_flag(check, ZAP_CHANNEL_SUSPENDED) &&
+ check->state == ZAP_CHANNEL_STATE_DOWN &&
+ check->type != ZAP_CHAN_TYPE_DQ921 &&
+ check->type != ZAP_CHAN_TYPE_DQ931
+
+ ) {
+
+ if (span && span->channel_request) {
+ zap_set_caller_data(span, caller_data);
+ status = span->channel_request(span, i, direction, caller_data, zchan);
+ break;
+ }
+
+ status = check->zio->open(check);
+
+ if (status == ZAP_SUCCESS) {
+ zap_set_flag(check, ZAP_CHANNEL_INUSE);
+ zap_channel_open_chan(check);
+ *zchan = check;
+ break;
+ }
+ }
+
+ if (direction == ZAP_TOP_DOWN) {
+ i++;
+ } else {
+ i--;
+ }
+ }
+
+ zap_mutex_unlock(span->mutex);
+
+ return status;
+}
+
+static zap_status_t zap_channel_reset(zap_channel_t *zchan)
+{
+ zap_clear_flag(zchan, ZAP_CHANNEL_OPEN);
+ zchan->event_callback = NULL;
+ zap_clear_flag(zchan, ZAP_CHANNEL_DTMF_DETECT);
+ zap_clear_flag(zchan, ZAP_CHANNEL_SUPRESS_DTMF);
+ zap_channel_done(zchan);
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_HOLD);
+
+ memset(zchan->tokens, 0, sizeof(zchan->tokens));
+ zchan->token_count = 0;
+
+ if (zchan->dtmf_buffer) {
+ zap_buffer_zero(zchan->dtmf_buffer);
+ }
+
+ if (zchan->gen_dtmf_buffer) {
+ zap_buffer_zero(zchan->gen_dtmf_buffer);
+ }
+
+ if (zchan->digit_buffer) {
+ zap_buffer_zero(zchan->digit_buffer);
+ }
+
+ if (!zchan->dtmf_on) {
+ zchan->dtmf_on = ZAP_DEFAULT_DTMF_ON;
+ }
+
+ if (!zchan->dtmf_off) {
+ zchan->dtmf_off = ZAP_DEFAULT_DTMF_OFF;
+ }
+
+ memset(zchan->dtmf_hangup_buf, '\0', zchan->span->dtmf_hangup_len);
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_TRANSCODE)) {
+ zchan->effective_codec = zchan->native_codec;
+ zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8);
+ zap_clear_flag(zchan, ZAP_CHANNEL_TRANSCODE);
+ }
+
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_init(zap_channel_t *zchan)
+{
+
+ if (zchan->init_state != ZAP_CHANNEL_STATE_DOWN) {
+ zap_set_state_locked(zchan, zchan->init_state);
+ zchan->init_state = ZAP_CHANNEL_STATE_DOWN;
+ }
+
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_open_chan(zap_channel_t *zchan)
+{
+ zap_status_t status = ZAP_FAIL;
+
+ assert(zchan != NULL);
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_SUSPENDED)) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", "Channel is suspended");
+ return ZAP_FAIL;
+ }
+ if (globals.cpu_monitor.alarm &&
+ globals.cpu_monitor.alarm_action_flags & ZAP_CPU_ALARM_ACTION_REJECT) {
+
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", "CPU usage alarm is on - refusing to open channel\n");
+ zap_log(ZAP_LOG_WARNING, "CPU usage alarm is on - refusing to open channel\n");
+ zchan->caller_data.hangup_cause = ZAP_CAUSE_SWITCH_CONGESTION;
+ return ZAP_FAIL;
+ }
+
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_READY) || (status = zap_mutex_trylock(zchan->mutex)) != ZAP_SUCCESS) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "Channel is not ready or is in use %d %d", zap_test_flag(zchan, ZAP_CHANNEL_READY), status);
+ return status;
+ }
+
+ status = ZAP_FAIL;
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_READY)) {
+ status = zchan->span->zio->open(zchan);
+ if (status == ZAP_SUCCESS) {
+ zap_set_flag(zchan, ZAP_CHANNEL_OPEN | ZAP_CHANNEL_INUSE);
+ }
+ } else {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", "Channel is not ready");
+ }
+
+ zap_mutex_unlock(zchan->mutex);
+ return status;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_open(uint32_t span_id, uint32_t chan_id, zap_channel_t **zchan)
+{
+ zap_channel_t *check;
+ zap_status_t status = ZAP_FAIL;
+ zap_span_t *span = NULL;
+
+ zap_mutex_unlock(globals.mutex);
+ zap_span_find(span_id, &span);
+
+ if (!span || !zap_test_flag(span, ZAP_SPAN_CONFIGURED) || chan_id >= ZAP_MAX_CHANNELS_SPAN) {
+ zap_log(ZAP_LOG_CRIT, "SPAN NOT DEFINED!\n");
+ *zchan = NULL;
+ goto done;
+ }
+
+ if (span->channel_request) {
+ zap_log(ZAP_LOG_ERROR, "Individual channel selection not implemented on this span.\n");
+ *zchan = NULL;
+ goto done;
+ }
+
+ if (!(check = span->channels[chan_id])) {
+ zap_log(ZAP_LOG_ERROR, "Invalid Channel %d\n", chan_id);
+ *zchan = NULL;
+ goto done;
+ }
+
+ if (zap_test_flag(check, ZAP_CHANNEL_SUSPENDED) ||
+ !zap_test_flag(check, ZAP_CHANNEL_READY) || (status = zap_mutex_trylock(check->mutex)) != ZAP_SUCCESS) {
+ *zchan = NULL;
+ goto done;
+ }
+
+ status = ZAP_FAIL;
+
+ if (zap_test_flag(check, ZAP_CHANNEL_READY) && (!zap_test_flag(check, ZAP_CHANNEL_INUSE) ||
+ (check->type == ZAP_CHAN_TYPE_FXS && check->token_count == 1))) {
+ if (!zap_test_flag(check, ZAP_CHANNEL_OPEN)) {
+ status = check->zio->open(check);
+ if (status == ZAP_SUCCESS) {
+ zap_set_flag(check, ZAP_CHANNEL_OPEN);
+ }
+ } else {
+ status = ZAP_SUCCESS;
+ }
+ zap_set_flag(check, ZAP_CHANNEL_INUSE);
+ *zchan = check;
+ }
+ zap_mutex_unlock(check->mutex);
+
+ done:
+ zap_mutex_unlock(globals.mutex);
+
+ return status;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_outgoing_call(zap_channel_t *zchan)
+{
+ zap_status_t status;
+
+ assert(zchan != NULL);
+
+ if (zchan->span->outgoing_call) {
+ if ((status = zchan->span->outgoing_call(zchan)) == ZAP_SUCCESS) {
+ zap_set_flag(zchan, ZAP_CHANNEL_OUTBOUND);
+ }
+ return status;
+ } else {
+ zap_log(ZAP_LOG_ERROR, "outgoing_call method not implemented!\n");
+ }
+
+ return ZAP_FAIL;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_done(zap_channel_t *zchan)
+{
+ assert(zchan != NULL);
+
+ memset(&zchan->caller_data, 0, sizeof(zchan->caller_data));
+
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_INUSE);
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_OUTBOUND);
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_WINK);
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_FLASH);
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_STATE_CHANGE);
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_HOLD);
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_RINGING);
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_PROGRESS_DETECT);
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_CALLERID_DETECT);
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_3WAY);
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_PROGRESS);
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_MEDIA);
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_ANSWERED);
+ zap_mutex_lock(zchan->pre_buffer_mutex);
+ zap_buffer_destroy(&zchan->pre_buffer);
+ zchan->pre_buffer_size = 0;
+ zap_mutex_unlock(zchan->pre_buffer_mutex);
+
+ zap_channel_flush_dtmf(zchan);
+
+ zchan->init_state = ZAP_CHANNEL_STATE_DOWN;
+ zchan->state = ZAP_CHANNEL_STATE_DOWN;
+ zap_log(ZAP_LOG_DEBUG, "channel done %u:%u\n", zchan->span_id, zchan->chan_id);
+
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_use(zap_channel_t *zchan)
+{
+
+ assert(zchan != NULL);
+
+ zap_set_flag_locked(zchan, ZAP_CHANNEL_INUSE);
+
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_close(zap_channel_t **zchan)
+{
+ zap_channel_t *check;
+ zap_status_t status = ZAP_FAIL;
+
+ assert(zchan != NULL);
+ check = *zchan;
+ *zchan = NULL;
+
+ if (!check) {
+ return ZAP_FAIL;
+ }
+
+ if (zap_test_flag(check, ZAP_CHANNEL_CONFIGURED)) {
+ zap_mutex_lock(check->mutex);
+ if (zap_test_flag(check, ZAP_CHANNEL_OPEN)) {
+ status = check->zio->close(check);
+ if (status == ZAP_SUCCESS) {
+ zap_channel_reset(check);
+ *zchan = NULL;
+ }
+ }
+ check->ring_count = 0;
+ zap_mutex_unlock(check->mutex);
+ }
+
+ return status;
+}
+
+
+static zap_status_t zchan_activate_dtmf_buffer(zap_channel_t *zchan)
+{
+
+ if (!zchan->dtmf_buffer) {
+ if (zap_buffer_create(&zchan->dtmf_buffer, 1024, 3192, 0) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Failed to allocate DTMF Buffer!\n");
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "buffer error");
+ return ZAP_FAIL;
+ } else {
+ zap_log(ZAP_LOG_DEBUG, "Created DTMF Buffer!\n");
+ }
+ }
+
+
+ if (!zchan->tone_session.buffer) {
+ memset(&zchan->tone_session, 0, sizeof(zchan->tone_session));
+ teletone_init_session(&zchan->tone_session, 0, NULL, NULL);
+ }
+
+ zchan->tone_session.rate = zchan->rate;
+ zchan->tone_session.duration = zchan->dtmf_on * (zchan->tone_session.rate / 1000);
+ zchan->tone_session.wait = zchan->dtmf_off * (zchan->tone_session.rate / 1000);
+ zchan->tone_session.volume = -7;
+
+ /*
+ zchan->tone_session.debug = 1;
+ zchan->tone_session.debug_stream = stdout;
+ */
+
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_command(zap_channel_t *zchan, zap_command_t command, void *obj)
+{
+ zap_status_t status = ZAP_FAIL;
+
+ assert(zchan != NULL);
+ assert(zchan->zio != NULL);
+
+ zap_mutex_lock(zchan->mutex);
+
+ switch(command) {
+
+ case ZAP_COMMAND_ENABLE_CALLERID_DETECT:
+ {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_CALLERID)) {
+ if (zap_fsk_demod_init(&zchan->fsk, zchan->rate, zchan->fsk_buf, sizeof(zchan->fsk_buf)) != ZAP_SUCCESS) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
+ GOTO_STATUS(done, ZAP_FAIL);
+ }
+ zap_set_flag_locked(zchan, ZAP_CHANNEL_CALLERID_DETECT);
+ }
+ }
+ break;
+ case ZAP_COMMAND_DISABLE_CALLERID_DETECT:
+ {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_CALLERID)) {
+ zap_fsk_demod_destroy(&zchan->fsk);
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_CALLERID_DETECT);
+ }
+ }
+ break;
+ case ZAP_COMMAND_TRACE_INPUT:
+ {
+ char *path = (char *) obj;
+ if (zchan->fds[0] > 0) {
+ close(zchan->fds[0]);
+ zchan->fds[0] = -1;
+ }
+ if ((zchan->fds[0] = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) {
+ zap_log(ZAP_LOG_DEBUG, "Tracing channel %u:%u to [%s]\n", zchan->span_id, zchan->chan_id, path);
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
+ GOTO_STATUS(done, ZAP_FAIL);
+ }
+ break;
+ case ZAP_COMMAND_TRACE_OUTPUT:
+ {
+ char *path = (char *) obj;
+ if (zchan->fds[1] > 0) {
+ close(zchan->fds[1]);
+ zchan->fds[1] = -1;
+ }
+ if ((zchan->fds[1] = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) {
+ zap_log(ZAP_LOG_DEBUG, "Tracing channel %u:%u to [%s]\n", zchan->span_id, zchan->chan_id, path);
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
+ GOTO_STATUS(done, ZAP_FAIL);
+ }
+ break;
+ case ZAP_COMMAND_SET_INTERVAL:
+ {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_INTERVAL)) {
+ zchan->effective_interval = ZAP_COMMAND_OBJ_INT;
+ if (zchan->effective_interval == zchan->native_interval) {
+ zap_clear_flag(zchan, ZAP_CHANNEL_BUFFER);
+ } else {
+ zap_set_flag(zchan, ZAP_CHANNEL_BUFFER);
+ }
+ zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8);
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ }
+ break;
+ case ZAP_COMMAND_GET_INTERVAL:
+ {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_INTERVAL)) {
+ ZAP_COMMAND_OBJ_INT = zchan->effective_interval;
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ }
+ break;
+ case ZAP_COMMAND_SET_CODEC:
+ {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_CODECS)) {
+ zchan->effective_codec = ZAP_COMMAND_OBJ_INT;
+
+ if (zchan->effective_codec == zchan->native_codec) {
+ zap_clear_flag(zchan, ZAP_CHANNEL_TRANSCODE);
+ } else {
+ zap_set_flag(zchan, ZAP_CHANNEL_TRANSCODE);
+ }
+ zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8);
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ }
+ break;
+
+ case ZAP_COMMAND_SET_NATIVE_CODEC:
+ {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_CODECS)) {
+ zchan->effective_codec = zchan->native_codec;
+ zap_clear_flag(zchan, ZAP_CHANNEL_TRANSCODE);
+ zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8);
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ }
+ break;
+
+ case ZAP_COMMAND_GET_CODEC:
+ {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_CODECS)) {
+ ZAP_COMMAND_OBJ_INT = zchan->effective_codec;
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ }
+ break;
+ case ZAP_COMMAND_GET_NATIVE_CODEC:
+ {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_CODECS)) {
+ ZAP_COMMAND_OBJ_INT = zchan->native_codec;
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ }
+ break;
+ case ZAP_COMMAND_ENABLE_PROGRESS_DETECT:
+ {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_PROGRESS)) {
+ /* if they don't have thier own, use ours */
+ zap_channel_clear_detected_tones(zchan);
+ zap_channel_clear_needed_tones(zchan);
+ teletone_multi_tone_init(&zchan->span->tone_finder[ZAP_TONEMAP_DIAL], &zchan->span->tone_detect_map[ZAP_TONEMAP_DIAL]);
+ teletone_multi_tone_init(&zchan->span->tone_finder[ZAP_TONEMAP_RING], &zchan->span->tone_detect_map[ZAP_TONEMAP_RING]);
+ teletone_multi_tone_init(&zchan->span->tone_finder[ZAP_TONEMAP_BUSY], &zchan->span->tone_detect_map[ZAP_TONEMAP_BUSY]);
+ zap_set_flag(zchan, ZAP_CHANNEL_PROGRESS_DETECT);
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ }
+ break;
+ case ZAP_COMMAND_DISABLE_PROGRESS_DETECT:
+ {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_PROGRESS)) {
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_PROGRESS_DETECT);
+ zap_channel_clear_detected_tones(zchan);
+ zap_channel_clear_needed_tones(zchan);
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ }
+ break;
+ case ZAP_COMMAND_ENABLE_DTMF_DETECT:
+ {
+ /* if they don't have thier own, use ours */
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_DETECT)) {
+ zap_tone_type_t tt = ZAP_COMMAND_OBJ_INT;
+ if (tt == ZAP_TONE_DTMF) {
+ teletone_dtmf_detect_init (&zchan->dtmf_detect, zchan->rate);
+ zap_set_flag_locked(zchan, ZAP_CHANNEL_DTMF_DETECT);
+ zap_set_flag_locked(zchan, ZAP_CHANNEL_SUPRESS_DTMF);
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ } else {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid command");
+ GOTO_STATUS(done, ZAP_FAIL);
+ }
+ }
+ }
+ break;
+ case ZAP_COMMAND_DISABLE_DTMF_DETECT:
+ {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_DETECT)) {
+ zap_tone_type_t tt = ZAP_COMMAND_OBJ_INT;
+ if (tt == ZAP_TONE_DTMF) {
+ teletone_dtmf_detect_init (&zchan->dtmf_detect, zchan->rate);
+ zap_clear_flag(zchan, ZAP_CHANNEL_DTMF_DETECT);
+ zap_clear_flag(zchan, ZAP_CHANNEL_SUPRESS_DTMF);
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ } else {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid command");
+ GOTO_STATUS(done, ZAP_FAIL);
+ }
+ }
+ }
+
+ case ZAP_COMMAND_SET_PRE_BUFFER_SIZE:
+ {
+ int val = ZAP_COMMAND_OBJ_INT;
+
+ if (val < 0) {
+ val = 0;
+ }
+
+ zchan->pre_buffer_size = val * 8;
+
+ zap_mutex_lock(zchan->pre_buffer_mutex);
+ if (!zchan->pre_buffer_size) {
+ zap_buffer_destroy(&zchan->pre_buffer);
+ } else if (!zchan->pre_buffer) {
+ zap_buffer_create(&zchan->pre_buffer, 1024, zchan->pre_buffer_size, 0);
+ }
+ zap_mutex_unlock(zchan->pre_buffer_mutex);
+
+ GOTO_STATUS(done, ZAP_SUCCESS);
+
+ }
+ break;
+ case ZAP_COMMAND_GET_DTMF_ON_PERIOD:
+ {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
+ ZAP_COMMAND_OBJ_INT = zchan->dtmf_on;
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ }
+ break;
+ case ZAP_COMMAND_GET_DTMF_OFF_PERIOD:
+ {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
+ ZAP_COMMAND_OBJ_INT = zchan->dtmf_on;
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ }
+ break;
+ case ZAP_COMMAND_SET_DTMF_ON_PERIOD:
+ {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
+ int val = ZAP_COMMAND_OBJ_INT;
+ if (val > 10 && val < 1000) {
+ zchan->dtmf_on = val;
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ } else {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid value %d range 10-1000", val);
+ GOTO_STATUS(done, ZAP_FAIL);
+ }
+ }
+ }
+ break;
+ case ZAP_COMMAND_SET_DTMF_OFF_PERIOD:
+ {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
+ int val = ZAP_COMMAND_OBJ_INT;
+ if (val > 10 && val < 1000) {
+ zchan->dtmf_off = val;
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ } else {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid value %d range 10-1000", val);
+ GOTO_STATUS(done, ZAP_FAIL);
+ }
+ }
+ }
+ break;
+ case ZAP_COMMAND_SEND_DTMF:
+ {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
+ char *digits = ZAP_COMMAND_OBJ_CHAR_P;
+
+ if ((status = zchan_activate_dtmf_buffer(zchan)) != ZAP_SUCCESS) {
+ GOTO_STATUS(done, status);
+ }
+
+ zap_buffer_write(zchan->gen_dtmf_buffer, digits, strlen(digits));
+
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ }
+ break;
+
+ case ZAP_COMMAND_DISABLE_ECHOCANCEL:
+ {
+ zap_mutex_lock(zchan->pre_buffer_mutex);
+ zap_buffer_destroy(&zchan->pre_buffer);
+ zchan->pre_buffer_size = 0;
+ zap_mutex_unlock(zchan->pre_buffer_mutex);
+ }
+ break;
+
+ case ZAP_COMMAND_SET_RX_GAIN:
+ {
+ zchan->rxgain = ZAP_COMMAND_OBJ_FLOAT;
+ reset_gain_table(zchan->rxgain_table, zchan->rxgain, zchan->native_codec);
+ if (zchan->rxgain == 0.0) {
+ zap_clear_flag(zchan, ZAP_CHANNEL_USE_RX_GAIN);
+ } else {
+ zap_set_flag(zchan, ZAP_CHANNEL_USE_RX_GAIN);
+ }
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ break;
+ case ZAP_COMMAND_GET_RX_GAIN:
+ {
+ ZAP_COMMAND_OBJ_FLOAT = zchan->rxgain;
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ break;
+ case ZAP_COMMAND_SET_TX_GAIN:
+ {
+ zchan->txgain = ZAP_COMMAND_OBJ_FLOAT;
+ reset_gain_table(zchan->txgain_table, zchan->txgain, zchan->native_codec);
+ if (zchan->txgain == 0.0) {
+ zap_clear_flag(zchan, ZAP_CHANNEL_USE_TX_GAIN);
+ } else {
+ zap_set_flag(zchan, ZAP_CHANNEL_USE_TX_GAIN);
+ }
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ break;
+ case ZAP_COMMAND_GET_TX_GAIN:
+ {
+ ZAP_COMMAND_OBJ_FLOAT = zchan->txgain;
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!zchan->zio->command) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "method not implemented");
+ zap_log(ZAP_LOG_ERROR, "no command function defined by the I/O openzap module!\n");
+ GOTO_STATUS(done, ZAP_FAIL);
+ }
+
+ status = zchan->zio->command(zchan, command, obj);
+
+ if (status == ZAP_NOTIMPL) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "I/O command %d not implemented in backend", command);
+ zap_log(ZAP_LOG_ERROR, "I/O backend does not support command %d!\n", command);
+ }
+done:
+ zap_mutex_unlock(zchan->mutex);
+ return status;
+
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_wait(zap_channel_t *zchan, zap_wait_flag_t *flags, int32_t to)
+{
+ assert(zchan != NULL);
+ assert(zchan->zio != NULL);
+
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "channel not open");
+ return ZAP_FAIL;
+ }
+
+ if (!zchan->zio->wait) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "method not implemented");
+ return ZAP_FAIL;
+ }
+
+ return zchan->zio->wait(zchan, flags, to);
+
+}
+
+/*******************************/
+ZIO_CODEC_FUNCTION(zio_slin2ulaw)
+{
+ int16_t sln_buf[512] = {0}, *sln = sln_buf;
+ uint8_t *lp = data;
+ uint32_t i;
+ zap_size_t len = *datalen;
+
+ if (max > len) {
+ max = len;
+ }
+
+ memcpy(sln, data, max);
+
+ for(i = 0; i < max; i++) {
+ *lp++ = linear_to_ulaw(*sln++);
+ }
+
+ *datalen = max / 2;
+
+ return ZAP_SUCCESS;
+
+}
+
+
+ZIO_CODEC_FUNCTION(zio_ulaw2slin)
+{
+ int16_t *sln = data;
+ uint8_t law[1024] = {0}, *lp = law;
+ uint32_t i;
+ zap_size_t len = *datalen;
+
+ if (max > len) {
+ max = len;
+ }
+
+ memcpy(law, data, max);
+
+ for(i = 0; i < max; i++) {
+ *sln++ = ulaw_to_linear(*lp++);
+ }
+
+ *datalen = max * 2;
+
+ return ZAP_SUCCESS;
+}
+
+ZIO_CODEC_FUNCTION(zio_slin2alaw)
+{
+ int16_t sln_buf[512] = {0}, *sln = sln_buf;
+ uint8_t *lp = data;
+ uint32_t i;
+ zap_size_t len = *datalen;
+
+ if (max > len) {
+ max = len;
+ }
+
+ memcpy(sln, data, max);
+
+ for(i = 0; i < max; i++) {
+ *lp++ = linear_to_alaw(*sln++);
+ }
+
+ *datalen = max / 2;
+
+ return ZAP_SUCCESS;
+
+}
+
+
+ZIO_CODEC_FUNCTION(zio_alaw2slin)
+{
+ int16_t *sln = data;
+ uint8_t law[1024] = {0}, *lp = law;
+ uint32_t i;
+ zap_size_t len = *datalen;
+
+ if (max > len) {
+ max = len;
+ }
+
+ memcpy(law, data, max);
+
+ for(i = 0; i < max; i++) {
+ *sln++ = alaw_to_linear(*lp++);
+ }
+
+ *datalen = max * 2;
+
+ return ZAP_SUCCESS;
+}
+
+ZIO_CODEC_FUNCTION(zio_ulaw2alaw)
+{
+ zap_size_t len = *datalen;
+ uint32_t i;
+ uint8_t *lp = data;
+
+ if (max > len) {
+ max = len;
+ }
+
+ for(i = 0; i < max; i++) {
+ *lp = ulaw_to_alaw(*lp);
+ lp++;
+ }
+
+ return ZAP_SUCCESS;
+}
+
+ZIO_CODEC_FUNCTION(zio_alaw2ulaw)
+{
+ zap_size_t len = *datalen;
+ uint32_t i;
+ uint8_t *lp = data;
+
+ if (max > len) {
+ max = len;
+ }
+
+ for(i = 0; i < max; i++) {
+ *lp = alaw_to_ulaw(*lp);
+ lp++;
+ }
+
+ return ZAP_SUCCESS;
+}
+
+/******************************/
+
+OZ_DECLARE(void) zap_channel_clear_detected_tones(zap_channel_t *zchan)
+{
+ uint32_t i;
+
+ memset(zchan->detected_tones, 0, sizeof(zchan->detected_tones[0]) * ZAP_TONEMAP_INVALID);
+
+ for (i = 1; i < ZAP_TONEMAP_INVALID; i++) {
+ zchan->span->tone_finder[i].tone_count = 0;
+ }
+}
+
+OZ_DECLARE(void) zap_channel_clear_needed_tones(zap_channel_t *zchan)
+{
+ memset(zchan->needed_tones, 0, sizeof(zchan->needed_tones[0]) * ZAP_TONEMAP_INVALID);
+}
+
+OZ_DECLARE(zap_size_t) zap_channel_dequeue_dtmf(zap_channel_t *zchan, char *dtmf, zap_size_t len)
+{
+ zap_size_t bytes = 0;
+
+ assert(zchan != NULL);
+
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_READY)) {
+ return ZAP_FAIL;
+ }
+
+ if (zchan->digit_buffer && zap_buffer_inuse(zchan->digit_buffer)) {
+ zap_mutex_lock(zchan->mutex);
+ if ((bytes = zap_buffer_read(zchan->digit_buffer, dtmf, len)) > 0) {
+ *(dtmf + bytes) = '\0';
+ }
+ zap_mutex_unlock(zchan->mutex);
+ }
+
+ return bytes;
+}
+
+OZ_DECLARE(void) zap_channel_flush_dtmf(zap_channel_t *zchan)
+{
+ if (zchan->digit_buffer && zap_buffer_inuse(zchan->digit_buffer)) {
+ zap_mutex_lock(zchan->mutex);
+ zap_buffer_zero(zchan->digit_buffer);
+ zap_mutex_unlock(zchan->mutex);
+ }
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_queue_dtmf(zap_channel_t *zchan, const char *dtmf)
+{
+ zap_status_t status;
+ register zap_size_t len, inuse;
+ zap_size_t wr = 0;
+ const char *p;
+
+ assert(zchan != NULL);
+
+ if (zchan->pre_buffer) {
+ zap_buffer_zero(zchan->pre_buffer);
+ }
+
+ zap_mutex_lock(zchan->mutex);
+
+ inuse = zap_buffer_inuse(zchan->digit_buffer);
+ len = strlen(dtmf);
+
+ if (len + inuse > zap_buffer_len(zchan->digit_buffer)) {
+ zap_buffer_toss(zchan->digit_buffer, strlen(dtmf));
+ }
+
+ if (zchan->span->dtmf_hangup_len) {
+ for (p = dtmf; zap_is_dtmf(*p); p++) {
+ memmove (zchan->dtmf_hangup_buf, zchan->dtmf_hangup_buf + 1, zchan->span->dtmf_hangup_len - 1);
+ zchan->dtmf_hangup_buf[zchan->span->dtmf_hangup_len - 1] = *p;
+ if (!strcmp(zchan->dtmf_hangup_buf, zchan->span->dtmf_hangup)) {
+ zap_log(ZAP_LOG_DEBUG, "DTMF hangup detected.\n");
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ break;
+ }
+ }
+ }
+
+ p = dtmf;
+ while (wr < len && p) {
+ if (zap_is_dtmf(*p)) {
+ wr++;
+ } else {
+ break;
+ }
+ p++;
+ }
+
+ status = zap_buffer_write(zchan->digit_buffer, dtmf, wr) ? ZAP_SUCCESS : ZAP_FAIL;
+ zap_mutex_unlock(zchan->mutex);
+
+ return status;
+}
+
+
+static zap_status_t handle_dtmf(zap_channel_t *zchan, zap_size_t datalen)
+{
+ zap_buffer_t *buffer = NULL;
+ zap_size_t dblen = 0;
+ int wrote = 0;
+
+ if (zchan->gen_dtmf_buffer && (dblen = zap_buffer_inuse(zchan->gen_dtmf_buffer))) {
+ char digits[128] = "";
+ char *cur;
+ int x = 0;
+
+ if (dblen > sizeof(digits) - 1) {
+ dblen = sizeof(digits) - 1;
+ }
+
+ if (zap_buffer_read(zchan->gen_dtmf_buffer, digits, dblen) && !zap_strlen_zero_buf(digits)) {
+ zap_log(ZAP_LOG_DEBUG, "%d:%d GENERATE DTMF [%s]\n", zchan->span_id, zchan->chan_id, digits);
+
+ cur = digits;
+
+ if (*cur == 'F') {
+ zap_channel_command(zchan, ZAP_COMMAND_FLASH, NULL);
+ cur++;
+ }
+
+ for (; *cur; cur++) {
+ if ((wrote = teletone_mux_tones(&zchan->tone_session, &zchan->tone_session.TONES[(int)*cur]))) {
+ zap_buffer_write(zchan->dtmf_buffer, zchan->tone_session.buffer, wrote * 2);
+ x++;
+ } else {
+ zap_log(ZAP_LOG_ERROR, "%d:%d Problem Adding DTMF SEQ [%s]\n", zchan->span_id, zchan->chan_id, digits);
+ return ZAP_FAIL;
+ }
+ }
+
+ if (x) {
+ zchan->skip_read_frames = (wrote / (zchan->effective_interval * 8)) + 4;
+ }
+ }
+ }
+
+
+ if (!zchan->buffer_delay || --zchan->buffer_delay == 0) {
+ if (zchan->dtmf_buffer && (dblen = zap_buffer_inuse(zchan->dtmf_buffer))) {
+ buffer = zchan->dtmf_buffer;
+ } else if (zchan->fsk_buffer && (dblen = zap_buffer_inuse(zchan->fsk_buffer))) {
+ buffer = zchan->fsk_buffer;
+ }
+ }
+
+ if (buffer) {
+ zap_size_t dlen = datalen;
+ uint8_t auxbuf[1024];
+ zap_size_t len, br, max = sizeof(auxbuf);
+
+ if (zchan->native_codec != ZAP_CODEC_SLIN) {
+ dlen *= 2;
+ }
+
+ len = dblen > dlen ? dlen : dblen;
+
+ br = zap_buffer_read(buffer, auxbuf, len);
+ if (br < dlen) {
+ memset(auxbuf + br, 0, dlen - br);
+ }
+
+ if (zchan->native_codec != ZAP_CODEC_SLIN) {
+ if (zchan->native_codec == ZAP_CODEC_ULAW) {
+ zio_slin2ulaw(auxbuf, max, &dlen);
+ } else if (zchan->native_codec == ZAP_CODEC_ALAW) {
+ zio_slin2alaw(auxbuf, max, &dlen);
+ }
+ }
+
+ return zchan->zio->write(zchan, auxbuf, &dlen);
+ }
+
+ return ZAP_SUCCESS;
+
+}
+
+
+OZ_DECLARE(void) zap_generate_sln_silence(int16_t *data, uint32_t samples, uint32_t divisor)
+{
+ int16_t x;
+ uint32_t i;
+ int sum_rnd = 0;
+ int16_t rnd2 = (int16_t) zap_current_time_in_ms() * (int16_t) (intptr_t) data;
+
+ assert(divisor);
+
+ for (i = 0; i < samples; i++, sum_rnd = 0) {
+ for (x = 0; x < 6; x++) {
+ rnd2 = rnd2 * 31821U + 13849U;
+ sum_rnd += rnd2 ;
+ }
+ //switch_normalize_to_16bit(sum_rnd);
+ *data = (int16_t) ((int16_t) sum_rnd / (int) divisor);
+
+ data++;
+ }
+}
+
+
+
+OZ_DECLARE(zap_status_t) zap_channel_read(zap_channel_t *zchan, void *data, zap_size_t *datalen)
+{
+ zap_status_t status = ZAP_FAIL;
+ zio_codec_t codec_func = NULL;
+ zap_size_t max = *datalen;
+ unsigned i = 0;
+
+ assert(zchan != NULL);
+ assert(zchan->zio != NULL);
+
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "channel not open");
+ return ZAP_FAIL;
+ }
+
+ if (!zchan->zio->read) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "method not implemented");
+ return ZAP_FAIL;
+ }
+
+ status = zchan->zio->read(zchan, data, datalen);
+ if (zchan->fds[0] > -1) {
+ int dlen = (int) *datalen;
+ if (write(zchan->fds[0], data, dlen) != dlen) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "file write error!");
+ return ZAP_FAIL;
+ }
+ }
+
+ if (status == ZAP_SUCCESS) {
+ if (zap_test_flag(zchan, ZAP_CHANNEL_USE_RX_GAIN)
+ && (zchan->native_codec == ZAP_CODEC_ALAW || zchan->native_codec == ZAP_CODEC_ULAW)) {
+ unsigned char *rdata = data;
+ for (i = 0; i < *datalen; i++) {
+ rdata[i] = zchan->rxgain_table[rdata[i]];
+ }
+ }
+ handle_dtmf(zchan, *datalen);
+ }
+
+ if (status == ZAP_SUCCESS && zap_test_flag(zchan, ZAP_CHANNEL_TRANSCODE) && zchan->effective_codec != zchan->native_codec) {
+ if (zchan->native_codec == ZAP_CODEC_ULAW && zchan->effective_codec == ZAP_CODEC_SLIN) {
+ codec_func = zio_ulaw2slin;
+ } else if (zchan->native_codec == ZAP_CODEC_ULAW && zchan->effective_codec == ZAP_CODEC_ALAW) {
+ codec_func = zio_ulaw2alaw;
+ } else if (zchan->native_codec == ZAP_CODEC_ALAW && zchan->effective_codec == ZAP_CODEC_SLIN) {
+ codec_func = zio_alaw2slin;
+ } else if (zchan->native_codec == ZAP_CODEC_ALAW && zchan->effective_codec == ZAP_CODEC_ULAW) {
+ codec_func = zio_alaw2ulaw;
+ }
+
+ if (codec_func) {
+ status = codec_func(data, max, datalen);
+ } else {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "codec error!");
+ status = ZAP_FAIL;
+ }
+ }
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_DTMF_DETECT) || zap_test_flag(zchan, ZAP_CHANNEL_PROGRESS_DETECT) ||
+ zap_test_flag(zchan, ZAP_CHANNEL_CALLERID_DETECT)) {
+ uint8_t sln_buf[1024] = {0};
+ int16_t *sln;
+ zap_size_t slen = 0;
+ char digit_str[80] = "";
+
+ if (zchan->effective_codec == ZAP_CODEC_SLIN) {
+ sln = data;
+ slen = *datalen / 2;
+ } else {
+ zap_size_t len = *datalen;
+ uint32_t i;
+ uint8_t *lp = data;
+
+ slen = sizeof(sln_buf) / 2;
+ if (len > slen) {
+ len = slen;
+ }
+
+ sln = (int16_t *) sln_buf;
+ for(i = 0; i < len; i++) {
+ if (zchan->effective_codec == ZAP_CODEC_ULAW) {
+ *sln++ = ulaw_to_linear(*lp++);
+ } else if (zchan->effective_codec == ZAP_CODEC_ALAW) {
+ *sln++ = alaw_to_linear(*lp++);
+ } else {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "codec error!");
+ return ZAP_FAIL;
+ }
+ }
+ sln = (int16_t *) sln_buf;
+ slen = len;
+ }
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_CALLERID_DETECT)) {
+ if (zap_fsk_demod_feed(&zchan->fsk, sln, slen) != ZAP_SUCCESS) {
+ zap_size_t type, mlen;
+ char str[128], *sp;
+
+ while(zap_fsk_data_parse(&zchan->fsk, &type, &sp, &mlen) == ZAP_SUCCESS) {
+ *(str+mlen) = '\0';
+ zap_copy_string(str, sp, ++mlen);
+ zap_clean_string(str);
+ zap_log(ZAP_LOG_DEBUG, "FSK: TYPE %s LEN %d VAL [%s]\n", zap_mdmf_type2str(type), mlen-1, str);
+
+ switch(type) {
+ case MDMF_DDN:
+ case MDMF_PHONE_NUM:
+ {
+ if (mlen > sizeof(zchan->caller_data.ani)) {
+ mlen = sizeof(zchan->caller_data.ani);
+ }
+ zap_set_string(zchan->caller_data.ani.digits, str);
+ zap_set_string(zchan->caller_data.cid_num.digits, zchan->caller_data.ani.digits);
+ }
+ break;
+ case MDMF_NO_NUM:
+ {
+ zap_set_string(zchan->caller_data.ani.digits, *str == 'P' ? "private" : "unknown");
+ zap_set_string(zchan->caller_data.cid_name, zchan->caller_data.ani.digits);
+ }
+ break;
+ case MDMF_PHONE_NAME:
+ {
+ if (mlen > sizeof(zchan->caller_data.cid_name)) {
+ mlen = sizeof(zchan->caller_data.cid_name);
+ }
+ zap_set_string(zchan->caller_data.cid_name, str);
+ }
+ break;
+ case MDMF_NO_NAME:
+ {
+ zap_set_string(zchan->caller_data.cid_name, *str == 'P' ? "private" : "unknown");
+ }
+ case MDMF_DATETIME:
+ {
+ if (mlen > sizeof(zchan->caller_data.cid_date)) {
+ mlen = sizeof(zchan->caller_data.cid_date);
+ }
+ zap_set_string(zchan->caller_data.cid_date, str);
+ }
+ break;
+ }
+ }
+ zap_channel_command(zchan, ZAP_COMMAND_DISABLE_CALLERID_DETECT, NULL);
+ }
+ }
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_PROGRESS_DETECT) && !zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_PROGRESS)) {
+ uint32_t i;
+
+ for (i = 1; i < ZAP_TONEMAP_INVALID; i++) {
+ if (zchan->span->tone_finder[i].tone_count) {
+ if (zchan->needed_tones[i] && teletone_multi_tone_detect(&zchan->span->tone_finder[i], sln, (int)slen)) {
+ if (++zchan->detected_tones[i]) {
+ zchan->needed_tones[i] = 0;
+ zchan->detected_tones[0]++;
+ }
+ }
+ }
+ }
+ }
+
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_DTMF_DETECT) && !zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_DETECT)) {
+ teletone_dtmf_detect(&zchan->dtmf_detect, sln, (int)slen);
+ teletone_dtmf_get(&zchan->dtmf_detect, digit_str, sizeof(digit_str));
+
+ if(*digit_str) {
+ zio_event_cb_t event_callback = NULL;
+
+ if (zchan->state == ZAP_CHANNEL_STATE_CALLWAITING && (*digit_str == 'D' || *digit_str == 'A')) {
+ zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]++;
+ } else {
+ zap_channel_queue_dtmf(zchan, digit_str);
+
+ if (zchan->span->event_callback) {
+ event_callback = zchan->span->event_callback;
+ } else if (zchan->event_callback) {
+ event_callback = zchan->event_callback;
+ }
+
+ if (event_callback) {
+ zchan->event_header.channel = zchan;
+ zchan->event_header.e_type = ZAP_EVENT_DTMF;
+ zchan->event_header.data = digit_str;
+ event_callback(zchan, &zchan->event_header);
+ zchan->event_header.e_type = ZAP_EVENT_NONE;
+ zchan->event_header.data = NULL;
+ }
+ if (zap_test_flag(zchan, ZAP_CHANNEL_SUPRESS_DTMF)) {
+ zchan->skip_read_frames = 20;
+ }
+ }
+ }
+ }
+ }
+
+ if (zchan->skip_read_frames > 0 || zap_test_flag(zchan, ZAP_CHANNEL_MUTE)) {
+
+ zap_mutex_lock(zchan->pre_buffer_mutex);
+ if (zchan->pre_buffer && zap_buffer_inuse(zchan->pre_buffer)) {
+ zap_buffer_zero(zchan->pre_buffer);
+ }
+ zap_mutex_unlock(zchan->pre_buffer_mutex);
+
+
+ memset(data, 255, *datalen);
+
+ if (zchan->skip_read_frames > 0) {
+ zchan->skip_read_frames--;
+ }
+ } else {
+ zap_mutex_lock(zchan->pre_buffer_mutex);
+ if (zchan->pre_buffer_size && zchan->pre_buffer) {
+ zap_buffer_write(zchan->pre_buffer, data, *datalen);
+ if (zap_buffer_inuse(zchan->pre_buffer) >= zchan->pre_buffer_size) {
+ zap_buffer_read(zchan->pre_buffer, data, *datalen);
+ } else {
+ memset(data, 255, *datalen);
+ }
+ }
+ zap_mutex_unlock(zchan->pre_buffer_mutex);
+ }
+
+
+ return status;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_channel_write(zap_channel_t *zchan, void *data, zap_size_t datasize, zap_size_t *datalen)
+{
+ zap_status_t status = ZAP_FAIL;
+ zio_codec_t codec_func = NULL;
+ zap_size_t max = datasize;
+ unsigned i = 0;
+
+ assert(zchan != NULL);
+ assert(zchan->zio != NULL);
+
+ if (!zchan->buffer_delay &&
+ ((zchan->dtmf_buffer && zap_buffer_inuse(zchan->dtmf_buffer)) ||
+ (zchan->fsk_buffer && zap_buffer_inuse(zchan->fsk_buffer)))) {
+ /* read size writing DTMF ATM */
+ return ZAP_SUCCESS;
+ }
+
+
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "channel not open");
+ return ZAP_FAIL;
+ }
+
+ if (!zchan->zio->write) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "method not implemented");
+ return ZAP_FAIL;
+ }
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_TRANSCODE) && zchan->effective_codec != zchan->native_codec) {
+ if (zchan->native_codec == ZAP_CODEC_ULAW && zchan->effective_codec == ZAP_CODEC_SLIN) {
+ codec_func = zio_slin2ulaw;
+ } else if (zchan->native_codec == ZAP_CODEC_ULAW && zchan->effective_codec == ZAP_CODEC_ALAW) {
+ codec_func = zio_alaw2ulaw;
+ } else if (zchan->native_codec == ZAP_CODEC_ALAW && zchan->effective_codec == ZAP_CODEC_SLIN) {
+ codec_func = zio_slin2alaw;
+ } else if (zchan->native_codec == ZAP_CODEC_ALAW && zchan->effective_codec == ZAP_CODEC_ULAW) {
+ codec_func = zio_ulaw2alaw;
+ }
+
+ if (codec_func) {
+ status = codec_func(data, max, datalen);
+ } else {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "codec error!");
+ status = ZAP_FAIL;
+ }
+ }
+
+ if (zchan->fds[1] > -1) {
+ int dlen = (int) *datalen;
+ if ((write(zchan->fds[1], data, dlen)) != dlen) {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "file write error!");
+ return ZAP_FAIL;
+ }
+ }
+
+ if (zap_test_flag(zchan, ZAP_CHANNEL_USE_TX_GAIN)
+ && (zchan->native_codec == ZAP_CODEC_ALAW || zchan->native_codec == ZAP_CODEC_ULAW)) {
+ unsigned char *wdata = data;
+ for (i = 0; i < *datalen; i++) {
+ wdata[i] = zchan->txgain_table[wdata[i]];
+ }
+ }
+ status = zchan->zio->write(zchan, data, datalen);
+
+ return status;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_clear_vars(zap_channel_t *zchan)
+{
+ if(zchan->variable_hash) {
+ hashtable_destroy(zchan->variable_hash);
+ }
+ zchan->variable_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys);
+
+ if(!zchan->variable_hash)
+ return ZAP_FAIL;
+
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_add_var(zap_channel_t *zchan, const char *var_name, const char *value)
+{
+ char *t_name = 0, *t_val = 0;
+
+ if(!zchan->variable_hash || !var_name || !value)
+ {
+ return ZAP_FAIL;
+ }
+
+ t_name = strdup(var_name);
+ t_val = strdup(value);
+
+ if(hashtable_insert(zchan->variable_hash, t_name, t_val, HASHTABLE_FLAG_FREE_KEY | HASHTABLE_FLAG_FREE_VALUE)) {
+ return ZAP_SUCCESS;
+ }
+ return ZAP_FAIL;
+}
+
+OZ_DECLARE(const char *) zap_channel_get_var(zap_channel_t *zchan, const char *var_name)
+{
+ if(!zchan->variable_hash || !var_name)
+ {
+ return NULL;
+ }
+ return (const char *) hashtable_search(zchan->variable_hash, (void *)var_name);
+}
+
+static struct {
+ zap_io_interface_t *pika_interface;
+} interfaces;
+
+
+OZ_DECLARE(char *) zap_api_execute(const char *type, const char *cmd)
+{
+ zap_io_interface_t *zio = NULL;
+ char *dup = NULL, *p;
+ char *rval = NULL;
+
+ if (type && !cmd) {
+ dup = strdup(type);
+ if ((p = strchr(dup, ' '))) {
+ *p++ = '\0';
+ cmd = p;
+ }
+
+ type = dup;
+ }
+
+ zap_mutex_lock(globals.mutex);
+ if (!(zio = (zap_io_interface_t *) hashtable_search(globals.interface_hash, (void *)type))) {
+ zap_load_module_assume(type);
+ if ((zio = (zap_io_interface_t *) hashtable_search(globals.interface_hash, (void *)type))) {
+ zap_log(ZAP_LOG_INFO, "auto-loaded '%s'\n", type);
+ }
+ }
+ zap_mutex_unlock(globals.mutex);
+
+ if (zio && zio->api) {
+ zap_stream_handle_t stream = { 0 };
+ zap_status_t status;
+ ZAP_STANDARD_STREAM(stream);
+ status = zio->api(&stream, cmd);
+
+ if (status != ZAP_SUCCESS) {
+ zap_safe_free(stream.data);
+ } else {
+ rval = (char *) stream.data;
+ }
+ }
+
+ zap_safe_free(dup);
+
+ return rval;
+}
+
+static void zap_set_channels_gains(zap_span_t *span, int currindex, float rxgain, float txgain)
+{
+ unsigned chan_index = 0;
+
+ if (!span->chan_count) {
+ return;
+ }
+
+ for (chan_index = currindex+1; chan_index <= span->chan_count; chan_index++) {
+ if (!ZAP_IS_VOICE_CHANNEL(span->channels[chan_index])) {
+ continue;
+ }
+ zap_channel_command(span->channels[chan_index], ZAP_COMMAND_SET_RX_GAIN, &rxgain);
+ zap_channel_command(span->channels[chan_index], ZAP_COMMAND_SET_TX_GAIN, &txgain);
+ }
+}
+
+static zap_status_t load_config(void)
+{
+ char cfg_name[] = "openzap.conf";
+ zap_config_t cfg;
+ char *var, *val;
+ int catno = -1;
+ zap_span_t *span = NULL;
+ unsigned configured = 0, d = 0;
+ char name[80] = "";
+ char number[25] = "";
+ zap_io_interface_t *zio = NULL;
+ zap_analog_start_type_t tmp;
+ float rxgain = 0.0;
+ float txgain = 0.0;
+ int chanindex = 0;
+
+ if (!zap_config_open_file(&cfg, cfg_name)) {
+ return ZAP_FAIL;
+ }
+
+ while (zap_config_next_pair(&cfg, &var, &val)) {
+ if (*cfg.category == '#') {
+ if (cfg.catno != catno) {
+ zap_log(ZAP_LOG_DEBUG, "Skipping %s\n", cfg.category);
+ catno = cfg.catno;
+ }
+ } else if (!strncasecmp(cfg.category, "span", 4)) {
+ if (cfg.catno != catno) {
+ char *type = cfg.category + 4;
+ char *name;
+
+ if (*type == ' ') {
+ type++;
+ }
+
+ zap_log(ZAP_LOG_DEBUG, "found config for span\n");
+ catno = cfg.catno;
+
+ if (zap_strlen_zero(type)) {
+ zap_log(ZAP_LOG_CRIT, "failure creating span, no type specified.\n");
+ span = NULL;
+ continue;
+ }
+
+ if ((name = strchr(type, ' '))) {
+ *name++ = '\0';
+ }
+
+ zap_mutex_lock(globals.mutex);
+ if (!(zio = (zap_io_interface_t *) hashtable_search(globals.interface_hash, type))) {
+ zap_load_module_assume(type);
+ if ((zio = (zap_io_interface_t *) hashtable_search(globals.interface_hash, type))) {
+ zap_log(ZAP_LOG_INFO, "auto-loaded '%s'\n", type);
+ }
+ }
+ zap_mutex_unlock(globals.mutex);
+
+ if (!zio) {
+ zap_log(ZAP_LOG_CRIT, "failure creating span, no such type '%s'\n", type);
+ span = NULL;
+ continue;
+ }
+
+ if (!zio->configure_span) {
+ zap_log(ZAP_LOG_CRIT, "failure creating span, no configure_span method for '%s'\n", type);
+ span = NULL;
+ continue;
+ }
+
+ if (zap_span_create(zio, &span, name) == ZAP_SUCCESS) {
+ span->type = strdup(type);
+ d = 0;
+
+ zap_log(ZAP_LOG_DEBUG, "created span %d (%s) of type %s\n", span->span_id, span->name, type);
+
+ } else {
+ zap_log(ZAP_LOG_CRIT, "failure creating span of type %s\n", type);
+ span = NULL;
+ continue;
+ }
+ }
+
+ if (!span) {
+ continue;
+ }
+
+ zap_log(ZAP_LOG_DEBUG, "span %d [%s]=[%s]\n", span->span_id, var, val);
+
+ if (!strcasecmp(var, "trunk_type")) {
+ span->trunk_type = zap_str2zap_trunk_type(val);
+ zap_log(ZAP_LOG_DEBUG, "setting trunk type to '%s'\n", zap_trunk_type2str(span->trunk_type));
+ } else if (!strcasecmp(var, "name")) {
+ if (!strcasecmp(val, "undef")) {
+ *name = '\0';
+ } else {
+ zap_copy_string(name, val, sizeof(name));
+ }
+ } else if (!strcasecmp(var, "number")) {
+ if (!strcasecmp(val, "undef")) {
+ *number = '\0';
+ } else {
+ zap_copy_string(number, val, sizeof(number));
+ }
+ } else if (!strcasecmp(var, "analog-start-type")) {
+ if (span->trunk_type == ZAP_TRUNK_FXS || span->trunk_type == ZAP_TRUNK_FXO || span->trunk_type == ZAP_TRUNK_EM) {
+ if ((tmp = zap_str2zap_analog_start_type(val)) != ZAP_ANALOG_START_NA) {
+ span->start_type = tmp;
+ zap_log(ZAP_LOG_DEBUG, "changing start type to '%s'\n", zap_analog_start_type2str(span->start_type));
+ }
+ } else {
+ zap_log(ZAP_LOG_ERROR, "This option is only valid on analog trunks!\n");
+ }
+ } else if (!strcasecmp(var, "fxo-channel")) {
+ if (span->trunk_type == ZAP_TRUNK_NONE) {
+ span->trunk_type = ZAP_TRUNK_FXO;
+ zap_log(ZAP_LOG_DEBUG, "setting trunk type to '%s' start(%s)\n", zap_trunk_type2str(span->trunk_type),
+ zap_analog_start_type2str(span->start_type));
+ }
+ if (span->trunk_type == ZAP_TRUNK_FXO) {
+ chanindex = span->chan_count;
+ configured += zio->configure_span(span, val, ZAP_CHAN_TYPE_FXO, name, number);
+ zap_set_channels_gains(span, chanindex, rxgain, txgain);
+ } else {
+ zap_log(ZAP_LOG_WARNING, "Cannot add FXO channels to an FXS trunk!\n");
+ }
+ } else if (!strcasecmp(var, "fxs-channel")) {
+ if (span->trunk_type == ZAP_TRUNK_NONE) {
+ span->trunk_type = ZAP_TRUNK_FXS;
+ zap_log(ZAP_LOG_DEBUG, "setting trunk type to '%s' start(%s)\n", zap_trunk_type2str(span->trunk_type),
+ zap_analog_start_type2str(span->start_type));
+ }
+ if (span->trunk_type == ZAP_TRUNK_FXS) {
+ chanindex = span->chan_count;
+ configured += zio->configure_span(span, val, ZAP_CHAN_TYPE_FXS, name, number);
+ zap_set_channels_gains(span, chanindex, rxgain, txgain);
+ } else {
+ zap_log(ZAP_LOG_WARNING, "Cannot add FXS channels to an FXO trunk!\n");
+ }
+ } else if (!strcasecmp(var, "em-channel")) {
+ if (span->trunk_type == ZAP_TRUNK_NONE) {
+ span->trunk_type = ZAP_TRUNK_EM;
+ zap_log(ZAP_LOG_DEBUG, "setting trunk type to '%s' start(%s)\n", zap_trunk_type2str(span->trunk_type),
+ zap_analog_start_type2str(span->start_type));
+ }
+ if (span->trunk_type == ZAP_TRUNK_EM) {
+ chanindex = span->chan_count;
+ configured += zio->configure_span(span, val, ZAP_CHAN_TYPE_EM, name, number);
+ zap_set_channels_gains(span, chanindex, rxgain, txgain);
+ } else {
+ zap_log(ZAP_LOG_WARNING, "Cannot add EM channels to a non-EM trunk!\n");
+ }
+ } else if (!strcasecmp(var, "b-channel")) {
+ chanindex = span->chan_count;
+ configured += zio->configure_span(span, val, ZAP_CHAN_TYPE_B, name, number);
+ zap_set_channels_gains(span, chanindex, rxgain, txgain);
+ } else if (!strcasecmp(var, "d-channel")) {
+ if (d) {
+ zap_log(ZAP_LOG_WARNING, "ignoring extra d-channel\n");
+ } else {
+ zap_chan_type_t qtype;
+ if (!strncasecmp(val, "lapd:", 5)) {
+ qtype = ZAP_CHAN_TYPE_DQ931;
+ val += 5;
+ } else {
+ qtype = ZAP_CHAN_TYPE_DQ921;
+ }
+ configured += zio->configure_span(span, val, qtype, name, number);
+ d++;
+ }
+ } else if (!strcasecmp(var, "cas-channel")) {
+ chanindex = span->chan_count;
+ configured += zio->configure_span(span, val, ZAP_CHAN_TYPE_CAS, name, number);
+ zap_set_channels_gains(span, chanindex, rxgain, txgain);
+ } else if (!strcasecmp(var, "dtmf_hangup")) {
+ span->dtmf_hangup = strdup(val);
+ span->dtmf_hangup_len = strlen(val);
+ } else if (!strcasecmp(var, "txgain")) {
+ if (sscanf(val, "%f", &txgain) != 1) {
+ zap_log(ZAP_LOG_ERROR, "invalid txgain: '%s'\n", val);
+ }
+ } else if (!strcasecmp(var, "rxgain")) {
+ if (sscanf(val, "%f", &rxgain) != 1) {
+ zap_log(ZAP_LOG_ERROR, "invalid rxgain: '%s'\n", val);
+ }
+ } else {
+ zap_log(ZAP_LOG_ERROR, "unknown span variable '%s'\n", var);
+ }
+ } else if (!strncasecmp(cfg.category, "general", 7)) {
+ if (!strncasecmp(var, "cpu_monitoring_interval", 24)) {
+ if (atoi(val) > 0) {
+ globals.cpu_monitor.interval = atoi(val);
+ } else {
+ zap_log(ZAP_LOG_ERROR, "Invalid cpu monitoring interval %s\n", val);
+ }
+ } else if (!strncasecmp(var, "cpu_set_alarm_threshold", 22)) {
+ if (atoi(val) > 0 && atoi(val) < 100) {
+ globals.cpu_monitor.set_alarm_threshold = (uint8_t)atoi(val);
+ } else {
+ zap_log(ZAP_LOG_ERROR, "Invalid cpu alarm set threshold %s\n", val);
+ }
+ } else if (!strncasecmp(var, "cpu_reset_alarm_threshold", 22)) {
+ if (atoi(val) > 0 && atoi(val) < 100) {
+ globals.cpu_monitor.reset_alarm_threshold = (uint8_t)atoi(val);
+ 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;
+ zap_log(ZAP_LOG_ERROR, "Cpu alarm reset threshold must be lower than set threshold, set threshold to %d\n", globals.cpu_monitor.reset_alarm_threshold);
+ }
+ } else {
+ zap_log(ZAP_LOG_ERROR, "Invalid cpu alarm reset threshold %s\n", val);
+ }
+ } else if (!strncasecmp(var, "cpu_alarm_action", 16)) {
+ char* p = val;
+ do {
+ if (!strncasecmp(p, "reject", 6)) {
+ globals.cpu_monitor.alarm_action_flags |= ZAP_CPU_ALARM_ACTION_REJECT;
+ } else if (!strncasecmp(p, "warn", 4)) {
+ globals.cpu_monitor.alarm_action_flags |= ZAP_CPU_ALARM_ACTION_WARN;
+ }
+ p = strchr(p, ',');
+ if (p) {
+ while(++p) if (*p != 0x20) break;
+ }
+ } while (p);
+ }
+ } else {
+ zap_log(ZAP_LOG_ERROR, "unknown param [%s] '%s' / '%s'\n", cfg.category, var, val);
+ }
+ }
+ zap_config_close_file(&cfg);
+
+ zap_log(ZAP_LOG_INFO, "Configured %u channel(s)\n", configured);
+ return configured ? ZAP_SUCCESS : ZAP_FAIL;
+}
+
+static zap_status_t process_module_config(zap_io_interface_t *zio)
+{
+ zap_config_t cfg;
+ char *var, *val;
+ char filename[256] = "";
+ assert(zio != NULL);
+
+ snprintf(filename, sizeof(filename), "%s.conf", zio->name);
+
+ if (!zio->configure) {
+ zap_log(ZAP_LOG_DEBUG, "Module %s does not support configuration.\n", zio->name);
+ return ZAP_FAIL;
+ }
+
+ if (!zap_config_open_file(&cfg, filename)) {
+ zap_log(ZAP_LOG_ERROR, "Cannot open %s\n", filename);
+ return ZAP_FAIL;
+ }
+
+ while (zap_config_next_pair(&cfg, &var, &val)) {
+ zio->configure(cfg.category, var, val, cfg.lineno);
+ }
+
+ zap_config_close_file(&cfg);
+
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(int) zap_load_module(const char *name)
+{
+ zap_dso_lib_t lib;
+ int count = 0, x = 0;
+ char path[128] = "";
+ char *err;
+ zap_module_t *mod;
+
+#ifdef WIN32
+ const char *ext = ".dll";
+ //const char *EXT = ".DLL";
+#define ZAP_MOD_DIR "." //todo
+#elif defined (MACOSX) || defined (DARWIN)
+ const char *ext = ".dylib";
+ //const char *EXT = ".DYLIB";
+#else
+ const char *ext = ".so";
+ //const char *EXT = ".SO";
+#endif
+
+ if (*name == *ZAP_PATH_SEPARATOR) {
+ snprintf(path, sizeof(path), "%s%s", name, ext);
+ } else {
+ snprintf(path, sizeof(path), "%s%s%s%s", ZAP_MOD_DIR, ZAP_PATH_SEPARATOR, name, ext);
+ }
+
+ if (!(lib = zap_dso_open(path, &err))) {
+ zap_log(ZAP_LOG_ERROR, "Error loading %s [%s]\n", path, err);
+ zap_safe_free(err);
+ return 0;
+ }
+
+ if (!(mod = (zap_module_t *) zap_dso_func_sym(lib, "zap_module", &err))) {
+ zap_log(ZAP_LOG_ERROR, "Error loading %s [%s]\n", path, err);
+ zap_safe_free(err);
+ return 0;
+ }
+
+ if (mod->io_load) {
+ zap_io_interface_t *interface1 = NULL; /* name conflict w/windows here */
+
+ if (mod->io_load(&interface1) != ZAP_SUCCESS || !interface1 || !interface1->name) {
+ zap_log(ZAP_LOG_ERROR, "Error loading %s\n", path);
+ } else {
+ zap_log(ZAP_LOG_INFO, "Loading IO from %s [%s]\n", path, interface1->name);
+ zap_mutex_lock(globals.mutex);
+ if (hashtable_search(globals.interface_hash, (void *)interface1->name)) {
+ zap_log(ZAP_LOG_ERROR, "Interface %s already loaded!\n", interface1->name);
+ } else {
+ hashtable_insert(globals.interface_hash, (void *)interface1->name, interface1, HASHTABLE_FLAG_NONE);
+ process_module_config(interface1);
+ x++;
+ }
+ zap_mutex_unlock(globals.mutex);
+ }
+ }
+
+ if (mod->sig_load) {
+ if (mod->sig_load() != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error loading %s\n", path);
+ } else {
+ zap_log(ZAP_LOG_INFO, "Loading SIG from %s\n", path);
+ x++;
+ }
+ }
+
+ if (x) {
+ char *p;
+ mod->lib = lib;
+ zap_set_string(mod->path, path);
+ if (mod->name[0] == '\0') {
+ if (!(p = strrchr(path, *ZAP_PATH_SEPARATOR))) {
+ p = path;
+ }
+ zap_set_string(mod->name, p);
+ }
+
+ zap_mutex_lock(globals.mutex);
+ if (hashtable_search(globals.module_hash, (void *)mod->name)) {
+ zap_log(ZAP_LOG_ERROR, "Module %s already loaded!\n", mod->name);
+ zap_dso_destroy(&lib);
+ } else {
+ hashtable_insert(globals.module_hash, (void *)mod->name, mod, HASHTABLE_FLAG_NONE);
+ count++;
+ }
+ zap_mutex_unlock(globals.mutex);
+ } else {
+ zap_log(ZAP_LOG_ERROR, "Unloading %s\n", path);
+ zap_dso_destroy(&lib);
+ }
+
+ return count;
+}
+
+OZ_DECLARE(int) zap_load_module_assume(const char *name)
+{
+ char buf[256] = "";
+
+ snprintf(buf, sizeof(buf), "ozmod_%s", name);
+ return zap_load_module(buf);
+}
+
+OZ_DECLARE(int) zap_load_modules(void)
+{
+ char cfg_name[] = "modules.conf";
+ zap_config_t cfg;
+ char *var, *val;
+ int count = 0;
+
+ if (!zap_config_open_file(&cfg, cfg_name)) {
+ return ZAP_FAIL;
+ }
+
+ while (zap_config_next_pair(&cfg, &var, &val)) {
+ if (!strcasecmp(cfg.category, "modules")) {
+ if (!strcasecmp(var, "load")) {
+ count += zap_load_module(val);
+ }
+ }
+ }
+
+ return count;
+}
+
+OZ_DECLARE(zap_status_t) zap_unload_modules(void)
+{
+ zap_hash_iterator_t *i;
+ zap_dso_lib_t lib;
+
+ for (i = hashtable_first(globals.module_hash); i; i = hashtable_next(i)) {
+ const void *key;
+ void *val;
+
+ hashtable_this(i, &key, NULL, &val);
+
+ if (key && val) {
+ zap_module_t *mod = (zap_module_t *) val;
+
+ if (!mod) {
+ continue;
+ }
+
+ if (mod->io_unload) {
+ if (mod->io_unload() == ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_INFO, "Unloading IO %s\n", mod->name);
+ } else {
+ zap_log(ZAP_LOG_ERROR, "Error unloading IO %s\n", mod->name);
+ }
+ }
+
+ if (mod->sig_unload) {
+ if (mod->sig_unload() == ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_INFO, "Unloading SIG %s\n", mod->name);
+ } else {
+ zap_log(ZAP_LOG_ERROR, "Error unloading SIG %s\n", mod->name);
+ }
+ }
+
+
+ zap_log(ZAP_LOG_INFO, "Unloading %s\n", mod->path);
+ lib = mod->lib;
+ zap_dso_destroy(&lib);
+
+ }
+ }
+
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_configure_span(const char *type, zap_span_t *span, zio_signal_cb_t sig_cb, ...)
+{
+ zap_module_t *mod = (zap_module_t *) hashtable_search(globals.module_hash, (void *)type);
+ zap_status_t status = ZAP_FAIL;
+
+ if (!mod) {
+ zap_load_module_assume(type);
+ if ((mod = (zap_module_t *) hashtable_search(globals.module_hash, (void *)type))) {
+ zap_log(ZAP_LOG_INFO, "auto-loaded '%s'\n", type);
+ }
+ }
+
+ if (mod && mod->sig_configure) {
+ va_list ap;
+ va_start(ap, sig_cb);
+ status = mod->sig_configure(span, sig_cb, ap);
+ va_end(ap);
+ } else {
+ zap_log(ZAP_LOG_ERROR, "can't find '%s'\n", type);
+ status = ZAP_FAIL;
+ }
+
+ return status;
+}
+
+OZ_DECLARE(zap_status_t) zap_span_start(zap_span_t *span)
+{
+ if (span->start) {
+ return span->start(span);
+ }
+
+ return ZAP_FAIL;
+}
+
+OZ_DECLARE(zap_status_t) zap_span_send_signal(zap_span_t *span, zap_sigmsg_t *sigmsg)
+{
+ zap_status_t status = ZAP_FAIL;
+
+ if (span->signal_cb) {
+
+ if (sigmsg->channel) {
+ zap_mutex_lock(sigmsg->channel->mutex);
+ }
+
+ status = span->signal_cb(sigmsg);
+
+ if (sigmsg->channel) {
+ zap_mutex_unlock(sigmsg->channel->mutex);
+ }
+ }
+
+ return status;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_global_init(void)
+{
+ int modcount;
+
+ memset(&globals, 0, sizeof(globals));
+
+ time_init();
+
+ zap_thread_override_default_stacksize(ZAP_THREAD_STACKSIZE);
+
+ memset(&interfaces, 0, sizeof(interfaces));
+ globals.interface_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys);
+ globals.module_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys);
+ globals.span_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys);
+ modcount = 0;
+ zap_mutex_create(&globals.mutex);
+ zap_mutex_create(&globals.span_mutex);
+
+ modcount = zap_load_modules();
+ zap_log(ZAP_LOG_NOTICE, "Modules configured: %d \n", modcount);
+
+ globals.cpu_monitor.interval = 1000;
+ globals.cpu_monitor.alarm_action_flags = ZAP_CPU_ALARM_ACTION_WARN | ZAP_CPU_ALARM_ACTION_REJECT;
+ globals.cpu_monitor.set_alarm_threshold = 80;
+ globals.cpu_monitor.reset_alarm_threshold = 70;
+
+ if (load_config() != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "No modules configured!\n");
+ return ZAP_FAIL;
+ }
+
+ globals.running = 1;
+ if (!zap_cpu_monitor_disabled) {
+ if (zap_cpu_monitor_start() != ZAP_SUCCESS) {
+ return ZAP_FAIL;
+ }
+ }
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(uint32_t) zap_running(void)
+{
+ return globals.running;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_global_destroy(void)
+{
+ unsigned int j;
+ zap_span_t *sp;
+
+ time_end();
+
+ globals.running = 0;
+ zap_cpu_monitor_stop();
+ zap_span_close_all();
+ zap_sleep(1000);
+
+ zap_mutex_lock(globals.span_mutex);
+ for (sp = globals.spans; sp;) {
+ zap_span_t *cur_span = sp;
+ sp = sp->next;
+
+ if (cur_span) {
+ if (zap_test_flag(cur_span, ZAP_SPAN_CONFIGURED)) {
+ zap_mutex_lock(cur_span->mutex);
+ zap_clear_flag(cur_span, ZAP_SPAN_CONFIGURED);
+ for(j = 1; j <= cur_span->chan_count && cur_span->channels[j]; j++) {
+ zap_channel_t *cur_chan = cur_span->channels[j];
+ if (cur_chan) {
+ if (zap_test_flag(cur_chan, ZAP_CHANNEL_CONFIGURED)) {
+ zap_channel_destroy(cur_chan);
+ }
+ free(cur_chan);
+ cur_chan = NULL;
+ }
+ }
+ zap_mutex_unlock(cur_span->mutex);
+
+ if (cur_span->mutex) {
+ zap_mutex_destroy(&cur_span->mutex);
+ }
+
+ zap_safe_free(cur_span->signal_data);
+ zap_span_destroy(cur_span);
+ }
+
+ hashtable_remove(globals.span_hash, (void *)cur_span->name);
+ zap_safe_free(cur_span->type);
+ zap_safe_free(cur_span->name);
+ free(cur_span);
+ cur_span = NULL;
+ }
+ }
+ globals.spans = NULL;
+ zap_mutex_unlock(globals.span_mutex);
+
+ globals.span_index = 0;
+
+ zap_unload_modules();
+
+ zap_mutex_lock(globals.mutex);
+ hashtable_destroy(globals.interface_hash);
+ hashtable_destroy(globals.module_hash);
+ hashtable_destroy(globals.span_hash);
+ zap_mutex_unlock(globals.mutex);
+ zap_mutex_destroy(&globals.mutex);
+ zap_mutex_destroy(&globals.span_mutex);
+ memset(&globals, 0, sizeof(globals));
+ return ZAP_SUCCESS;
+}
+
+
+OZ_DECLARE(uint32_t) zap_separate_string(char *buf, char delim, char **array, int arraylen)
+{
+ int argc;
+ char *ptr;
+ int quot = 0;
+ char qc = '\'';
+ int x;
+
+ if (!buf || !array || !arraylen) {
+ return 0;
+ }
+
+ memset(array, 0, arraylen * sizeof(*array));
+
+ ptr = buf;
+
+ for (argc = 0; *ptr && (argc < arraylen - 1); argc++) {
+ array[argc] = ptr;
+ for (; *ptr; ptr++) {
+ if (*ptr == qc) {
+ if (quot) {
+ quot--;
+ } else {
+ quot++;
+ }
+ } else if ((*ptr == delim) && !quot) {
+ *ptr++ = '\0';
+ break;
+ }
+ }
+ }
+
+ if (*ptr) {
+ array[argc++] = ptr;
+ }
+
+ /* strip quotes and leading / trailing spaces */
+ for (x = 0; x < argc; x++) {
+ char *p;
+
+ while(*(array[x]) == ' ') {
+ (array[x])++;
+ }
+ p = array[x];
+ while((p = strchr(array[x], qc))) {
+ memmove(p, p+1, strlen(p));
+ p++;
+ }
+ p = array[x] + (strlen(array[x]) - 1);
+ while(*p == ' ') {
+ *p-- = '\0';
+ }
+ }
+
+ return argc;
+}
+
+OZ_DECLARE(void) zap_bitstream_init(zap_bitstream_t *bsp, uint8_t *data, uint32_t datalen, zap_endian_t endian, uint8_t ss)
+{
+ memset(bsp, 0, sizeof(*bsp));
+ bsp->data = data;
+ bsp->datalen = datalen;
+ bsp->endian = endian;
+ bsp->ss = ss;
+
+ if (endian < 0) {
+ bsp->top = bsp->bit_index = 7;
+ bsp->bot = 0;
+ } else {
+ bsp->top = bsp->bit_index = 0;
+ bsp->bot = 7;
+ }
+
+}
+
+OZ_DECLARE(int8_t) zap_bitstream_get_bit(zap_bitstream_t *bsp)
+{
+ int8_t bit = -1;
+
+
+ if (bsp->byte_index >= bsp->datalen) {
+ goto done;
+ }
+
+ if (bsp->ss) {
+ if (!bsp->ssv) {
+ bsp->ssv = 1;
+ return 0;
+ } else if (bsp->ssv == 2) {
+ bsp->byte_index++;
+ bsp->ssv = 0;
+ return 1;
+ }
+ }
+
+
+
+
+ bit = (bsp->data[bsp->byte_index] >> (bsp->bit_index)) & 1;
+
+ if (bsp->bit_index == bsp->bot) {
+ bsp->bit_index = bsp->top;
+ if (bsp->ss) {
+ bsp->ssv = 2;
+ goto done;
+ }
+
+ if (++bsp->byte_index > bsp->datalen) {
+ bit = -1;
+ goto done;
+ }
+
+ } else {
+ bsp->bit_index = bsp->bit_index + bsp->endian;
+ }
+
+
+ done:
+ return bit;
+}
+
+OZ_DECLARE(void) print_hex_bytes(uint8_t *data, zap_size_t dlen, char *buf, zap_size_t blen)
+{
+ char *bp = buf;
+ uint8_t *byte = data;
+ uint32_t i, j = 0;
+
+ if (blen < (dlen * 3) + 2) {
+ return;
+ }
+
+ *bp++ = '[';
+ j++;
+
+ for(i = 0; i < dlen; i++) {
+ snprintf(bp, blen-j, "%02x ", *byte++);
+ bp += 3;
+ j += 3;
+ }
+
+ *--bp = ']';
+
+}
+
+OZ_DECLARE(void) print_bits(uint8_t *b, int bl, char *buf, int blen, zap_endian_t e, uint8_t ss)
+{
+ zap_bitstream_t bs;
+ int j = 0, c = 0;
+ int8_t bit;
+ uint32_t last;
+
+ if (blen < (bl * 10) + 2) {
+ return;
+ }
+
+ zap_bitstream_init(&bs, b, bl, e, ss);
+ last = bs.byte_index;
+ while((bit = zap_bitstream_get_bit(&bs)) > -1) {
+ buf[j++] = bit ? '1' : '0';
+ if (bs.byte_index != last) {
+ buf[j++] = ' ';
+ last = bs.byte_index;
+ if (++c == 8) {
+ buf[j++] = '\n';
+ c = 0;
+ }
+ }
+ }
+
+}
+
+
+
+OZ_DECLARE_NONSTD(zap_status_t) zap_console_stream_raw_write(zap_stream_handle_t *handle, uint8_t *data, zap_size_t datalen)
+{
+ zap_size_t need = handle->data_len + datalen;
+
+ if (need >= handle->data_size) {
+ void *new_data;
+ need += handle->alloc_chunk;
+
+ if (!(new_data = realloc(handle->data, need))) {
+ return ZAP_MEMERR;
+ }
+
+ handle->data = new_data;
+ handle->data_size = need;
+ }
+
+ memcpy((uint8_t *) (handle->data) + handle->data_len, data, datalen);
+ handle->data_len += datalen;
+ handle->end = (uint8_t *) (handle->data) + handle->data_len;
+ *(uint8_t *)handle->end = '\0';
+
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(int) zap_vasprintf(char **ret, const char *fmt, va_list ap) /* code from switch_apr.c */
+{
+#ifdef HAVE_VASPRINTF
+ return vasprintf(ret, fmt, ap);
+#else
+ char *buf;
+ int len;
+ size_t buflen;
+ va_list ap2;
+ char *tmp = NULL;
+
+#ifdef _MSC_VER
+#if _MSC_VER >= 1500
+ /* hack for incorrect assumption in msvc header files for code analysis */
+ __analysis_assume(tmp);
+#endif
+ ap2 = ap;
+#else
+ va_copy(ap2, ap);
+#endif
+
+ len = vsnprintf(tmp, 0, fmt, ap2);
+
+ if (len > 0 && (buf = malloc((buflen = (size_t) (len + 1)))) != NULL) {
+ len = vsnprintf(buf, buflen, fmt, ap);
+ *ret = buf;
+ } else {
+ *ret = NULL;
+ len = -1;
+ }
+
+ va_end(ap2);
+ return len;
+#endif
+}
+
+OZ_DECLARE_NONSTD(zap_status_t) zap_console_stream_write(zap_stream_handle_t *handle, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf = handle->data;
+ char *end = handle->end;
+ int ret = 0;
+ char *data = NULL;
+
+ if (handle->data_len >= handle->data_size) {
+ return ZAP_FAIL;
+ }
+
+ va_start(ap, fmt);
+ ret = zap_vasprintf(&data, fmt, ap);
+ va_end(ap);
+
+ if (data) {
+ zap_size_t remaining = handle->data_size - handle->data_len;
+ zap_size_t need = strlen(data) + 1;
+
+ if ((remaining < need) && handle->alloc_len) {
+ zap_size_t new_len;
+ void *new_data;
+
+ new_len = handle->data_size + need + handle->alloc_chunk;
+ if ((new_data = realloc(handle->data, new_len))) {
+ handle->data_size = handle->alloc_len = new_len;
+ handle->data = new_data;
+ buf = handle->data;
+ remaining = handle->data_size - handle->data_len;
+ handle->end = (uint8_t *) (handle->data) + handle->data_len;
+ end = handle->end;
+ } else {
+ zap_log(ZAP_LOG_CRIT, "Memory Error!\n");
+ free(data);
+ return ZAP_FAIL;
+ }
+ }
+
+ if (remaining < need) {
+ ret = -1;
+ } else {
+ ret = 0;
+ snprintf(end, remaining, "%s", data);
+ handle->data_len = strlen(buf);
+ handle->end = (uint8_t *) (handle->data) + handle->data_len;
+ }
+ free(data);
+ }
+
+ return ret ? ZAP_FAIL : ZAP_SUCCESS;
+}
+
+static void *zap_cpu_monitor_run(zap_thread_t *me, void *obj)
+{
+#ifndef WIN32
+ cpu_monitor_t *monitor = (cpu_monitor_t *)obj;
+ struct zap_cpu_monitor_stats *cpu_stats = zap_new_cpu_monitor();
+ if (!cpu_stats) {
+ return NULL;
+ }
+ monitor->running = 1;
+
+ while(zap_running()) {
+ double time;
+ if (zap_cpu_get_system_idle_time(cpu_stats, &time)) {
+ break;
+ }
+
+ if (monitor->alarm) {
+ if ((int)time >= (100-monitor->set_alarm_threshold)) {
+ zap_log(ZAP_LOG_DEBUG, "CPU alarm OFF (idle:%d)\n", (int) time);
+ monitor->alarm = 0;
+ }
+ if (monitor->alarm_action_flags & ZAP_CPU_ALARM_ACTION_WARN) {
+ zap_log(ZAP_LOG_WARNING, "CPU alarm is ON (cpu usage:%d)\n", (int) (100-time));
+ }
+ } else {
+ if ((int)time <= (100-monitor->reset_alarm_threshold)) {
+ zap_log(ZAP_LOG_DEBUG, "CPU alarm ON (idle:%d)\n", (int) time);
+ monitor->alarm = 1;
+ }
+ }
+ zap_interrupt_wait(monitor->interrupt, monitor->interval);
+ }
+ zap_delete_cpu_monitor(cpu_stats);
+ monitor->running = 0;
+#else
+ UNREFERENCED_PARAMETER(me);
+ UNREFERENCED_PARAMETER(obj);
+#endif
+
+ return NULL;
+}
+
+
+static zap_status_t zap_cpu_monitor_start(void)
+{
+ if (zap_interrupt_create(&globals.cpu_monitor.interrupt, ZAP_INVALID_SOCKET) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_CRIT, "Failed to create CPU monitor interrupt\n");
+ return ZAP_FAIL;
+ }
+
+ if (zap_thread_create_detached(zap_cpu_monitor_run, &globals.cpu_monitor) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_CRIT, "Failed to create cpu monitor thread!!\n");
+ return ZAP_FAIL;
+ }
+ return ZAP_SUCCESS;
+}
+
+static void zap_cpu_monitor_stop(void)
+{
+ if (!globals.cpu_monitor.interrupt) {
+ return;
+ }
+
+ if (!globals.cpu_monitor.running) {
+ return;
+ }
+
+ if (zap_interrupt_signal(globals.cpu_monitor.interrupt) != ZAP_SUCCESS) {
+ zap_log(ZAP_LOG_CRIT, "Failed to stop CPU monitor\n");
+ return;
+ }
+
+ while(globals.cpu_monitor.running) {
+ zap_sleep(10);
+ }
+
+ zap_interrupt_destroy(&globals.cpu_monitor.interrupt);
+}
+
+OZ_DECLARE(void) zap_cpu_monitor_disable(void)
+{
+ zap_cpu_monitor_disabled = 1;
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
Added: freeswitch/trunk/libs/openzap/src/zap_m3ua.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/zap_m3ua.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/zap_m3ua.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,692 @@
+/*
+ * zap_m3ua.c
+ * openzap
+ *
+ * Created by Shane Burrell on 4/3/08.
+ * Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ *
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic *
+ *
+ * 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.
+ */
+
+
+#include "openzap.h"
+#include "m3ua_client.h"
+#include "zap_m3ua.h"
+
+#define MAX_REQ_ID MAX_PENDING_CALLS
+typedef uint16_t m3ua_request_id_t;
+
+typedef enum {
+ BST_FREE,
+ BST_WAITING,
+ BST_READY,
+ BST_FAIL
+} m3ua_request_status_t;
+
+typedef struct {
+ m3ua_request_status_t status;
+ m3uac_event_t event;
+ zap_span_t *span;
+ zap_channel_t *zchan;
+} m3ua_request_t;
+
+
+struct general_config {
+ uint32_t region;
+};
+typedef struct general_config general_config_t;
+
+
+struct m3ua_channel_profile {
+ char name[80];
+ int cust_span;
+ unsigned char opc[3];
+ unsigned char dpc[3];
+ int local_ip[4];
+ int local_port;
+ int remote_ip[4];
+ int remote_port;
+ int m3ua_mode;
+};
+typedef struct m3ua_channel_profile m3ua_channel_profile_t;
+
+static struct {
+ zap_hash_t *profile_hash;
+ general_config_t general_config;
+} globals;
+
+struct m3ua_span_data {
+ uint32_t boardno;
+ uint32_t flags;
+};
+typedef struct m3ua_span_data m3ua_span_data_t;
+
+struct m3ua_chan_data {
+ zap_buffer_t *digit_buffer;
+ zap_mutex_t *digit_mutex;
+ zap_size_t dtmf_len;
+ uint32_t flags;
+ uint32_t hdlc_bytes;
+};
+typedef struct m3ua_chan_data m3ua_chan_data_t;
+
+static zap_mutex_t *request_mutex = NULL;
+static zap_mutex_t *signal_mutex = NULL;
+
+static uint8_t req_map[MAX_REQ_ID+1] = { 0 };
+
+static void release_request_id(m3ua_request_id_t r)
+{
+ zap_mutex_lock(request_mutex);
+ req_map[r] = 0;
+ zap_mutex_unlock(request_mutex);
+}
+
+/*static m3ua_request_id_t next_request_id(void)
+{
+ m3ua_request_id_t r = 0;
+ int ok = 0;
+
+ while(!ok) {
+ zap_mutex_lock(request_mutex);
+ for (r = 1; r <= MAX_REQ_ID; r++) {
+ if (!req_map[r]) {
+ ok = 1;
+ req_map[r] = 1;
+ break;
+ }
+ }
+ zap_mutex_unlock(request_mutex);
+ if (!ok) {
+ zap_sleep(5);
+ }
+ }
+ return r;
+}
+*/
+
+static __inline__ void state_advance(zap_channel_t *zchan)
+{
+
+ m3ua_data_t *m3ua_data = zchan->span->signal_data;
+ m3uac_connection_t *mcon = &m3ua_data->mcon;
+ zap_sigmsg_t sig;
+ zap_status_t status;
+
+ zap_log(ZAP_LOG_DEBUG, "%d:%d STATE [%s]\n", zchan->span_id, zchan->chan_id, zap_channel_state2str(zchan->state));
+
+ memset(&sig, 0, sizeof(sig));
+ sig.chan_id = zchan->chan_id;
+ sig.span_id = zchan->span_id;
+ sig.channel = zchan;
+
+ switch (zchan->state) {
+ case ZAP_CHANNEL_STATE_DOWN:
+ {
+ if (zchan->extra_id) {
+ release_request_id((m3ua_request_id_t)zchan->extra_id);
+ zchan->extra_id = 0;
+ }
+ zap_channel_done(zchan);
+ }
+ break;
+ case ZAP_CHANNEL_STATE_PROGRESS_MEDIA:
+ case ZAP_CHANNEL_STATE_PROGRESS:
+ {
+ if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ sig.event_id = ZAP_SIGEVENT_PROGRESS_MEDIA;
+ if ((status = m3ua_data->signal_cb(&sig) != ZAP_SUCCESS)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ } else {
+ m3uac_exec_command(mcon,
+ zchan->physical_span_id-1,
+ zchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_START_ACK,
+ 0);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_RING:
+ {
+ if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ sig.event_id = ZAP_SIGEVENT_START;
+ if ((status = m3ua_data->signal_cb(&sig) != ZAP_SUCCESS)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ }
+
+ }
+ break;
+ case ZAP_CHANNEL_STATE_RESTART:
+ {
+ if (zchan->last_state != ZAP_CHANNEL_STATE_HANGUP && zchan->last_state != ZAP_CHANNEL_STATE_DOWN) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ } else {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_UP:
+ {
+ if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+ sig.event_id = ZAP_SIGEVENT_UP;
+ if ((status = m3ua_data->signal_cb(&sig) != ZAP_SUCCESS)) {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+ }
+ } else {
+ if (!(zap_test_flag(zchan, ZAP_CHANNEL_PROGRESS) || zap_test_flag(zchan, ZAP_CHANNEL_MEDIA))) {
+ m3uac_exec_command(mcon,
+ zchan->physical_span_id-1,
+ zchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_START_ACK,
+ 0);
+ }
+
+ m3uac_exec_command(mcon,
+ zchan->physical_span_id-1,
+ zchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_ANSWERED,
+ 0);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_DIALING:
+ {
+ }
+ break;
+ case ZAP_CHANNEL_STATE_HANGUP_COMPLETE:
+ {
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ }
+ break;
+ case ZAP_CHANNEL_STATE_HANGUP:
+ {
+ if (zap_test_flag(zchan, ZAP_CHANNEL_ANSWERED) || zap_test_flag(zchan, ZAP_CHANNEL_PROGRESS) || zap_test_flag(zchan, ZAP_CHANNEL_MEDIA)) {
+ m3uac_exec_command(mcon,
+ zchan->physical_span_id-1,
+ zchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_STOPPED,
+ zchan->caller_data.hangup_cause);
+ } else {
+ m3uac_exec_command(mcon,
+ zchan->physical_span_id-1,
+ zchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_START_NACK,
+ zchan->caller_data.hangup_cause);
+ }
+ }
+ break;
+ case ZAP_CHANNEL_STATE_CANCEL:
+ {
+ sig.event_id = ZAP_SIGEVENT_STOP;
+ status = m3ua_data->signal_cb(&sig);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ m3uac_exec_command(mcon,
+ zchan->physical_span_id-1,
+ zchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_START_NACK_ACK,
+ 0);
+ }
+ break;
+ case ZAP_CHANNEL_STATE_TERMINATING:
+ {
+ sig.event_id = ZAP_SIGEVENT_STOP;
+ status = m3ua_data->signal_cb(&sig);
+ zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+ m3uac_exec_command(mcon,
+ zchan->physical_span_id-1,
+ zchan->physical_chan_id-1,
+ 0,
+ SIGBOOST_EVENT_CALL_STOPPED_ACK,
+ 0);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+static __inline__ void check_state(zap_span_t *span)
+{
+ if (zap_test_flag(span, ZAP_SPAN_STATE_CHANGE)) {
+ uint32_t j;
+ zap_clear_flag_locked(span, ZAP_SPAN_STATE_CHANGE);
+ for(j = 1; j <= span->chan_count; j++) {
+ if (zap_test_flag((&span->channels[j]), ZAP_CHANNEL_STATE_CHANGE)) {
+ zap_clear_flag_locked((&span->channels[j]), ZAP_CHANNEL_STATE_CHANGE);
+ state_advance(&span->channels[j]);
+ zap_channel_complete_state(&span->channels[j]);
+ }
+ }
+ }
+}
+
+
+static int parse_ss7_event(zap_span_t *span, m3uac_connection_t *mcon, m3uac_event_t *event)
+{
+ zap_mutex_lock(signal_mutex);
+
+ if (!zap_running()) {
+ zap_log(ZAP_LOG_WARNING, "System is shutting down.\n");
+ goto end;
+ }
+
+
+ if (zap_test_flag(span, ZAP_SPAN_SUSPENDED) &&
+ event->event_id != SIGBOOST_EVENT_SYSTEM_RESTART_ACK && event->event_id != SIGBOOST_EVENT_HEARTBEAT) {
+
+ zap_log(ZAP_LOG_WARNING,
+ "INVALID EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n",
+ m3uac_event_id_name(event->event_id),
+ event->event_id,
+ event->span+1,
+ event->chan+1,
+ event->release_cause,
+ event->call_setup_id,
+ event->fseqno,
+ (event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
+ (event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A")
+ );
+
+ goto end;
+ }
+
+
+ zap_log(ZAP_LOG_DEBUG,
+ "RX EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n",
+ m3uac_event_id_name(event->event_id),
+ event->event_id,
+ event->span+1,
+ event->chan+1,
+ event->release_cause,
+ event->call_setup_id,
+ event->fseqno,
+ (event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
+ (event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A")
+ );
+
+
+
+ switch(event->event_id) {
+
+ case SIGBOOST_EVENT_CALL_START:
+ //handle_call_start(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_STOPPED:
+ //handle_call_stop(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_START_ACK:
+ //handle_call_start_ack(mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_START_NACK:
+ //handle_call_start_nack(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_ANSWERED:
+ //handle_call_answer(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_HEARTBEAT:
+ //handle_heartbeat(mcon, event);
+ break;
+ case SIGBOOST_EVENT_CALL_STOPPED_ACK:
+ case SIGBOOST_EVENT_CALL_START_NACK_ACK:
+ //handle_call_done(span, mcon, event);
+ break;
+ case SIGBOOST_EVENT_INSERT_CHECK_LOOP:
+ //handle_call_loop_start(event);
+ break;
+ case SIGBOOST_EVENT_REMOVE_CHECK_LOOP:
+ //handle_call_stop(event);
+ break;
+ case SIGBOOST_EVENT_SYSTEM_RESTART_ACK:
+ //handle_restart_ack(mcon, span, event);
+ break;
+ case SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE:
+ //handle_gap_abate(event);
+ break;
+ default:
+ zap_log(ZAP_LOG_WARNING, "No handler implemented for [%s]\n", m3uac_event_id_name(event->event_id));
+ break;
+ }
+
+ end:
+
+ zap_mutex_unlock(signal_mutex);
+
+ return 0;
+}
+
+static ZIO_CONFIGURE_FUNCTION(m3ua_configure)
+{
+ m3ua_channel_profile_t *profile = NULL;
+
+ int ok = 1;
+
+ if (!(profile = (m3ua_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)category))) {
+ profile = malloc(sizeof(*profile));
+ memset(profile, 0, sizeof(*profile));
+ zap_set_string(profile->name, category);
+ hashtable_insert(globals.profile_hash, (void *)profile->name, profile);
+ zap_log(ZAP_LOG_INFO, "creating profile [%s]\n", category);
+ }
+
+// zap_set_string(m3ua_data->mcon. cfg.local_ip, local_ip);
+ if (!strcasecmp(var, "local_sctp_port")) {
+ profile->local_port = 30000 ;
+ profile->remote_port = 30000;
+ profile->cust_span++;
+ }
+ ok = 1;
+
+
+ if (ok) {
+ zap_log(ZAP_LOG_INFO, "setting param [%s]=[%s] for profile [%s]\n", var, val, category);
+ } else {
+ zap_log(ZAP_LOG_ERROR, "unknown param [%s]\n", var);
+ }
+
+ return ZAP_SUCCESS;
+}
+
+static ZIO_CONFIGURE_SPAN_FUNCTION(m3ua_configure_span)
+{
+
+ return ZAP_FAIL;
+}
+
+static ZIO_OPEN_FUNCTION(m3ua_open)
+{
+
+ return ZAP_FAIL;
+}
+
+static ZIO_CLOSE_FUNCTION(m3ua_close)
+{
+
+ return ZAP_FAIL;
+}
+
+/*static ZIO_SET_INTERVAL_FUNCTION(m3ua_set_interval)
+{
+
+ return 0;
+}*/
+
+static ZIO_WAIT_FUNCTION(m3ua_wait)
+{
+
+ return ZAP_FAIL;
+}
+
+static ZIO_READ_FUNCTION(m3ua_read)
+{
+
+ return ZAP_FAIL;
+}
+
+static ZIO_WRITE_FUNCTION(m3ua_write)
+{
+
+ return ZAP_FAIL;
+}
+
+static ZIO_COMMAND_FUNCTION(m3ua_command)
+{
+ return ZAP_FAIL;
+}
+
+static ZIO_SPAN_POLL_EVENT_FUNCTION(m3ua_poll_event)
+{
+ return ZAP_FAIL;
+}
+
+static ZIO_SPAN_NEXT_EVENT_FUNCTION(m3ua_next_event)
+{
+ return ZAP_FAIL;
+}
+
+
+static ZIO_SPAN_DESTROY_FUNCTION(m3ua_span_destroy)
+{
+ m3ua_span_data_t *span_data = (m3ua_span_data_t *) span->mod_data;
+
+ if (span_data) {
+ free(span_data);
+ }
+
+ return ZAP_SUCCESS;
+}
+static ZIO_CHANNEL_DESTROY_FUNCTION(m3ua_channel_destroy)
+{
+ m3ua_chan_data_t *chan_data = (m3ua_chan_data_t *) zchan->mod_data;
+ m3ua_span_data_t *span_data = (m3ua_span_data_t *) zchan->span->mod_data;
+
+ if (!chan_data) {
+ return ZAP_FAIL;
+ }
+
+
+
+
+
+
+ zap_mutex_destroy(&chan_data->digit_mutex);
+ zap_buffer_destroy(&chan_data->digit_buffer);
+
+
+ zap_safe_free(chan_data);
+
+ if (span_data) {
+ free(span_data);
+ }
+
+
+ return ZAP_SUCCESS;
+}
+
+
+
+static ZIO_GET_ALARMS_FUNCTION(m3ua_get_alarms)
+{
+ return ZAP_FAIL;
+}
+
+static zap_io_interface_t m3ua_interface;
+
+zap_status_t m3ua_init(zap_io_interface_t **zint)
+{
+ assert(zint != NULL);
+ memset(&m3ua_interface, 0, sizeof(m3ua_interface));
+
+ m3ua_interface.name = "m3ua";
+ m3ua_interface.configure = m3ua_configure;
+ m3ua_interface.configure_span = m3ua_configure_span;
+ m3ua_interface.open = m3ua_open;
+ m3ua_interface.close = m3ua_close;
+ m3ua_interface.wait = m3ua_wait;
+ m3ua_interface.read = m3ua_read;
+ m3ua_interface.write = m3ua_write;
+ m3ua_interface.command = m3ua_command;
+ m3ua_interface.poll_event = m3ua_poll_event;
+ m3ua_interface.next_event = m3ua_next_event;
+ m3ua_interface.channel_destroy = m3ua_channel_destroy;
+ m3ua_interface.span_destroy = m3ua_span_destroy;
+ m3ua_interface.get_alarms = m3ua_get_alarms;
+ *zint = &m3ua_interface;
+
+ return ZAP_FAIL;
+}
+
+zap_status_t m3ua_destroy(void)
+{
+ return ZAP_FAIL;
+}
+
+
+static void *m3ua_run(zap_thread_t *me, void *obj)
+{
+ zap_span_t *span = (zap_span_t *) obj;
+ m3ua_data_t *m3ua_data = span->signal_data;
+ m3uac_connection_t *mcon, *pcon;
+ uint32_t ms = 10, too_long = 60000;
+
+
+ m3ua_data->pcon = m3ua_data->mcon;
+
+ if (m3uac_connection_open(&m3ua_data->mcon,
+ m3ua_data->mcon.cfg.local_ip,
+ m3ua_data->mcon.cfg.local_port,
+ m3ua_data->mcon.cfg.remote_ip,
+ m3ua_data->mcon.cfg.remote_port) < 0) {
+ zap_log(ZAP_LOG_DEBUG, "Error: Opening MCON Socket [%d] %s\n", m3ua_data->mcon.socket, strerror(errno));
+ goto end;
+ }
+
+ if (m3uac_connection_open(&m3ua_data->pcon,
+ m3ua_data->pcon.cfg.local_ip,
+ ++m3ua_data->pcon.cfg.local_port,
+ m3ua_data->pcon.cfg.remote_ip,
+ m3ua_data->pcon.cfg.remote_port) < 0) {
+ zap_log(ZAP_LOG_DEBUG, "Error: Opening PCON Socket [%d] %s\n", m3ua_data->pcon.socket, strerror(errno));
+ goto end;
+ }
+
+ mcon = &m3ua_data->mcon;
+ pcon = &m3ua_data->pcon;
+
+ top:
+
+ //init_outgoing_array();
+
+ m3uac_exec_command(mcon,
+ 0,
+ 0,
+ -1,
+ SIGBOOST_EVENT_SYSTEM_RESTART,
+ 0);
+
+ while (zap_test_flag(m3ua_data, ZAP_M3UA_RUNNING)) {
+ fd_set rfds, efds;
+ struct timeval tv = { 0, ms * 1000 };
+ int max, activity, i = 0;
+ m3uac_event_t *event = NULL;
+
+ if (!zap_running()) {
+ m3uac_exec_command(mcon,
+ 0,
+ 0,
+ -1,
+ SIGBOOST_EVENT_SYSTEM_RESTART,
+ 0);
+ break;
+ }
+
+ FD_ZERO(&rfds);
+ FD_ZERO(&efds);
+ FD_SET(mcon->socket, &rfds);
+ FD_SET(mcon->socket, &efds);
+ FD_SET(pcon->socket, &rfds);
+ FD_SET(pcon->socket, &efds);
+
+ max = ((pcon->socket > mcon->socket) ? pcon->socket : mcon->socket) + 1;
+
+ if ((activity = select(max, &rfds, NULL, &efds, &tv)) < 0) {
+ goto error;
+ }
+
+ if (activity) {
+ if (FD_ISSET(pcon->socket, &efds) || FD_ISSET(mcon->socket, &efds)) {
+ goto error;
+ }
+
+ if (FD_ISSET(pcon->socket, &rfds)) {
+ if ((event = m3uac_connection_readp(pcon, i))) {
+ parse_ss7_event(span, mcon, event);
+ } else goto top;
+ }
+
+ if (FD_ISSET(mcon->socket, &rfds)) {
+ if ((event = m3uac_connection_read(mcon, i))) {
+ parse_ss7_event(span, mcon, event);
+ } else goto top;
+ }
+ }
+
+ check_state(span);
+ mcon->hb_elapsed += ms;
+
+ if (mcon->hb_elapsed >= too_long && (mcon->up || !zap_test_flag(span, ZAP_SPAN_SUSPENDED))) {
+ zap_set_state_all(span, ZAP_CHANNEL_STATE_RESTART);
+ zap_set_flag_locked(span, ZAP_SPAN_SUSPENDED);
+ mcon->up = 0;
+ zap_log(ZAP_LOG_CRIT, "Lost Heartbeat!\n");
+ }
+
+ }
+
+ goto end;
+
+ error:
+ zap_log(ZAP_LOG_CRIT, "Socket Error!\n");
+
+ end:
+
+ m3uac_connection_close(&m3ua_data->mcon);
+ m3uac_connection_close(&m3ua_data->pcon);
+
+ zap_clear_flag(m3ua_data, ZAP_M3UA_RUNNING);
+
+ zap_log(ZAP_LOG_DEBUG, "M3UA thread ended.\n");
+ return NULL;
+}
+zap_status_t m3ua_start(zap_span_t *span)
+{
+ m3ua_data_t *m3ua_data = span->signal_data;
+ zap_set_flag(m3ua_data, ZAP_M3UA_RUNNING);
+ return zap_thread_create_detached(m3ua_run, span);
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+*/
Added: freeswitch/trunk/libs/openzap/src/zap_threadmutex.c (0 => 17141)
--- freeswitch/trunk/libs/openzap/src/zap_threadmutex.c (rev 0)
+++ freeswitch/trunk/libs/openzap/src/zap_threadmutex.c 2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,454 @@
+/*
+ * Cross Platform Thread/Mutex abstraction
+ * Copyright(C) 2007 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Soozware, and permit persons to whom the Soozware is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer.
+ *
+ * Contributors:
+ *
+ * Moises Silva <moy@sangoma.com>
+ *
+ */
+
+#ifdef WIN32
+/* required for TryEnterCriticalSection definition. Must be defined before windows.h include */
+#define _WIN32_WINNT 0x0400
+#endif
+
+#include "openzap.h"
+#include "zap_threadmutex.h"
+
+#ifdef WIN32
+#include <process.h>
+
+#define ZAP_THREAD_CALLING_CONVENTION __stdcall
+
+struct zap_mutex {
+ CRITICAL_SECTION mutex;
+};
+
+#else
+#include <pthread.h>
+#include <poll.h>
+
+#define ZAP_THREAD_CALLING_CONVENTION
+
+struct zap_mutex {
+ pthread_mutex_t mutex;
+};
+
+#endif
+
+struct zap_interrupt {
+ zap_socket_t device;
+#ifdef WIN32
+ /* for generic interruption */
+ HANDLE event;
+#else
+ /* for generic interruption */
+ int readfd;
+ int writefd;
+#endif
+};
+
+struct zap_thread {
+#ifdef WIN32
+ void *handle;
+#else
+ pthread_t handle;
+#endif
+ void *private_data;
+ zap_thread_function_t function;
+ zap_size_t stack_size;
+#ifndef WIN32
+ pthread_attr_t attribute;
+#endif
+};
+
+zap_size_t thread_default_stacksize = 0;
+
+OZ_DECLARE(void) zap_thread_override_default_stacksize(zap_size_t size)
+{
+ thread_default_stacksize = size;
+}
+
+static void * ZAP_THREAD_CALLING_CONVENTION thread_launch(void *args)
+{
+ void *exit_val;
+ zap_thread_t *thread = (zap_thread_t *)args;
+ exit_val = thread->function(thread, thread->private_data);
+#ifndef WIN32
+ pthread_attr_destroy(&thread->attribute);
+#endif
+ zap_safe_free(thread);
+
+ return exit_val;
+}
+
+OZ_DECLARE(zap_status_t) zap_thread_create_detached(zap_thread_function_t func, void *data)
+{
+ return zap_thread_create_detached_ex(func, data, thread_default_stacksize);
+}
+
+OZ_DECLARE(zap_status_t) zap_thread_create_detached_ex(zap_thread_function_t func, void *data, zap_size_t stack_size)
+{
+ zap_thread_t *thread = NULL;
+ zap_status_t status = ZAP_FAIL;
+
+ if (!func || !(thread = (zap_thread_t *)malloc(sizeof(zap_thread_t)))) {
+ goto done;
+ }
+
+ thread->private_data = data;
+ thread->function = func;
+ thread->stack_size = stack_size;
+
+#if defined(WIN32)
+ thread->handle = (void *)_beginthreadex(NULL, (unsigned)thread->stack_size, (unsigned int (__stdcall *)(void *))thread_launch, thread, 0, NULL);
+ if (!thread->handle) {
+ goto fail;
+ }
+ CloseHandle(thread->handle);
+
+ status = ZAP_SUCCESS;
+ goto done;
+#else
+
+ if (pthread_attr_init(&thread->attribute) != 0) goto fail;
+
+ if (pthread_attr_setdetachstate(&thread->attribute, PTHREAD_CREATE_DETACHED) != 0) goto failpthread;
+
+ if (thread->stack_size && pthread_attr_setstacksize(&thread->attribute, thread->stack_size) != 0) goto failpthread;
+
+ if (pthread_create(&thread->handle, &thread->attribute, thread_launch, thread) != 0) goto failpthread;
+
+ status = ZAP_SUCCESS;
+ goto done;
+ failpthread:
+ pthread_attr_destroy(&thread->attribute);
+#endif
+
+ fail:
+ if (thread) {
+ zap_safe_free(thread);
+ }
+ done:
+ return status;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_mutex_create(zap_mutex_t **mutex)
+{
+ zap_status_t status = ZAP_FAIL;
+#ifndef WIN32
+ pthread_mutexattr_t attr;
+#endif
+ zap_mutex_t *check = NULL;
+
+ check = (zap_mutex_t *)malloc(sizeof(**mutex));
+ if (!check)
+ goto done;
+#ifdef WIN32
+ InitializeCriticalSection(&check->mutex);
+#else
+ if (pthread_mutexattr_init(&attr))
+ goto done;
+
+ if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
+ goto fail;
+
+ if (pthread_mutex_init(&check->mutex, &attr))
+ goto fail;
+
+ goto success;
+
+ fail:
+ pthread_mutexattr_destroy(&attr);
+ goto done;
+
+ success:
+#endif
+ *mutex = check;
+ status = ZAP_SUCCESS;
+
+ done:
+ return status;
+}
+
+OZ_DECLARE(zap_status_t) zap_mutex_destroy(zap_mutex_t **mutex)
+{
+ zap_mutex_t *mp = *mutex;
+ *mutex = NULL;
+ if (!mp) {
+ return ZAP_FAIL;
+ }
+#ifdef WIN32
+ DeleteCriticalSection(&mp->mutex);
+#else
+ if (pthread_mutex_destroy(&mp->mutex))
+ return ZAP_FAIL;
+#endif
+ zap_safe_free(mp);
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) _zap_mutex_lock(zap_mutex_t *mutex)
+{
+#ifdef WIN32
+ EnterCriticalSection(&mutex->mutex);
+#else
+ int err;
+ if ((err = pthread_mutex_lock(&mutex->mutex))) {
+ zap_log(ZAP_LOG_ERROR, "Failed to lock mutex %d:%s\n", err, strerror(err));
+ return ZAP_FAIL;
+ }
+#endif
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) _zap_mutex_trylock(zap_mutex_t *mutex)
+{
+#ifdef WIN32
+ if (!TryEnterCriticalSection(&mutex->mutex))
+ return ZAP_FAIL;
+#else
+ if (pthread_mutex_trylock(&mutex->mutex))
+ return ZAP_FAIL;
+#endif
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) _zap_mutex_unlock(zap_mutex_t *mutex)
+{
+#ifdef WIN32
+ LeaveCriticalSection(&mutex->mutex);
+#else
+ if (pthread_mutex_unlock(&mutex->mutex))
+ return ZAP_FAIL;
+#endif
+ return ZAP_SUCCESS;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_interrupt_create(zap_interrupt_t **ininterrupt, zap_socket_t device)
+{
+ zap_interrupt_t *interrupt = NULL;
+#ifndef WIN32
+ int fds[2];
+#endif
+
+ interrupt = calloc(1, sizeof(*interrupt));
+ if (!interrupt) {
+ zap_log(ZAP_LOG_ERROR, "Failed to allocate interrupt memory\n");
+ return ZAP_FAIL;
+ }
+
+ interrupt->device = device;
+#ifdef WIN32
+ interrupt->event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!interrupt->event) {
+ zap_log(ZAP_LOG_ERROR, "Failed to allocate interrupt event\n");
+ goto failed;
+ }
+#else
+ if (pipe(fds)) {
+ zap_log(ZAP_LOG_ERROR, "Failed to allocate interrupt pipe: %s\n", strerror(errno));
+ goto failed;
+ }
+
+ interrupt->readfd = fds[0];
+ interrupt->writefd = fds[1];
+#endif
+
+ *ininterrupt = interrupt;
+ return ZAP_SUCCESS;
+
+failed:
+ if (interrupt) {
+#ifndef WIN32
+ if (interrupt->readfd) {
+ close(interrupt->readfd);
+ close(interrupt->writefd);
+ interrupt->readfd = -1;
+ interrupt->writefd = -1;
+ }
+#endif
+ zap_safe_free(interrupt);
+ }
+ return ZAP_FAIL;
+}
+
+#define ONE_BILLION 1000000000
+
+OZ_DECLARE(zap_status_t) zap_interrupt_wait(zap_interrupt_t *interrupt, int ms)
+{
+ int num = 1;
+#ifdef WIN32
+ DWORD res = 0;
+ HANDLE ints[2];
+#else
+ int res = 0;
+ struct pollfd ints[2];
+ char pipebuf[255];
+#endif
+
+ /* start implementation */
+#ifdef WIN32
+ ints[0] = interrupt->event;
+ if (interrupt->device != ZAP_INVALID_SOCKET) {
+ num++;
+ ints[1] = interrupt->device;
+ }
+ res = WaitForMultipleObjects(num, ints, FALSE, ms >= 0 ? ms : INFINITE);
+ switch (res) {
+ case WAIT_TIMEOUT:
+ return ZAP_TIMEOUT;
+ case WAIT_FAILED:
+ case WAIT_ABANDONED: /* is it right to fail with abandoned? */
+ return ZAP_FAIL;
+ default:
+ if (res >= (sizeof(ints)/sizeof(ints[0]))) {
+ zap_log(ZAP_LOG_ERROR, "Error waiting for openzap interrupt event (WaitForSingleObject returned %d)\n", res);
+ return ZAP_FAIL;
+ }
+ return ZAP_SUCCESS;
+ }
+#else
+ ints[0].fd = interrupt->readfd;
+ ints[0].events = POLLIN;
+ ints[0].revents = 0;
+
+ if (interrupt->device != ZAP_INVALID_SOCKET) {
+ num++;
+ ints[1].fd = interrupt->device;
+ ints[1].events = POLLIN;
+ ints[1].revents = 0;
+ }
+
+ res = poll(ints, num, ms);
+ if (res == -1) {
+ zap_log(ZAP_LOG_CRIT, "interrupt poll failed (%s)\n", strerror(errno));
+ return ZAP_FAIL;
+ }
+
+ if (res == 0) {
+ return ZAP_TIMEOUT;
+ }
+
+ if (ints[0].revents & POLLIN) {
+ res = read(ints[0].fd, pipebuf, sizeof(pipebuf));
+ if (res == -1) {
+ zap_log(ZAP_LOG_CRIT, "reading interrupt descriptor failed (%s)\n", strerror(errno));
+ }
+ }
+
+ return ZAP_SUCCESS;
+#endif
+}
+
+OZ_DECLARE(zap_status_t) zap_interrupt_signal(zap_interrupt_t *interrupt)
+{
+#ifdef WIN32
+ if (!SetEvent(interrupt->event)) {
+ zap_log(ZAP_LOG_ERROR, "Failed to signal interrupt\n");
+ return ZAP_FAIL;
+ }
+#else
+ int err;
+ if ((err = write(interrupt->writefd, "w", 1)) != 1) {
+ zap_log(ZAP_LOG_ERROR, "Failed to signal interrupt: %s\n", errno, strerror(errno));
+ return ZAP_FAIL;
+ }
+#endif
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_interrupt_destroy(zap_interrupt_t **ininterrupt)
+{
+ zap_interrupt_t *interrupt = NULL;
+ interrupt = *ininterrupt;
+#ifdef WIN32
+ CloseHandle(interrupt->event);
+#else
+ close(interrupt->readfd);
+ close(interrupt->writefd);
+ interrupt->readfd = -1;
+ interrupt->writefd = -1;
+#endif
+ zap_safe_free(interrupt);
+ *ininterrupt = NULL;
+ return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_interrupt_multiple_wait(zap_interrupt_t *interrupts[], zap_size_t size, int ms)
+{
+#ifndef WIN32
+ int i;
+ int res = 0;
+ int numdevices = 0;
+ char pipebuf[255];
+ struct pollfd ints[size*2];
+
+ memset(&ints, 0, sizeof(ints));
+
+ for (i = 0; i < size; i++) {
+ ints[i].events = POLLIN;
+ ints[i].revents = 0;
+ ints[i].fd = interrupts[i]->readfd;
+ if (interrupts[i]->device != ZAP_INVALID_SOCKET) {
+ ints[i+numdevices].events = POLLIN;
+ ints[i+numdevices].revents = 0;
+ ints[i+numdevices].fd = interrupts[i]->device;
+ numdevices++;
+ }
+ }
+
+ res = poll(ints, size + numdevices, ms);
+
+ if (res == -1) {
+ zap_log(ZAP_LOG_CRIT, "interrupt poll failed (%s)\n", strerror(errno));
+ return ZAP_FAIL;
+ }
+
+ if (res == 0) {
+ return ZAP_TIMEOUT;
+ }
+
+ for (i = size; i < zap_array_len(ints); i++) {
+ if (ints[i].revents & POLLIN) {
+ res = read(ints[0].fd, pipebuf, sizeof(pipebuf));
+ if (res == -1) {
+ zap_log(ZAP_LOG_CRIT, "reading interrupt descriptor failed (%s)\n", strerror(errno));
+ }
+ }
+ }
+
+#elif defined(__WINDOWS__)
+ UNREFERENCED_PARAMETER(interrupts);
+ UNREFERENCED_PARAMETER(size);
+ UNREFERENCED_PARAMETER(ms);
+#endif
+ return ZAP_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */