aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormattf <mattf@f38db490-d61c-443f-a65b-d21fe96a405b>2006-09-19 17:07:22 +0000
committermattf <mattf@f38db490-d61c-443f-a65b-d21fe96a405b>2006-09-19 17:07:22 +0000
commit42a59d0531531eaf829c6b4e5daaf98aeed4d38d (patch)
treed60c1d44680a2468dac728d9ab7d40f2aa0d323f
parente61c86f66aa05d8897a3ce99836770a75bb6edf7 (diff)
Mergeing in Paul Cadach's chan_h323 changes *holds breath*
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@43281 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--Makefile2
-rw-r--r--acinclude.m4314
-rw-r--r--build_tools/cflags.xml2
-rw-r--r--build_tools/menuselect-deps.in1
-rw-r--r--channels/Makefile25
-rw-r--r--channels/chan_h323.c2214
-rw-r--r--channels/h323/Makefile40
-rw-r--r--channels/h323/README16
-rw-r--r--channels/h323/TODO5
-rw-r--r--channels/h323/ast_h323.cpp1441
-rw-r--r--channels/h323/ast_h323.h246
-rw-r--r--channels/h323/chan_h323.h116
-rw-r--r--channels/h323/h323.conf.sample149
-rw-r--r--configure.ac88
-rw-r--r--doc/realtime.txt5
-rw-r--r--main/Makefile9
16 files changed, 3163 insertions, 1510 deletions
diff --git a/Makefile b/Makefile
index f5f0205e5..0b381dbdb 100644
--- a/Makefile
+++ b/Makefile
@@ -641,7 +641,7 @@ uninstall-all: _uninstall
rm -rf $(DESTDIR)$(ASTLOGDIR)
menuselect: menuselect/menuselect menuselect-tree
- -@menuselect/menuselect $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) menuselect.makeopts && echo "menuselect changes saved!" || echo "menuselect changes NOT saved!"
+ -@menuselect/menuselect $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) menuselect.makeopts && (echo "menuselect changes saved!"; rm -f channels/h323/Makefile.ast main/asterisk) || echo "menuselect changes NOT saved!"
menuselect/menuselect: makeopts menuselect/menuselect.c menuselect/menuselect_curses.c menuselect/menuselect_stub.c menuselect/menuselect.h menuselect/linkedlists.h makeopts
@unset CC LD AR RANLIB && $(MAKE) -C menuselect CONFIGURE_SILENT="--silent"
diff --git a/acinclude.m4 b/acinclude.m4
index 71ae30184..702916148 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -116,6 +116,320 @@ fi
AC_SUBST([GNU_MAKE])
])
+
+AC_DEFUN(
+[AST_CHECK_PWLIB], [
+PWLIB_INCDIR=
+PWLIB_LIBDIR=
+if test "${PWLIBDIR:-unset}" != "unset" ; then
+ AC_CHECK_FILE(${PWLIBDIR}/version.h, HAS_PWLIB=1, )
+fi
+if test "${HAS_PWLIB:-unset}" = "unset" ; then
+ if test "${OPENH323DIR:-unset}" != "unset"; then
+ AC_CHECK_FILE(${OPENH323DIR}/../pwlib/version.h, HAS_PWLIB=1, )
+ fi
+ if test "${HAS_PWLIB:-unset}" != "unset" ; then
+ PWLIBDIR="${OPENH323DIR}/../pwlib"
+ else
+ AC_CHECK_FILE(${HOME}/pwlib/include/ptlib.h, HAS_PWLIB=1, )
+ if test "${HAS_PWLIB:-unset}" != "unset" ; then
+ PWLIBDIR="${HOME}/pwlib"
+ else
+ AC_CHECK_FILE(/usr/local/include/ptlib.h, HAS_PWLIB=1, )
+ if test "${HAS_PWLIB:-unset}" != "unset" ; then
+ AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/local/bin)
+ if test "${PTLIB_CONFIG:-unset}" = "unset" ; then
+ AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/local/share/pwlib/make)
+ fi
+ PWLIB_INCDIR="/usr/local/include"
+ PWLIB_LIBDIR="/usr/local/lib"
+ else
+ AC_CHECK_FILE(/usr/include/ptlib.h, HAS_PWLIB=1, )
+ if test "${HAS_PWLIB:-unset}" != "unset" ; then
+ AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/share/pwlib/make)
+ PWLIB_INCDIR="/usr/include"
+ PWLIB_LIBDIR="/usr/lib"
+ fi
+ fi
+ fi
+ fi
+fi
+
+#if test "${HAS_PWLIB:-unset}" = "unset" ; then
+# echo "Cannot find pwlib - please install or set PWLIBDIR and try again"
+# exit
+#fi
+
+if test "${HAS_PWLIB:-unset}" != "unset" ; then
+ if test "${PWLIBDIR:-unset}" = "unset" ; then
+ if test "${PTLIB_CONFIG:-unset}" != "unset" ; then
+ PWLIBDIR=`$PTLIB_CONFIG --prefix`
+ else
+ echo "Cannot find ptlib-config - please install and try again"
+ exit
+ fi
+ fi
+
+ if test "x$PWLIBDIR" = "x/usr" -o "x$PWLIBDIR" = "x/usr/"; then
+ PWLIBDIR="/usr/share/pwlib"
+ PWLIB_INCDIR="/usr/include"
+ PWLIB_LIBDIR="/usr/lib"
+ fi
+ if test "x$PWLIBDIR" = "x/usr/local" -o "x$PWLIBDIR" = "x/usr/"; then
+ PWLIBDIR="/usr/local/share/pwlib"
+ PWLIB_INCDIR="/usr/local/include"
+ PWLIB_LIBDIR="/usr/local/lib"
+ fi
+
+ if test "${PWLIB_INCDIR:-unset}" = "unset"; then
+ PWLIB_INCDIR="${PWLIBDIR}/include"
+ fi
+ if test "${PWLIB_LIBDIR:-unset}" = "unset"; then
+ PWLIB_LIBDIR="${PWLIBDIR}/lib"
+ fi
+
+ AC_SUBST([PWLIBDIR])
+ AC_SUBST([PWLIB_INCDIR])
+ AC_SUBST([PWLIB_LIBDIR])
+fi
+])
+
+
+AC_DEFUN(
+[AST_CHECK_OPENH323_PLATFORM], [
+PWLIB_OSTYPE=
+case "$host_os" in
+ linux*) PWLIB_OSTYPE=linux ;
+ ;;
+ freebsd* ) PWLIB_OSTYPE=FreeBSD ;
+ ;;
+ openbsd* ) PWLIB_OSTYPE=OpenBSD ;
+ ENDLDLIBS="-lossaudio" ;
+ ;;
+ netbsd* ) PWLIB_OSTYPE=NetBSD ;
+ ENDLDLIBS="-lossaudio" ;
+ ;;
+ solaris* | sunos* ) PWLIB_OSTYPE=solaris ;
+ ;;
+ darwin* ) PWLIB_OSTYPE=Darwin ;
+ ;;
+ beos*) PWLIB_OSTYPE=beos ;
+ STDCCFLAGS="$STDCCFLAGS -D__BEOS__"
+ ;;
+ cygwin*) PWLIB_OSTYPE=cygwin ;
+ ;;
+ mingw*) PWLIB_OSTYPE=mingw ;
+ STDCCFLAGS="$STDCCFLAGS -mms-bitfields" ;
+ ENDLDLIBS="-lwinmm -lwsock32 -lsnmpapi -lmpr -lcomdlg32 -lgdi32 -lavicap32" ;
+ ;;
+ * ) PWLIB_OSTYPE="$host_os" ;
+ AC_MSG_WARN("OS $PWLIB_OSTYPE not recognized - proceed with caution!") ;
+ ;;
+esac
+
+PWLIB_MACHTYPE=
+case "$host_cpu" in
+ x86 | i686 | i586 | i486 | i386 ) PWLIB_MACHTYPE=x86
+ ;;
+
+ x86_64) PWLIB_MACHTYPE=x86_64 ;
+ P_64BIT=1 ;
+ LIB64=1 ;
+ ;;
+
+ alpha | alphaev56 | alphaev6 | alphaev67 | alphaev7) PWLIB_MACHTYPE=alpha ;
+ P_64BIT=1 ;
+ ;;
+
+ sparc ) PWLIB_MACHTYPE=sparc ;
+ ;;
+
+ powerpc ) PWLIB_MACHTYPE=ppc ;
+ ;;
+
+ ppc ) PWLIB_MACHTYPE=ppc ;
+ ;;
+
+ powerpc64 ) PWLIB_MACHTYPE=ppc64 ;
+ P_64BIT=1 ;
+ LIB64=1 ;
+ ;;
+
+ ppc64 ) PWLIB_MACHTYPE=ppc64 ;
+ P_64BIT=1 ;
+ LIB64=1 ;
+ ;;
+
+ ia64) PWLIB_MACHTYPE=ia64 ;
+ P_64BIT=1 ;
+ ;;
+
+ s390x) PWLIB_MACHTYPE=s390x ;
+ P_64BIT=1 ;
+ LIB64=1 ;
+ ;;
+
+ s390) PWLIB_MACHTYPE=s390 ;
+ ;;
+
+ * ) PWLIB_MACHTYPE="$host_cpu";
+ AC_MSG_WARN("CPU $PWLIB_MACHTYPE not recognized - proceed with caution!") ;;
+esac
+
+PWLIB_PLATFORM="${PWLIB_OSTYPE}_${PWLIB_MACHTYPE}"
+
+AC_SUBST([PWLIB_PLATFORM])
+])
+
+
+AC_DEFUN(
+[AST_CHECK_OPENH323], [
+OPENH323_INCDIR=
+OPENH323_LIBDIR=
+if test "${OPENH323DIR:-unset}" != "unset" ; then
+ AC_CHECK_FILE(${OPENH323DIR}/version.h, HAS_OPENH323=1, )
+fi
+if test "${HAS_OPENH323:-unset}" = "unset" ; then
+ AC_CHECK_FILE(${PWLIBDIR}/../openh323/version.h, OPENH323DIR="${PWLIBDIR}/../openh323"; HAS_OPENH323=1, )
+ if test "${HAS_OPENH323:-unset}" != "unset" ; then
+ OPENH323DIR="${PWLIBDIR}/../openh323"
+ AC_CHECK_FILE(${OPENH323DIR}/include/h323.h, , OPENH323_INCDIR="${PWLIB_INCDIR}/openh323"; OPENH323_LIBDIR="${PWLIB_LIBDIR}")
+ else
+ AC_CHECK_FILE(${HOME}/openh323/include/h323.h, HAS_OPENH323=1, )
+ if test "${HAS_OPENH323:-unset}" != "unset" ; then
+ OPENH323DIR="${HOME}/openh323"
+ else
+ AC_CHECK_FILE(/usr/local/include/openh323/h323.h, HAS_OPENH323=1, )
+ if test "${HAS_OPENH323:-unset}" != "unset" ; then
+ OPENH323DIR="/usr/local/share/openh323"
+ OPENH323_INCDIR="/usr/local/include/openh323"
+ OPENH323_LIBDIR="/usr/local/lib"
+ else
+ AC_CHECK_FILE(/usr/include/openh323/h323.h, HAS_OPENH323=1, )
+ if test "${HAS_OPENH323:-unset}" != "unset" ; then
+ OPENH323DIR="/usr/share/openh323"
+ OPENH323_INCDIR="/usr/include/openh323"
+ OPENH323_LIBDIR="/usr/lib"
+ fi
+ fi
+ fi
+ fi
+fi
+
+if test "${HAS_OPENH323:-unset}" != "unset" ; then
+ if test "${OPENH323_INCDIR:-unset}" = "unset"; then
+ OPENH323_INCDIR="${OPENH323DIR}/include"
+ fi
+ if test "${OPENH323_LIBDIR:-unset}" = "unset"; then
+ OPENH323_LIBDIR="${OPENH323DIR}/lib"
+ fi
+
+ AC_SUBST([OPENH323DIR])
+ AC_SUBST([OPENH323_INCDIR])
+ AC_SUBST([OPENH323_LIBDIR])
+fi
+])
+
+
+AC_DEFUN(
+[AST_CHECK_PWLIB_VERSION], [
+ if test "${HAS_$2:-unset}" != "unset"; then
+ $2_VERSION=`grep "$2_VERSION" ${$2_INCDIR}/$3 | cut -f2 -d ' ' | sed -e 's/"//g'`
+ $2_MAJOR_VERSION=`echo ${$2_VERSION} | cut -f1 -d.`
+ $2_MINOR_VERSION=`echo ${$2_VERSION} | cut -f2 -d.`
+ $2_BUILD_NUMBER=`echo ${$2_VERSION} | cut -f3 -d.`
+ let $2_VER=${$2_MAJOR_VERSION}*10000+${$2_MINOR_VERSION}*100+${$2_BUILD_NUMBER}
+ let $2_REQ=$4*10000+$5*100+$6
+
+ AC_MSG_CHECKING(if $1 version ${$2_VERSION} is compatible with chan_h323)
+ if test ${$2_VER} -lt ${$2_REQ}; then
+ AC_MSG_RESULT(no)
+ unset HAS_$2
+ else
+ AC_MSG_RESULT(yes)
+ fi
+ fi
+])
+
+
+AC_DEFUN(
+[AST_CHECK_PWLIB_BUILD], [
+ if test "${HAS_$2:-unset}" != "unset"; then
+ AC_MSG_CHECKING($1 installation validity)
+
+ saved_cppflags="${CPPFLAGS}"
+ saved_libs="${LIBS}"
+ LIBS="${LIBS} -L${$2_LIBDIR} -l${PLATFORM_$2} $7"
+ CPPFLAGS="${CPPFLAGS} -I${$2_INCDIR} $6"
+
+ AC_LANG_PUSH([C++])
+
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([$4],[$5])],
+ [ AC_MSG_RESULT(yes)
+ ac_cv_lib_$2="yes"
+ ],
+ [ AC_MSG_RESULT(no)
+ ac_cv_lib_$2="no"
+ ]
+ )
+
+ AC_LANG_POP([C++])
+
+ LIBS="${saved_libs}"
+ CPPFLAGS="${saved_cppflags}"
+
+ if test "${ac_cv_lib_$2}" = "yes"; then
+ if test "${$2_LIBDIR}" != "" -a "${$2_LIBDIR}" != "/usr/lib"; then
+ $2_LIB="-L${$2_LIBDIR} -l${PLATFORM_$2}"
+ else
+ $2_LIB="-l${PLATFORM_$2}"
+ fi
+ if test "${$2_INCDIR}" != "" -a "${$2_INCDIR}" != "/usr/include"; then
+ $2_INCLUDE="-I${$2_INCDIR}"
+ fi
+ PBX_$2=1
+ AC_DEFINE([HAVE_$2], 1, [$3])
+ fi
+ fi
+])
+
+AC_DEFUN(
+[AST_CHECK_OPENH323_BUILD], [
+ if test "${HAS_OPENH323:-unset}" != "unset"; then
+ AC_MSG_CHECKING(OpenH323 build option)
+ OPENH323_SUFFIX=
+ files=`ls -l ${OPENH323_LIBDIR}/libh323_${PWLIB_PLATFORM}_*.so*`
+ libfile=
+ if test -n "$files"; then
+ for f in $files; do
+ if test -f $f -a ! -L $f; then
+ libfile=`basename $f`
+ break;
+ fi
+ done
+ fi
+ if test "${libfile:-unset}" != "unset"; then
+ OPENH323_SUFFIX=`eval "echo ${libfile} | sed -e 's/libh323_${PWLIB_PLATFORM}_\(@<:@^.@:>@*\)\..*/\1/'"`
+ fi
+ case "${OPENH323_SUFFIX}" in
+ n)
+ OPENH323_BUILD="notrace";;
+ r)
+ OPENH323_BUILD="opt";;
+ d)
+ OPENH323_BUILD="debug";;
+ *)
+ OPENH323_BUILD="notrace";;
+ esac
+ AC_MSG_RESULT(${OPENH323_BUILD})
+
+ AC_SUBST([OPENH323_SUFFIX])
+ AC_SUBST([OPENH323_BUILD])
+ fi
+])
+
+
# AST_FUNC_FORK
# -------------
AN_FUNCTION([fork], [AST_FUNC_FORK])
diff --git a/build_tools/cflags.xml b/build_tools/cflags.xml
index e7c1e4edf..7c2fbddff 100644
--- a/build_tools/cflags.xml
+++ b/build_tools/cflags.xml
@@ -7,6 +7,8 @@
</member>
<member name="DETECT_DEADLOCKS" displayname="Detect Deadlocks">
</member>
+ <member name="DO_CRASH" displayname="Crash on fatal errors">
+ </member>
<member name="DONT_OPTIMIZE" displayname="Disable Optimizations by the Compiler">
</member>
<member name="DUMP_SCHEDULER" displayname="Dump Scheduler Contents for Debugging">
diff --git a/build_tools/menuselect-deps.in b/build_tools/menuselect-deps.in
index 005e1537b..5c790e0f1 100644
--- a/build_tools/menuselect-deps.in
+++ b/build_tools/menuselect-deps.in
@@ -4,6 +4,7 @@ FREETDS=@PBX_FREETDS@
GSM=@PBX_GSM@
GTK=@PBX_GTK@
H323=@PBX_H323@
+OPENH323=@PBX_OPENH323@
IKSEMEL=@PBX_IKSEMEL@
IMAP_TK=@PBX_IMAP_TK@
IXJUSER=@PBX_IXJUSER@
diff --git a/channels/Makefile b/channels/Makefile
index 13c6b1646..b0c2bf72b 100644
--- a/channels/Makefile
+++ b/channels/Makefile
@@ -63,7 +63,20 @@ clean::
rm -f busy.h ringtone.h gentone
$(MAKE) -C misdn clean
--include $(PWD)/Makefile.ast
+ifneq ($(wildcard h323/Makefile.ast),)
+ include h323/Makefile.ast
+H323LDFLAGS += -Wl,--version-script=h323/noexport.map
+else
+h323/libchanh323.a h323/Makefile.ast:
+ $(CMD_PREFIX) $(MAKE) -C h323
+ $(CMD_PREFIX) rm -f ../main/asterisk
+ $(CMD_PREFIX) echo "***************************************************************"
+ $(CMD_PREFIX) echo
+ $(CMD_PREFIX) echo "********** Re-run 'make' to pick up H.323 parameters **********"
+ $(CMD_PREFIX) echo
+ $(CMD_PREFIX) echo "***************************************************************"
+ $(CMD_PREFIX) exit 1
+endif
$(eval $(call ast_make_final_host,gentone,gentone.c))
gentone: LIBS+=-lm
@@ -81,11 +94,13 @@ $(chan_iax2): iax2-parser.o iax2-provision.o
chan_alsa.o: busy.h ringtone.h
ifeq ($(OSARCH),linux-gnu)
-chan_h323.so: chan_h323.o h323_module_interface.so h323/libchanh323.a h323/Makefile.ast
- $(CC) $(SOLINK) $(H323LDFLAGS) -o $@ $^ h323/libchanh323.a $(H323LDLIBS) -lstdc++
+chan_h323.so: chan_h323.o h323/libchanh323.a h323/Makefile.ast
+ $(ECHO_PREFIX) echo " [LD] $^ -> $@"
+ $(CMD_PREFIX) $(CXX) $(SOLINK) $(H323LDFLAGS) -o $@ $< h323/libchanh323.a $(H323LDLIBS)
else
-chan_h323.so: chan_h323.o h323_module_interface.so h323/libchanh323.a
- $(CC) $(SOLINK) -o $@ $^ h323/libchanh323.a $(CHANH323LIB) -L$(PWLIBDIR)/lib $(PTLIB) -L$(OPENH323DIR)/lib $(H323LIB) -L/usr/lib -lcrypto -lssl -lexpat
+chan_h323.so: chan_h323.o h323/libchanh323.a
+ $(ECHO_PREFIX) echo " [LD] $^ -> $@"
+ $(CMD_PREFIX) $(CXX) $(SOLINK) -o $@ $< h323/libchanh323.a $(CHANH323LIB) -L$(PWLIBDIR)/lib $(PTLIB) -L$(OPENH323DIR)/lib $(H323LIB) -L/usr/lib -lcrypto -lssl -lexpat
endif
chan_misdn.o: CFLAGS+=-Imisdn -DCHAN_MISDN_VERSION=\"0.3.0\"
diff --git a/channels/chan_h323.c b/channels/chan_h323.c
index c4e44fddd..3b7c66da7 100644
--- a/channels/chan_h323.c
+++ b/channels/chan_h323.c
@@ -5,7 +5,7 @@
*
* OpenH323 Channel Driver for ASTERISK PBX.
* By Jeremy McNamara
- * For The NuFone Network
+ * For The NuFone Network
*
* chan_h323 has been derived from code created by
* Michael Manousos and Mark Spencer
@@ -34,12 +34,13 @@
*/
/*** MODULEINFO
- <depend>h323</depend>
+ <depend>openh323</depend>
+ <defaultenabled>no</defaultenabled>
***/
#ifdef __cplusplus
extern "C" {
-#endif
+#endif
#include "asterisk.h"
@@ -72,13 +73,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#ifdef __cplusplus
extern "C" {
-#endif
+#endif
#include "asterisk/lock.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
+#include "asterisk/musiconhold.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/utils.h"
@@ -93,6 +95,7 @@ extern "C" {
#include "asterisk/causes.h"
#include "asterisk/stringfields.h"
#include "asterisk/abstract_jb.h"
+#include "asterisk/astobj.h"
#ifdef __cplusplus
}
@@ -100,11 +103,11 @@ extern "C" {
#include "h323/chan_h323.h"
-send_digit_cb on_send_digit;
-on_rtp_cb on_external_rtp_create;
-start_rtp_cb on_start_rtp_channel;
+receive_digit_cb on_receive_digit;
+on_rtp_cb on_external_rtp_create;
+start_rtp_cb on_start_rtp_channel;
setup_incoming_cb on_incoming_call;
-setup_outbound_cb on_outgoing_call;
+setup_outbound_cb on_outgoing_call;
chan_ringing_cb on_chan_ringing;
con_established_cb on_connection_established;
clear_con_cb on_connection_cleared;
@@ -113,6 +116,7 @@ progress_cb on_progress;
rfc2833_cb on_set_rfc2833_payload;
hangup_cb on_hangup;
setcapabilities_cb on_setcapabilities;
+setpeercapabilities_cb on_setpeercapabilities;
/* global debug flag */
int h323debug;
@@ -128,7 +132,7 @@ static struct ast_jb_conf default_jbconf =
static struct ast_jb_conf global_jbconf;
/** Variables required by Asterisk */
-static const char desc[] = "The NuFone Network's Open H.323 Channel Driver";
+static const char tdesc[] = "The NuFone Network's Open H.323 Channel Driver";
static const char config[] = "h323.conf";
static char default_context[AST_MAX_CONTEXT] = "default";
static struct sockaddr_in bindaddr;
@@ -140,10 +144,10 @@ static int h323_signalling_port = 1720;
static char gatekeeper[100];
static int gatekeeper_disable = 1;
static int gatekeeper_discover = 0;
-static int usingGk = 0;
static int gkroute = 0;
/* Find user by alias (h.323 id) is default, alternative is the incomming call's source IP address*/
static int userbyalias = 1;
+static int acceptAnonymous = 1;
static int tos = 0;
static char secret[50];
static unsigned int unique = 0;
@@ -153,46 +157,53 @@ static call_options_t global_options;
/** Private structure of a OpenH323 channel */
struct oh323_pvt {
ast_mutex_t lock; /* Channel private lock */
- call_options_t options; /* Options to be used during call setup */
+ call_options_t options; /* Options to be used during call setup */
int alreadygone; /* Whether or not we've already been destroyed by our peer */
int needdestroy; /* if we need to be destroyed */
call_details_t cd; /* Call details */
- struct ast_channel *owner; /* Who owns us */
- struct sockaddr_in sa; /* Our peer */
- struct sockaddr_in redirip; /* Where our RTP should be going if not to us */
- int nonCodecCapability; /* non-audio capability */
+ struct ast_channel *owner; /* Who owns us */
+ struct sockaddr_in sa; /* Our peer */
+ struct sockaddr_in redirip; /* Where our RTP should be going if not to us */
+ int nonCodecCapability; /* non-audio capability */
int outgoing; /* Outgoing or incoming call? */
- char exten[AST_MAX_EXTENSION]; /* Requested extension */
- char context[AST_MAX_CONTEXT]; /* Context where to start */
- char accountcode[256]; /* Account code */
- char cid_num[80]; /* Caller*id number, if available */
- char cid_name[80]; /* Caller*id name, if available */
+ char exten[AST_MAX_EXTENSION]; /* Requested extension */
+ char context[AST_MAX_CONTEXT]; /* Context where to start */
+ char accountcode[256]; /* Account code */
char rdnis[80]; /* Referring DNIS, if available */
int amaflags; /* AMA Flags */
- struct ast_rtp *rtp; /* RTP Session */
- struct ast_dsp *vad; /* Used for in-band DTMF detection */
+ struct ast_rtp *rtp; /* RTP Session */
+ struct ast_dsp *vad; /* Used for in-band DTMF detection */
int nativeformats; /* Codec formats supported by a channel */
int needhangup; /* Send hangup when Asterisk is ready */
int hangupcause; /* Hangup cause from OpenH323 layer */
int newstate; /* Pending state change */
int newcontrol; /* Pending control to send */
int newdigit; /* Pending DTMF digit to send */
+ int newduration; /* Pending DTMF digit duration to send */
+ int pref_codec; /* Preferred codec */
+ int peercapability; /* Capabilities learned from peer */
+ int jointcapability; /* Common capabilities for local and remote side */
+ int dtmf_pt; /* Payload code used for RFC2833 messages */
+ int curDTMF; /* DTMF tone being generated to Asterisk side */
+ int DTMFsched; /* Scheduler descriptor for DTMF */
+ int update_rtp_info; /* Configuration of fd's array is pending */
+ int recvonly; /* Peer isn't wish to receive our voice stream */
+ int txDtmfDigit; /* DTMF digit being to send to H.323 side */
+ int noInbandDtmf; /* Inband DTMF processing by DSP isn't available */
+ int connection_established; /* Call got CONNECT message */
struct oh323_pvt *next; /* Next channel in list */
} *iflist = NULL;
static struct ast_user_list {
- struct oh323_user *users;
- ast_mutex_t lock;
+ ASTOBJ_CONTAINER_COMPONENTS(struct oh323_user);
} userl;
static struct ast_peer_list {
- struct oh323_peer *peers;
- ast_mutex_t lock;
+ ASTOBJ_CONTAINER_COMPONENTS(struct oh323_peer);
} peerl;
static struct ast_alias_list {
- struct oh323_alias *aliases;
- ast_mutex_t lock;
+ ASTOBJ_CONTAINER_COMPONENTS(struct oh323_alias);
} aliasl;
/** Asterisk RTP stuff */
@@ -214,7 +225,7 @@ AST_MUTEX_DEFINE_STATIC(h323_reload_lock);
static int h323_reloading = 0;
/* This is the thread for the monitor which checks for input on the channels
- which are not currently in use. */
+ which are not currently in use. */
static pthread_t monitor_thread = AST_PTHREADT_NULL;
static int restart_monitor(void);
static int h323_do_reload(void);
@@ -251,6 +262,76 @@ static const struct ast_channel_tech oh323_tech = {
#endif
};
+static const char* redirectingreason2str(int redirectingreason)
+{
+ switch (redirectingreason) {
+ case 0:
+ return "UNKNOWN";
+ case 1:
+ return "BUSY";
+ case 2:
+ return "NO_REPLY";
+ case 0xF:
+ return "UNCONDITIONAL";
+ default:
+ return "NOREDIRECT";
+ }
+}
+
+static void oh323_destroy_alias(struct oh323_alias *alias)
+{
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Destroying alias '%s'\n", alias->name);
+ free(alias);
+}
+
+static void oh323_destroy_user(struct oh323_user *user)
+{
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Destroying user '%s'\n", user->name);
+ ast_free_ha(user->ha);
+ free(user);
+}
+
+static void oh323_destroy_peer(struct oh323_peer *peer)
+{
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Destroying peer '%s'\n", peer->name);
+ ast_free_ha(peer->ha);
+ free(peer);
+}
+
+static int oh323_simulate_dtmf_end(void *data)
+{
+ struct oh323_pvt *pvt = data;
+
+ if (pvt) {
+ ast_mutex_lock(&pvt->lock);
+ /* Don't hold pvt lock while trying to lock the channel */
+ while(pvt->owner && ast_channel_trylock(pvt->owner)) {
+ ast_mutex_unlock(&pvt->lock);
+ usleep(1);
+ ast_mutex_lock(&pvt->lock);
+ }
+
+ if (pvt->owner) {
+ struct ast_frame f = {
+ .frametype = AST_FRAME_DTMF_END,
+ .subclass = pvt->curDTMF,
+ .samples = 0,
+ .src = "SIMULATE_DTMF_END",
+ };
+ ast_queue_frame(pvt->owner, &f);
+ ast_channel_unlock(pvt->owner);
+ }
+
+ pvt->DTMFsched = -1;
+ ast_mutex_unlock(&pvt->lock);
+ }
+
+ return 0;
+}
+
/* Channel and private structures should be already locked */
static void __oh323_update_info(struct ast_channel *c, struct oh323_pvt *pvt)
{
@@ -268,7 +349,7 @@ static void __oh323_update_info(struct ast_channel *c, struct oh323_pvt *pvt)
c->hangupcause = pvt->hangupcause;
ast_queue_hangup(c);
pvt->needhangup = 0;
- pvt->newstate = pvt->newcontrol = pvt->newdigit = -1;
+ pvt->newstate = pvt->newcontrol = pvt->newdigit = pvt->DTMFsched = -1;
}
if (pvt->newstate >= 0) {
ast_setstate(c, pvt->newstate);
@@ -280,15 +361,40 @@ static void __oh323_update_info(struct ast_channel *c, struct oh323_pvt *pvt)
}
if (pvt->newdigit >= 0) {
struct ast_frame f = {
- .frametype = AST_FRAME_DTMF,
+ .frametype = AST_FRAME_DTMF_END,
.subclass = pvt->newdigit,
- .samples = 800,
+ .samples = pvt->newduration * 8,
.src = "UPDATE_INFO",
};
-
+ if (pvt->newdigit == ' ') { /* signalUpdate message */
+ f.subclass = pvt->curDTMF;
+ if (pvt->DTMFsched >= 0) {
+ ast_sched_del(sched, pvt->DTMFsched);
+ pvt->DTMFsched = -1;
+ }
+ } else { /* Regular input or signal message */
+ if (pvt->newduration) { /* This is a signal, signalUpdate follows */
+ f.frametype = AST_FRAME_DTMF_BEGIN;
+ if (pvt->DTMFsched >= 0)
+ ast_sched_del(sched, pvt->DTMFsched);
+ pvt->DTMFsched = ast_sched_add(sched, pvt->newduration, oh323_simulate_dtmf_end, pvt);
+ if (h323debug)
+ ast_log(LOG_DTMF, "Scheduled DTMF END simulation for %d ms, id=%d\n", pvt->newduration, pvt->DTMFsched);
+ }
+ pvt->curDTMF = pvt->newdigit;
+ }
ast_queue_frame(c, &f);
pvt->newdigit = -1;
}
+ if (pvt->update_rtp_info > 0) {
+ if (pvt->rtp) {
+ ast_jb_configure(c, &global_jbconf);
+ c->fds[0] = ast_rtp_fd(pvt->rtp);
+ c->fds[1] = ast_rtcp_fd(pvt->rtp);
+ ast_queue_frame(pvt->owner, &ast_null_frame); /* Tell Asterisk to apply changes */
+ }
+ pvt->update_rtp_info = -1;
+ }
}
/* Only channel structure should be locked */
@@ -303,46 +409,55 @@ static void oh323_update_info(struct ast_channel *c)
}
}
-static void cleanup_call_details(call_details_t *cd)
-{
- if (cd->call_token) {
- free(cd->call_token);
- cd->call_token = NULL;
- }
- if (cd->call_source_aliases) {
- free(cd->call_source_aliases);
- cd->call_source_aliases = NULL;
- }
- if (cd->call_dest_alias) {
- free(cd->call_dest_alias);
- cd->call_dest_alias = NULL;
- }
- if (cd->call_source_name) {
- free(cd->call_source_name);
- cd->call_source_name = NULL;
- }
- if (cd->call_source_e164) {
- free(cd->call_source_e164);
- cd->call_source_e164 = NULL;
- }
- if (cd->call_dest_e164) {
- free(cd->call_dest_e164);
- cd->call_dest_e164 = NULL;
- }
- if (cd->sourceIp) {
- free(cd->sourceIp);
- cd->sourceIp = NULL;
- }
+static void cleanup_call_details(call_details_t *cd)
+{
+ if (cd->call_token) {
+ free(cd->call_token);
+ cd->call_token = NULL;
+ }
+ if (cd->call_source_aliases) {
+ free(cd->call_source_aliases);
+ cd->call_source_aliases = NULL;
+ }
+ if (cd->call_dest_alias) {
+ free(cd->call_dest_alias);
+ cd->call_dest_alias = NULL;
+ }
+ if (cd->call_source_name) {
+ free(cd->call_source_name);
+ cd->call_source_name = NULL;
+ }
+ if (cd->call_source_e164) {
+ free(cd->call_source_e164);
+ cd->call_source_e164 = NULL;
+ }
+ if (cd->call_dest_e164) {
+ free(cd->call_dest_e164);
+ cd->call_dest_e164 = NULL;
+ }
+ if (cd->sourceIp) {
+ free(cd->sourceIp);
+ cd->sourceIp = NULL;
+ }
+ if (cd->redirect_number) {
+ free(cd->redirect_number);
+ cd->redirect_number = NULL;
+ }
}
static void __oh323_destroy(struct oh323_pvt *pvt)
{
struct oh323_pvt *cur, *prev = NULL;
-
+
+ if (pvt->DTMFsched >= 0) {
+ ast_sched_del(sched, pvt->DTMFsched);
+ pvt->DTMFsched = -1;
+ }
+
if (pvt->rtp) {
ast_rtp_destroy(pvt->rtp);
}
-
+
/* Free dsp used for in-band DTMF detection */
if (pvt->vad) {
ast_dsp_free(pvt->vad);
@@ -351,10 +466,11 @@ static void __oh323_destroy(struct oh323_pvt *pvt)
/* Unlink us from the owner if we have one */
if (pvt->owner) {
- ast_mutex_lock(&pvt->owner->lock);
- ast_log(LOG_DEBUG, "Detaching from %s\n", pvt->owner->name);
+ ast_channel_lock(pvt->owner);
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Detaching from %s\n", pvt->owner->name);
pvt->owner->tech_pvt = NULL;
- ast_mutex_unlock(&pvt->owner->lock);
+ ast_channel_unlock(pvt->owner);
}
cur = iflist;
while(cur) {
@@ -371,6 +487,7 @@ static void __oh323_destroy(struct oh323_pvt *pvt)
if (!cur) {
ast_log(LOG_WARNING, "%p is not in list?!?! \n", cur);
} else {
+ ast_mutex_unlock(&pvt->lock);
ast_mutex_destroy(&pvt->lock);
free(pvt);
}
@@ -378,20 +495,53 @@ static void __oh323_destroy(struct oh323_pvt *pvt)
static void oh323_destroy(struct oh323_pvt *pvt)
{
+ if (h323debug) {
+ ast_log(LOG_DEBUG, "Destroying channel %s\n", (pvt->owner ? pvt->owner->name : "<unknown>"));
+ }
ast_mutex_lock(&iflock);
+ ast_mutex_lock(&pvt->lock);
__oh323_destroy(pvt);
ast_mutex_unlock(&iflock);
}
-static int oh323_digit_begin(struct ast_channel *chan, char digit)
+static int oh323_digit_begin(struct ast_channel *c, char digit)
{
- /* XXX Implement me, plz, kthx */
+ struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt;
+ char *token;
+
+ if (!pvt) {
+ ast_log(LOG_ERROR, "No private structure?! This is bad\n");
+ return -1;
+ }
+ ast_mutex_lock(&pvt->lock);
+ if (pvt->rtp && (pvt->options.dtmfmode & H323_DTMF_RFC2833) && (pvt->dtmf_pt > 0)) {
+ /* out-of-band DTMF */
+ if (h323debug) {
+ ast_log(LOG_DTMF, "Begin sending out-of-band digit %c on %s\n", digit, c->name);
+ }
+ ast_rtp_senddigit_begin(pvt->rtp, digit);
+ ast_mutex_unlock(&pvt->lock);
+ } else if (pvt->txDtmfDigit != digit) {
+ /* in-band DTMF */
+ if (h323debug) {
+ ast_log(LOG_DTMF, "Begin sending inband digit %c on %s\n", digit, c->name);
+ }
+ pvt->txDtmfDigit = digit;
+ token = pvt->cd.call_token ? strdup(pvt->cd.call_token) : NULL;
+ ast_mutex_unlock(&pvt->lock);
+ h323_send_tone(token, digit);
+ if (token) {
+ free(token);
+ }
+ } else
+ ast_mutex_unlock(&pvt->lock);
+ oh323_update_info(c);
return 0;
}
/**
* Send (play) the specified digit to the channel.
- *
+ *
*/
static int oh323_digit_end(struct ast_channel *c, char digit)
{
@@ -403,21 +553,22 @@ static int oh323_digit_end(struct ast_channel *c, char digit)
return -1;
}
ast_mutex_lock(&pvt->lock);
- if (pvt->rtp && (pvt->options.dtmfmode & H323_DTMF_RFC2833)) {
+ if (pvt->rtp && (pvt->options.dtmfmode & H323_DTMF_RFC2833) && (pvt->dtmf_pt > 0)) {
/* out-of-band DTMF */
if (h323debug) {
- ast_log(LOG_DEBUG, "Sending out-of-band digit %c on %s\n", digit, c->name);
+ ast_log(LOG_DTMF, "End sending out-of-band digit %c on %s\n", digit, c->name);
}
- ast_rtp_senddigit(pvt->rtp, digit);
+ ast_rtp_senddigit_end(pvt->rtp, digit);
ast_mutex_unlock(&pvt->lock);
} else {
/* in-band DTMF */
if (h323debug) {
- ast_log(LOG_DEBUG, "Sending inband digit %c on %s\n", digit, c->name);
+ ast_log(LOG_DTMF, "End sending inband digit %c on %s\n", digit, c->name);
}
+ pvt->txDtmfDigit = ' ';
token = pvt->cd.call_token ? strdup(pvt->cd.call_token) : NULL;
ast_mutex_unlock(&pvt->lock);
- h323_send_tone(token, digit);
+ h323_send_tone(token, ' ');
if (token) {
free(token);
}
@@ -427,15 +578,15 @@ static int oh323_digit_end(struct ast_channel *c, char digit)
}
/**
- * Make a call over the specified channel to the specified
+ * Make a call over the specified channel to the specified
* destination.
* Returns -1 on error, 0 on success.
*/
static int oh323_call(struct ast_channel *c, char *dest, int timeout)
-{
+{
int res = 0;
struct oh323_pvt *pvt = (struct oh323_pvt *)c->tech_pvt;
- char addr[INET_ADDRSTRLEN];
+ const char *addr;
char called_addr[1024];
if (h323debug) {
@@ -446,15 +597,15 @@ static int oh323_call(struct ast_channel *c, char *dest, int timeout)
return -1;
}
ast_mutex_lock(&pvt->lock);
- if (usingGk) {
+ if (!gatekeeper_disable) {
if (ast_strlen_zero(pvt->exten)) {
strncpy(called_addr, dest, sizeof(called_addr));
} else {
snprintf(called_addr, sizeof(called_addr), "%s@%s", pvt->exten, dest);
}
} else {
- ast_inet_ntoa(addr, sizeof(addr), pvt->sa.sin_addr);
res = htons(pvt->sa.sin_port);
+ addr = ast_inet_ntoa(pvt->sa.sin_addr);
if (ast_strlen_zero(pvt->exten)) {
snprintf(called_addr, sizeof(called_addr), "%s:%d", addr, res);
} else {
@@ -462,19 +613,37 @@ static int oh323_call(struct ast_channel *c, char *dest, int timeout)
}
}
/* make sure null terminated */
- called_addr[sizeof(called_addr) - 1] = '\0';
+ called_addr[sizeof(called_addr) - 1] = '\0';
- if (c->cid.cid_num) {
+ if (c->cid.cid_num)
strncpy(pvt->options.cid_num, c->cid.cid_num, sizeof(pvt->options.cid_num));
- }
- if (c->cid.cid_name) {
+
+ if (c->cid.cid_name)
strncpy(pvt->options.cid_name, c->cid.cid_name, sizeof(pvt->options.cid_name));
+
+ if (c->cid.cid_rdnis) {
+ strncpy(pvt->options.cid_rdnis, c->cid.cid_rdnis, sizeof(pvt->options.cid_rdnis));
}
+ if ((addr = pbx_builtin_getvar_helper(c, "PRIREDIRECTREASON"))) {
+ if (!strcasecmp(addr, "UNKNOWN"))
+ pvt->options.redirect_reason = 0;
+ else if (!strcasecmp(addr, "BUSY"))
+ pvt->options.redirect_reason = 1;
+ else if (!strcasecmp(addr, "NO_REPLY"))
+ pvt->options.redirect_reason = 2;
+ else if (!strcasecmp(addr, "UNCONDITIONAL"))
+ pvt->options.redirect_reason = 15;
+ else
+ pvt->options.redirect_reason = -1;
+ } else
+ pvt->options.redirect_reason = -1;
+
/* indicate that this is an outgoing call */
pvt->outgoing = 1;
- ast_log(LOG_DEBUG, "Placing outgoing call to %s, %d\n", called_addr, pvt->options.dtmfcodec);
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Placing outgoing call to %s, %d\n", called_addr, pvt->options.dtmfcodec);
ast_mutex_unlock(&pvt->lock);
res = h323_make_call(called_addr, &(pvt->cd), &pvt->options);
if (res) {
@@ -511,16 +680,15 @@ static int oh323_answer(struct ast_channel *c)
static int oh323_hangup(struct ast_channel *c)
{
struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt;
- int needcancel = 0;
int q931cause = AST_CAUSE_NORMAL_CLEARING;
char *call_token;
if (h323debug)
- ast_log(LOG_DEBUG, "Hanging up call %s\n", c->name);
+ ast_log(LOG_DEBUG, "Hanging up and scheduling destroy of call %s\n", c->name);
if (!c->tech_pvt) {
- ast_log(LOG_DEBUG, "Asked to hangup channel not connected\n");
+ ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
return 0;
}
ast_mutex_lock(&pvt->lock);
@@ -530,10 +698,7 @@ static int oh323_hangup(struct ast_channel *c)
ast_mutex_unlock(&pvt->lock);
return 0;
}
- if (!c || (c->_state != AST_STATE_UP)) {
- needcancel = 1;
- }
-
+
pvt->owner = NULL;
c->tech_pvt = NULL;
@@ -562,25 +727,25 @@ static int oh323_hangup(struct ast_channel *c)
if (call_token) {
/* Release lock to eliminate deadlock */
ast_mutex_unlock(&pvt->lock);
- if (h323_clear_call(call_token, q931cause)) {
- ast_log(LOG_DEBUG, "ClearCall failed.\n");
+ if (h323_clear_call(call_token, q931cause)) {
+ ast_log(LOG_WARNING, "ClearCall failed.\n");
}
free(call_token);
ast_mutex_lock(&pvt->lock);
}
- }
+ }
pvt->needdestroy = 1;
+ ast_mutex_unlock(&pvt->lock);
/* Update usage counter */
- ast_mutex_unlock(&pvt->lock);
- ast_atomic_fetchadd_int(&__mod_desc->usecnt, -1);
- ast_update_use_count();
+ ast_module_unref(ast_module_info->self);
+
return 0;
}
static struct ast_frame *oh323_rtp_read(struct oh323_pvt *pvt)
{
- /* Retrieve audio/etc from channel. Assumes pvt->lock is already held. */
+ /* Retrieve audio/etc from channel. Assumes pvt->lock is already held. */
struct ast_frame *f;
/* Only apply it for the first packet, we just need the correct ip/port */
@@ -599,27 +764,34 @@ static struct ast_frame *oh323_rtp_read(struct oh323_pvt *pvt)
if (f->frametype == AST_FRAME_VOICE) {
if (f->subclass != pvt->owner->nativeformats) {
/* Try to avoid deadlock */
- if (ast_mutex_trylock(&pvt->owner->lock)) {
+ if (ast_channel_trylock(pvt->owner)) {
ast_log(LOG_NOTICE, "Format changed but channel is locked. Ignoring frame...\n");
return &ast_null_frame;
}
- ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
pvt->owner->nativeformats = f->subclass;
pvt->nativeformats = f->subclass;
ast_set_read_format(pvt->owner, pvt->owner->readformat);
ast_set_write_format(pvt->owner, pvt->owner->writeformat);
- ast_mutex_unlock(&pvt->owner->lock);
- }
+ ast_channel_unlock(pvt->owner);
+ }
/* Do in-band DTMF detection */
if ((pvt->options.dtmfmode & H323_DTMF_INBAND) && pvt->vad) {
- if (!ast_mutex_trylock(&pvt->owner->lock)) {
- f = ast_dsp_process(pvt->owner,pvt->vad,f);
- ast_mutex_unlock(&pvt->owner->lock);
+ if ((pvt->nativeformats & (AST_FORMAT_SLINEAR | AST_FORMAT_ALAW | AST_FORMAT_ULAW))) {
+ if (!ast_channel_trylock(pvt->owner)) {
+ f = ast_dsp_process(pvt->owner, pvt->vad, f);
+ ast_channel_unlock(pvt->owner);
+ }
+ else
+ ast_log(LOG_NOTICE, "Unable to process inband DTMF while channel is locked\n");
+ } else if (pvt->nativeformats && !pvt->noInbandDtmf) {
+ ast_log(LOG_NOTICE, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(f->subclass));
+ pvt->noInbandDtmf = 1;
}
- else
- ast_log(LOG_NOTICE, "Unable to process inband DTMF while channel is locked\n");
if (f &&(f->frametype == AST_FRAME_DTMF)) {
- ast_log(LOG_DEBUG, "Received in-band digit %c.\n", f->subclass);
+ if (h323debug)
+ ast_log(LOG_DTMF, "Received in-band digit %c.\n", f->subclass);
}
}
}
@@ -633,7 +805,21 @@ static struct ast_frame *oh323_read(struct ast_channel *c)
struct oh323_pvt *pvt = (struct oh323_pvt *)c->tech_pvt;
ast_mutex_lock(&pvt->lock);
__oh323_update_info(c, pvt);
- fr = oh323_rtp_read(pvt);
+ switch(c->fdno) {
+ case 0:
+ fr = oh323_rtp_read(pvt);
+ break;
+ case 1:
+ if (pvt->rtp)
+ fr = ast_rtcp_read(pvt->rtp);
+ else
+ fr = &ast_null_frame;
+ break;
+ default:
+ ast_log(LOG_ERROR, "Unable to handle fd %d on channel %s\n", c->fdno, c->name);
+ fr = &ast_null_frame;
+ break;
+ }
ast_mutex_unlock(&pvt->lock);
return fr;
}
@@ -658,9 +844,8 @@ static int oh323_write(struct ast_channel *c, struct ast_frame *frame)
}
if (pvt) {
ast_mutex_lock(&pvt->lock);
- if (pvt->rtp) {
- res = ast_rtp_write(pvt->rtp, frame);
- }
+ if (pvt->rtp && !pvt->recvonly)
+ res = ast_rtp_write(pvt->rtp, frame);
__oh323_update_info(c, pvt);
ast_mutex_unlock(&pvt->lock);
}
@@ -684,10 +869,10 @@ static int oh323_indicate(struct ast_channel *c, int condition, const void *data
case AST_CONTROL_RINGING:
if (c->_state == AST_STATE_RING || c->_state == AST_STATE_RINGING) {
h323_send_alerting(token);
- break;
- }
- if (token)
- free(token);
+ break;
+ }
+ if (token)
+ free(token);
return -1;
case AST_CONTROL_PROGRESS:
if (c->_state != AST_STATE_UP) {
@@ -697,14 +882,13 @@ static int oh323_indicate(struct ast_channel *c, int condition, const void *data
if (token)
free(token);
return -1;
-
case AST_CONTROL_BUSY:
if (c->_state != AST_STATE_UP) {
h323_answering_call(token, 1);
ast_mutex_lock(&pvt->lock);
pvt->alreadygone = 1;
ast_mutex_unlock(&pvt->lock);
- ast_softhangup_nolock(c, AST_SOFTHANGUP_DEV);
+ ast_softhangup_nolock(c, AST_SOFTHANGUP_DEV);
break;
}
if (token)
@@ -767,48 +951,102 @@ static int oh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
return 0;
}
+static int __oh323_rtp_create(struct oh323_pvt *pvt)
+{
+ struct in_addr our_addr;
+
+ if (pvt->rtp)
+ return 0;
+
+ if (ast_find_ourip(&our_addr, bindaddr)) {
+ ast_mutex_unlock(&pvt->lock);
+ ast_log(LOG_ERROR, "Unable to locate local IP address for RTP stream\n");
+ return -1;
+ }
+ pvt->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, our_addr);
+ if (!pvt->rtp) {
+ ast_mutex_unlock(&pvt->lock);
+ ast_log(LOG_WARNING, "Unable to create RTP session: %s\n", strerror(errno));
+ return -1;
+ }
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Created RTP channel\n");
+
+ ast_rtp_settos(pvt->rtp, tos);
+
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", pvt->options.nat);
+ ast_rtp_setnat(pvt->rtp, pvt->options.nat);
+
+ if (pvt->dtmf_pt > 0)
+ ast_rtp_set_rtpmap_type(pvt->rtp, pvt->dtmf_pt, "audio", "telephone-event", 0);
+
+ if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
+ ast_jb_configure(pvt->owner, &global_jbconf);
+ pvt->owner->fds[0] = ast_rtp_fd(pvt->rtp);
+ pvt->owner->fds[1] = ast_rtcp_fd(pvt->rtp);
+ ast_queue_frame(pvt->owner, &ast_null_frame); /* Tell Asterisk to apply changes */
+ ast_channel_unlock(pvt->owner);
+ } else
+ pvt->update_rtp_info = 1;
+
+ return 0;
+}
+
/* Private structure should be locked on a call */
static struct ast_channel *__oh323_new(struct oh323_pvt *pvt, int state, const char *host)
{
struct ast_channel *ch;
int fmt;
-
+
/* Don't hold a oh323_pvt lock while we allocate a chanel */
ast_mutex_unlock(&pvt->lock);
ch = ast_channel_alloc(1);
/* Update usage counter */
- ast_atomic_fetchadd_int(&__mod_desc->usecnt, +1);
- ast_update_use_count();
+ ast_module_ref(ast_module_info->self);
ast_mutex_lock(&pvt->lock);
if (ch) {
ch->tech = &oh323_tech;
ast_string_field_build(ch, name, "H323/%s", host);
- ch->nativeformats = pvt->options.capability;
- if (!ch->nativeformats) {
- ch->nativeformats = global_options.capability;
- }
+ if (!(fmt = pvt->jointcapability) && !(fmt = pvt->options.capability))
+ fmt = global_options.capability;
+ ch->nativeformats = ast_codec_choose(&pvt->options.prefs, fmt, 1)/* | (pvt->jointcapability & AST_FORMAT_VIDEO_MASK)*/;
pvt->nativeformats = ch->nativeformats;
fmt = ast_best_codec(ch->nativeformats);
- ch->fds[0] = ast_rtp_fd(pvt->rtp);
- if (state == AST_STATE_RING) {
- ch->rings = 1;
- }
ch->writeformat = fmt;
ch->rawwriteformat = fmt;
ch->readformat = fmt;
ch->rawreadformat = fmt;
+#if 0
+ ch->fds[0] = ast_rtp_fd(pvt->rtp);
+ ch->fds[1] = ast_rtcp_fd(pvt->rtp);
+#endif
+#ifdef VIDEO_SUPPORT
+ if (pvt->vrtp) {
+ ch->fds[2] = ast_rtp_fd(pvt->vrtp);
+ ch->fds[3] = ast_rtcp_fd(pvt->vrtp);
+ }
+#endif
+#ifdef T38_SUPPORT
+ if (pvt->udptl) {
+ ch->fds[4] = ast_udptl_fd(pvt->udptl);
+ }
+#endif
+ if (state == AST_STATE_RING) {
+ ch->rings = 1;
+ }
/* Allocate dsp for in-band DTMF support */
if (pvt->options.dtmfmode & H323_DTMF_INBAND) {
pvt->vad = ast_dsp_new();
ast_dsp_set_features(pvt->vad, DSP_FEATURE_DTMF_DETECT);
- }
+ }
/* Register channel functions. */
ch->tech_pvt = pvt;
- /* Set the owner of this channel */
+ /* Set the owner of this channel */
pvt->owner = ch;
-
+
strncpy(ch->context, pvt->context, sizeof(ch->context) - 1);
- strncpy(ch->exten, pvt->exten, sizeof(ch->exten) - 1);
+ strncpy(ch->exten, pvt->exten, sizeof(ch->exten) - 1);
ch->priority = 1;
if (!ast_strlen_zero(pvt->accountcode)) {
ast_string_field_set(ch, accountcode, pvt->accountcode);
@@ -816,25 +1054,33 @@ static struct ast_channel *__oh323_new(struct oh323_pvt *pvt, int state, const c
if (pvt->amaflags) {
ch->amaflags = pvt->amaflags;
}
-
+
/* Don't use ast_set_callerid() here because it will
* generate a NewCallerID event before the NewChannel event */
- if (!ast_strlen_zero(pvt->cid_num)) {
- ch->cid.cid_num = ast_strdup(pvt->cid_num);
- ch->cid.cid_ani = ast_strdup(pvt->cid_num);
+ if (!ast_strlen_zero(pvt->options.cid_num)) {
+ ch->cid.cid_num = ast_strdup(pvt->options.cid_num);
+ ch->cid.cid_ani = ast_strdup(pvt->options.cid_num);
} else {
ch->cid.cid_num = ast_strdup(pvt->cd.call_source_e164);
ch->cid.cid_ani = ast_strdup(pvt->cd.call_source_e164);
}
- ch->cid.cid_name = ast_strdup(pvt->cid_name);
- ch->cid.cid_rdnis = ast_strdup(pvt->rdnis);
-
+ if (!ast_strlen_zero(pvt->options.cid_name))
+ ch->cid.cid_name = ast_strdup(pvt->options.cid_name);
+ else
+ ch->cid.cid_name = ast_strdup(pvt->cd.call_source_name);
+ if (pvt->cd.redirect_reason >= 0) {
+ ch->cid.cid_rdnis = ast_strdup(pvt->cd.redirect_number);
+ pbx_builtin_setvar_helper(ch, "PRIREDIRECTREASON", redirectingreason2str(pvt->cd.redirect_reason));
+ }
+
if (!ast_strlen_zero(pvt->exten) && strcmp(pvt->exten, "s")) {
ch->cid.cid_dnid = strdup(pvt->exten);
}
ast_setstate(ch, state);
+#if 0
if (pvt->rtp)
ast_jb_configure(ch, &global_jbconf);
+#endif
if (state != AST_STATE_DOWN) {
if (ast_pbx_start(ch)) {
ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ch->name);
@@ -842,7 +1088,7 @@ static struct ast_channel *__oh323_new(struct oh323_pvt *pvt, int state, const c
ch = NULL;
}
}
- } else {
+ } else {
ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
}
return ch;
@@ -858,6 +1104,8 @@ static struct oh323_pvt *oh323_alloc(int callid)
return NULL;
}
memset(pvt, 0, sizeof(struct oh323_pvt));
+ pvt->cd.redirect_reason = -1;
+#if 0
pvt->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0,bindaddr.sin_addr);
if (!pvt->rtp) {
ast_log(LOG_WARNING, "Unable to create RTP session: %s\n", strerror(errno));
@@ -865,25 +1113,31 @@ static struct oh323_pvt *oh323_alloc(int callid)
return NULL;
}
ast_rtp_settos(pvt->rtp, tos);
- ast_mutex_init(&pvt->lock);
- /* Ensure the call token is allocated */
- if ((pvt->cd).call_token == NULL) {
- (pvt->cd).call_token = (char *)malloc(128);
- }
- if (!pvt->cd.call_token) {
- ast_log(LOG_ERROR, "Not enough memory to alocate call token\n");
- return NULL;
+#endif
+ /* Ensure the call token is allocated for outgoing call */
+ if (!callid) {
+ if ((pvt->cd).call_token == NULL) {
+ (pvt->cd).call_token = (char *)malloc(128);
+ }
+ if (!pvt->cd.call_token) {
+ ast_log(LOG_ERROR, "Not enough memory to alocate call token\n");
+ ast_rtp_destroy(pvt->rtp);
+ free(pvt);
+ return NULL;
+ }
+ memset((char *)(pvt->cd).call_token, 0, 128);
+ pvt->cd.call_reference = callid;
}
- memset((char *)(pvt->cd).call_token, 0, 128);
- pvt->cd.call_reference = callid;
memcpy(&pvt->options, &global_options, sizeof(pvt->options));
+ pvt->jointcapability = pvt->options.capability;
if (pvt->options.dtmfmode & H323_DTMF_RFC2833) {
pvt->nonCodecCapability |= AST_RTP_DTMF;
} else {
pvt->nonCodecCapability &= ~AST_RTP_DTMF;
}
strncpy(pvt->context, default_context, sizeof(pvt->context) - 1);
- pvt->newstate = pvt->newcontrol = pvt->newdigit = -1;
+ pvt->newstate = pvt->newcontrol = pvt->newdigit = pvt->update_rtp_info = pvt->DTMFsched = -1;
+ ast_mutex_init(&pvt->lock);
/* Add to interface list */
ast_mutex_lock(&iflock);
pvt->next = iflist;
@@ -893,14 +1147,14 @@ static struct oh323_pvt *oh323_alloc(int callid)
}
static struct oh323_pvt *find_call_locked(int call_reference, const char *token)
-{
+{
struct oh323_pvt *pvt;
ast_mutex_lock(&iflock);
- pvt = iflist;
+ pvt = iflist;
while(pvt) {
if (!pvt->needdestroy && ((signed int)pvt->cd.call_reference == call_reference)) {
- /* Found the call */
+ /* Found the call */
if ((token != NULL) && (!strcmp(pvt->cd.call_token, token))) {
ast_mutex_lock(&pvt->lock);
ast_mutex_unlock(&iflock);
@@ -912,7 +1166,7 @@ static struct oh323_pvt *find_call_locked(int call_reference, const char *token)
return pvt;
}
}
- pvt = pvt->next;
+ pvt = pvt->next;
}
ast_mutex_unlock(&iflock);
return NULL;
@@ -922,11 +1176,12 @@ static int update_state(struct oh323_pvt *pvt, int state, int signal)
{
if (!pvt)
return 0;
- if (pvt->owner && !ast_mutex_trylock(&pvt->owner->lock)) {
+ if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
if (state >= 0)
ast_setstate(pvt->owner, state);
if (signal >= 0)
ast_queue_control(pvt->owner, signal);
+ ast_channel_unlock(pvt->owner);
return 1;
}
else {
@@ -938,59 +1193,408 @@ static int update_state(struct oh323_pvt *pvt, int state, int signal)
}
}
-struct oh323_user *find_user(const call_details_t *cd)
+static struct oh323_alias *build_alias(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime)
{
- struct oh323_user *u;
- char iabuf[INET_ADDRSTRLEN];
- u = userl.users;
- if (userbyalias) {
- while(u) {
- if (!strcasecmp(u->name, cd->call_source_aliases)) {
- break;
+ struct oh323_alias *alias;
+ int found = 0;
+
+ alias = ASTOBJ_CONTAINER_FIND_UNLINK_FULL(&aliasl, name, name, 0, 0, strcasecmp);
+
+ if (alias)
+ found++;
+ else {
+ if (!(alias = (struct oh323_alias *)calloc(1, sizeof(*alias))))
+ return NULL;
+ ASTOBJ_INIT(alias);
+ }
+ if (!found && name)
+ strncpy(alias->name, name, sizeof(alias->name) - 1);
+ for (; v || ((v = alt) && !(alt = NULL)); v = v->next) {
+ if (!strcasecmp(v->name, "e164")) {
+ strncpy(alias->e164, v->value, sizeof(alias->e164) - 1);
+ } else if (!strcasecmp(v->name, "prefix")) {
+ strncpy(alias->prefix, v->value, sizeof(alias->prefix) - 1);
+ } else if (!strcasecmp(v->name, "context")) {
+ strncpy(alias->context, v->value, sizeof(alias->context) - 1);
+ } else if (!strcasecmp(v->name, "secret")) {
+ strncpy(alias->secret, v->value, sizeof(alias->secret) - 1);
+ } else {
+ if (strcasecmp(v->value, "h323")) {
+ ast_log(LOG_WARNING, "Keyword %s does not make sense in type=h323\n", v->name);
}
- u = u->next;
}
- } else {
- while(u) {
- if (!strcasecmp(cd->sourceIp, ast_inet_ntoa(iabuf, sizeof(iabuf), u->addr.sin_addr))) {
- break;
- }
- u = u->next;
+ }
+ ASTOBJ_UNMARK(alias);
+ return alias;
+}
+
+static struct oh323_alias *realtime_alias(const char *alias)
+{
+ struct ast_variable *var, *tmp;
+ struct oh323_alias *a;
+
+ var = ast_load_realtime("h323", "name", alias, NULL);
+
+ if (!var)
+ return NULL;
+
+ for (tmp = var; tmp; tmp = tmp->next) {
+ if (!strcasecmp(tmp->name, "type") &&
+ !(!strcasecmp(tmp->value, "alias") || !strcasecmp(tmp->value, "h323"))) {
+ ast_variables_destroy(var);
+ return NULL;
}
}
- return u;
+
+ a = build_alias(alias, var, NULL, 1);
+
+ ast_variables_destroy(var);
+
+ return a;
}
-struct oh323_peer *find_peer(const char *peer, struct sockaddr_in *sin)
+#define DEPRECATED(_v, _new_opt) \
+ ast_log(LOG_WARNING, "Option %s found at line %d has beed deprecated. Use %s instead.\n", (_v)->name, (_v)->lineno, (_new_opt))
+
+static int update_common_options(struct ast_variable *v, struct call_options *options)
{
- struct oh323_peer *p = NULL;
- static char iabuf[INET_ADDRSTRLEN];
+ int tmp;
- p = peerl.peers;
- if (peer) {
- while(p) {
- if (!strcasecmp(p->name, peer)) {
- ast_log(LOG_DEBUG, "Found peer %s by name\n", peer);
- break;
+ if (!strcasecmp(v->name, "allow")) {
+ ast_parse_allow_disallow(&options->prefs, &options->capability, v->value, 1);
+ } else if (!strcasecmp(v->name, "disallow")) {
+ ast_parse_allow_disallow(&options->prefs, &options->capability, v->value, 0);
+ } else if (!strcasecmp(v->name, "dtmfmode")) {
+ if (!strcasecmp(v->value, "inband")) {
+ options->dtmfmode = H323_DTMF_INBAND;
+ } else if (!strcasecmp(v->value, "rfc2833")) {
+ options->dtmfmode = H323_DTMF_RFC2833;
+ } else {
+ ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value);
+ options->dtmfmode = H323_DTMF_RFC2833;
+ }
+ } else if (!strcasecmp(v->name, "dtmfcodec")) {
+ tmp = atoi(v->value);
+ if (tmp < 96)
+ ast_log(LOG_WARNING, "Invalid %s value %s at line %d\n", v->name, v->value, v->lineno);
+ else
+ options->dtmfcodec = tmp;
+ } else if (!strcasecmp(v->name, "bridge")) {
+ options->bridge = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "nat")) {
+ options->nat = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "noFastStart")) {
+ DEPRECATED(v, "fastStart");
+ options->fastStart = !ast_true(v->value);
+ } else if (!strcasecmp(v->name, "fastStart")) {
+ options->fastStart = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "noH245Tunneling")) {
+ DEPRECATED(v, "h245Tunneling");
+ options->h245Tunneling = !ast_true(v->value);
+ } else if (!strcasecmp(v->name, "h245Tunneling")) {
+ options->h245Tunneling = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "noSilenceSuppression")) {
+ DEPRECATED(v, "silenceSuppression");
+ options->silenceSuppression = !ast_true(v->value);
+ } else if (!strcasecmp(v->name, "silenceSuppression")) {
+ options->silenceSuppression = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "progress_setup")) {
+ tmp = atoi(v->value);
+ if ((tmp != 0) && (tmp != 1) && (tmp != 3) && (tmp != 8)) {
+ ast_log(LOG_WARNING, "Invalid value %s for %s at line %d, assuming 0\n", v->value, v->name, v->lineno);
+ tmp = 0;
+ }
+ options->progress_setup = tmp;
+ } else if (!strcasecmp(v->name, "progress_alert")) {
+ tmp = atoi(v->value);
+ if ((tmp != 0) && (tmp != 1) && (tmp != 8)) {
+ ast_log(LOG_WARNING, "Invalid value %s for %s at line %d, assuming 0\n", v->value, v->name, v->lineno);
+ tmp = 0;
+ }
+ options->progress_alert = tmp;
+ } else if (!strcasecmp(v->name, "progress_audio")) {
+ options->progress_audio = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "callerid")) {
+ ast_callerid_split(v->value, options->cid_name, sizeof(options->cid_name), options->cid_num, sizeof(options->cid_num));
+ } else if (!strcasecmp(v->name, "fullname")) {
+ ast_copy_string(options->cid_name, v->value, sizeof(options->cid_name));
+ } else if (!strcasecmp(v->name, "cid_number")) {
+ ast_copy_string(options->cid_num, v->value, sizeof(options->cid_num));
+ } else if (!strcasecmp(v->name, "tunneling")) {
+ if (!strcasecmp(v->value, "none"))
+ options->tunnelOptions = 0;
+ else if (!strcasecmp(v->value, "cisco"))
+ options->tunnelOptions |= H323_TUNNEL_CISCO;
+ else if (!strcasecmp(v->value, "qsig"))
+ options->tunnelOptions |= H323_TUNNEL_QSIG;
+ else
+ ast_log(LOG_WARNING, "Invalid value %s for %s at line %d\n", v->value, v->name, v->lineno);
+ } else
+ return 1;
+
+ return 0;
+}
+#undef DEPRECATED
+
+static struct oh323_user *build_user(char *name, struct ast_variable *v, struct ast_variable *alt, int realtime)
+{
+ struct oh323_user *user;
+ struct ast_ha *oldha;
+ int found = 0;
+ int format;
+
+ user = ASTOBJ_CONTAINER_FIND_UNLINK_FULL(&userl, name, name, 0, 0, strcmp);
+
+ if (user)
+ found++;
+ else {
+ if (!(user = (struct oh323_user *)calloc(1, sizeof(*user))))
+ return NULL;
+ ASTOBJ_INIT(user);
+ }
+ oldha = user->ha;
+ user->ha = (struct ast_ha *)NULL;
+ memcpy(&user->options, &global_options, sizeof(user->options));
+ /* Set default context */
+ strncpy(user->context, default_context, sizeof(user->context) - 1);
+ if (user && !found)
+ strncpy(user->name, name, sizeof(user->name) - 1);
+
+#if 0 /* XXX Port channel variables functionality from chan_sip XXX */
+ if (user->chanvars) {
+ ast_variables_destroy(user->chanvars);
+ user->chanvars = NULL;
+ }
+#endif
+
+ for (; v || ((v = alt) && !(alt = NULL)); v = v->next) {
+ if (!update_common_options(v, &user->options))
+ continue;
+ if (!strcasecmp(v->name, "context")) {
+ strncpy(user->context, v->value, sizeof(user->context) - 1);
+ } else if (!strcasecmp(v->name, "secret")) {
+ strncpy(user->secret, v->value, sizeof(user->secret) - 1);
+ } else if (!strcasecmp(v->name, "accountcode")) {
+ strncpy(user->accountcode, v->value, sizeof(user->accountcode) - 1);
+ } else if (!strcasecmp(v->name, "host")) {
+ if (!strcasecmp(v->value, "dynamic")) {
+ ast_log(LOG_ERROR, "A dynamic host on a type=user does not make any sense\n");
+ ASTOBJ_UNREF(user, oh323_destroy_user);
+ return NULL;
+ } else if (ast_get_ip(&user->addr, v->value)) {
+ ASTOBJ_UNREF(user, oh323_destroy_user);
+ return NULL;
}
- p = p->next;
+ /* Let us know we need to use ip authentication */
+ user->host = 1;
+ } else if (!strcasecmp(v->name, "amaflags")) {
+ format = ast_cdr_amaflags2int(v->value);
+ if (format < 0) {
+ ast_log(LOG_WARNING, "Invalid AMA Flags: %s at line %d\n", v->value, v->lineno);
+ } else {
+ user->amaflags = format;
+ }
+ } else if (!strcasecmp(v->name, "permit") ||
+ !strcasecmp(v->name, "deny")) {
+ user->ha = ast_append_ha(v->name, v->value, user->ha);
}
- } else {
- /* find by sin */
- if (sin) {
- while (p) {
- if ((!inaddrcmp(&p->addr, sin)) ||
- (p->addr.sin_addr.s_addr == sin->sin_addr.s_addr)) {
- ast_log(LOG_DEBUG, "Found peer %s/%s by addr\n", peer, ast_inet_ntoa(iabuf, sizeof(iabuf), p->addr.sin_addr));
- break;
- }
- p = p->next;
+ }
+ ASTOBJ_UNMARK(user);
+ ast_free_ha(oldha);
+ return user;
+}
+
+static struct oh323_user *realtime_user(const call_details_t *cd)
+{
+ struct ast_variable *var, *tmp;
+ struct oh323_user *user;
+ char *username;
+
+ if (userbyalias)
+ var = ast_load_realtime("h323", "name", username = cd->call_source_aliases, NULL);
+ else {
+ username = (char *)NULL;
+ var = ast_load_realtime("h323", "host", cd->sourceIp, NULL);
+ }
+
+ if (!var)
+ return NULL;
+
+ for (tmp = var; tmp; tmp = tmp->next) {
+ if (!strcasecmp(tmp->name, "type") &&
+ !(!strcasecmp(tmp->value, "user") || !strcasecmp(tmp->value, "friend"))) {
+ ast_variables_destroy(var);
+ return NULL;
+ } else if (!username && !strcasecmp(tmp->name, "name"))
+ username = tmp->value;
+ }
+
+ if (!username) {
+ ast_log(LOG_WARNING, "Cannot determine user name for IP address %s\n", cd->sourceIp);
+ ast_variables_destroy(var);
+ return NULL;
+ }
+
+ user = build_user(username, var, NULL, 1);
+
+ ast_variables_destroy(var);
+
+ return user;
+}
+
+static struct oh323_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime)
+{
+ struct oh323_peer *peer;
+ struct ast_ha *oldha;
+ int found = 0;
+
+ peer = ASTOBJ_CONTAINER_FIND_UNLINK_FULL(&peerl, name, name, 0, 0, strcmp);
+
+ if (peer)
+ found++;
+ else {
+ if (!(peer = (struct oh323_peer*)calloc(1, sizeof(*peer))))
+ return NULL;
+ ASTOBJ_INIT(peer);
+ }
+ oldha = peer->ha;
+ peer->ha = NULL;
+ memcpy(&peer->options, &global_options, sizeof(peer->options));
+ peer->addr.sin_port = htons(h323_signalling_port);
+ peer->addr.sin_family = AF_INET;
+ if (!found && name)
+ strncpy(peer->name, name, sizeof(peer->name) - 1);
+
+#if 0 /* XXX Port channel variables functionality from chan_sip XXX */
+ if (peer->chanvars) {
+ ast_variables_destroy(peer->chanvars);
+ peer->chanvars = NULL;
+ }
+#endif
+ /* Default settings for mailbox */
+ peer->mailbox[0] = '\0';
+
+ for (; v || ((v = alt) && !(alt = NULL)); v = v->next) {
+ if (!update_common_options(v, &peer->options))
+ continue;
+ if (!strcasecmp(v->name, "host")) {
+ if (!strcasecmp(v->value, "dynamic")) {
+ ast_log(LOG_ERROR, "Dynamic host configuration not implemented.\n");
+ ASTOBJ_UNREF(peer, oh323_destroy_peer);
+ return NULL;
+ }
+ if (ast_get_ip(&peer->addr, v->value)) {
+ ast_log(LOG_ERROR, "Could not determine IP for %s\n", v->value);
+ ASTOBJ_UNREF(peer, oh323_destroy_peer);
+ return NULL;
}
- }
+ } else if (!strcasecmp(v->name, "port")) {
+ peer->addr.sin_port = htons(atoi(v->value));
+ } else if (!strcasecmp(v->name, "permit") ||
+ !strcasecmp(v->name, "deny")) {
+ peer->ha = ast_append_ha(v->name, v->value, peer->ha);
+ } else if (!strcasecmp(v->name, "mailbox")) {
+ ast_copy_string(peer->mailbox, v->value, sizeof(peer->mailbox));
+ }
+ }
+ ASTOBJ_UNMARK(peer);
+ ast_free_ha(oldha);
+ return peer;
+}
+
+static struct oh323_peer *realtime_peer(const char *peername, struct sockaddr_in *sin)
+{
+ struct oh323_peer *peer;
+ struct ast_variable *var;
+ struct ast_variable *tmp;
+ const char *addr;
+
+ /* First check on peer name */
+ if (peername)
+ var = ast_load_realtime("h323", "name", peername, addr = NULL);
+ else if (sin) /* Then check on IP address for dynamic peers */
+ var = ast_load_realtime("h323", "host", addr = ast_inet_ntoa(sin->sin_addr), NULL);
+ else
+ return NULL;
+
+ if (!var)
+ return NULL;
+
+ for (tmp = var; tmp; tmp = tmp->next) {
+ /* If this is type=user, then skip this object. */
+ if (!strcasecmp(tmp->name, "type") &&
+ !(!strcasecmp(tmp->value, "peer") || !strcasecmp(tmp->value, "friend"))) {
+ ast_variables_destroy(var);
+ return NULL;
+ } else if (!peername && !strcasecmp(tmp->name, "name")) {
+ peername = tmp->value;
+ }
}
- if (!p) {
- ast_log(LOG_DEBUG, "Could not find peer %s by name or address\n", peer);
+
+ if (!peername) { /* Did not find peer in realtime */
+ ast_log(LOG_WARNING, "Cannot determine peer name for IP address %s\n", addr);
+ ast_variables_destroy(var);
+ return NULL;
}
+
+ /* Peer found in realtime, now build it in memory */
+ peer = build_peer(peername, var, NULL, 1);
+
+ ast_variables_destroy(var);
+
+ return peer;
+}
+
+static int oh323_addrcmp_str(struct in_addr inaddr, char *addr)
+{
+ return strcmp(ast_inet_ntoa(inaddr), addr);
+}
+
+static struct oh323_user *find_user(const call_details_t *cd, int realtime)
+{
+ struct oh323_user *u;
+
+ if (userbyalias)
+ u = ASTOBJ_CONTAINER_FIND(&userl, cd->call_source_aliases);
+ else
+ u = ASTOBJ_CONTAINER_FIND_FULL(&userl, cd->sourceIp, addr.sin_addr, 0, 0, oh323_addrcmp_str);
+
+ if (!u && realtime)
+ u = realtime_user(cd);
+
+ if (!u && h323debug)
+ ast_log(LOG_DEBUG, "Could not find user by name %s or address %s\n", cd->call_source_aliases, cd->sourceIp);
+
+ return u;
+}
+
+static int oh323_addrcmp(struct sockaddr_in addr, struct sockaddr_in *sin)
+{
+ int res;
+
+ if (!sin)
+ res = -1;
+ else
+ res = inaddrcmp(&addr , sin);
+
+ return res;
+}
+
+static struct oh323_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime)
+{
+ struct oh323_peer *p;
+
+ if (peer)
+ p = ASTOBJ_CONTAINER_FIND(&peerl, peer);
+ else
+ p = ASTOBJ_CONTAINER_FIND_FULL(&peerl, sin, addr, 0, 0, oh323_addrcmp);
+
+ if (!p && realtime)
+ p = realtime_peer(peer, sin);
+
+ if (!p && h323debug)
+ ast_log(LOG_DEBUG, "Could not find peer by name %s or address %s\n", (peer ? peer : "<NONE>"), (sin ? ast_inet_ntoa(sin->sin_addr) : "<NONE>"));
+
return p;
}
@@ -1012,15 +1616,18 @@ static int create_addr(struct oh323_pvt *pvt, char *opeer)
port++;
}
pvt->sa.sin_family = AF_INET;
- ast_mutex_lock(&peerl.lock);
- p = find_peer(peer, NULL);
+ p = find_peer(peer, NULL, 1);
if (p) {
found++;
memcpy(&pvt->options, &p->options, sizeof(pvt->options));
+ pvt->jointcapability = pvt->options.capability;
+#if 0
if (pvt->rtp) {
- ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", pvt->options.nat);
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", pvt->options.nat);
ast_rtp_setnat(pvt->rtp, pvt->options.nat);
}
+#endif
if (pvt->options.dtmfmode) {
if (pvt->options.dtmfmode & H323_DTMF_RFC2833) {
pvt->nonCodecCapability |= AST_RTP_DTMF;
@@ -1029,31 +1636,51 @@ static int create_addr(struct oh323_pvt *pvt, char *opeer)
}
}
if (p->addr.sin_addr.s_addr) {
- pvt->sa.sin_addr = p->addr.sin_addr;
- pvt->sa.sin_port = p->addr.sin_port;
- }
+ pvt->sa.sin_addr = p->addr.sin_addr;
+ pvt->sa.sin_port = p->addr.sin_port;
+ }
+ ASTOBJ_UNREF(p, oh323_destroy_peer);
}
- ast_mutex_unlock(&peerl.lock);
if (!p && !found) {
hostn = peer;
if (port) {
portno = atoi(port);
} else {
portno = h323_signalling_port;
- }
+ }
hp = ast_gethostbyname(hostn, &ahp);
if (hp) {
- memcpy(&pvt->options, &global_options, sizeof(pvt->options));
memcpy(&pvt->sa.sin_addr, hp->h_addr, sizeof(pvt->sa.sin_addr));
pvt->sa.sin_port = htons(portno);
- return 0;
+ /* Look peer by address */
+ p = find_peer(NULL, &pvt->sa, 1);
+ memcpy(&pvt->options, (p ? &p->options : &global_options), sizeof(pvt->options));
+ pvt->jointcapability = pvt->options.capability;
+ if (p) {
+ ASTOBJ_UNREF(p, oh323_destroy_peer);
+ }
+#if 0
+ if (pvt->rtp) {
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", pvt->options.nat);
+ ast_rtp_setnat(pvt->rtp, pvt->options.nat);
+ }
+#endif
+ if (pvt->options.dtmfmode) {
+ if (pvt->options.dtmfmode & H323_DTMF_RFC2833) {
+ pvt->nonCodecCapability |= AST_RTP_DTMF;
+ } else {
+ pvt->nonCodecCapability &= ~AST_RTP_DTMF;
+ }
+ }
+ return 0;
} else {
ast_log(LOG_WARNING, "No such host: %s\n", peer);
return -1;
}
- } else if (!p) {
+ } else if (!found) {
return -1;
- } else {
+ } else {
return 0;
}
}
@@ -1066,49 +1693,64 @@ static struct ast_channel *oh323_request(const char *type, int format, void *dat
char *ext, *host;
char *h323id = NULL;
char tmp[256], tmp1[256];
-
- ast_log(LOG_DEBUG, "type=%s, format=%d, data=%s.\n", type, format, (char *)data);
+
+ if (h323debug)
+ ast_log(LOG_DEBUG, "type=%s, format=%d, data=%s.\n", type, format, (char *)data);
+
pvt = oh323_alloc(0);
if (!pvt) {
ast_log(LOG_WARNING, "Unable to build pvt data for '%s'\n", (char *)data);
return NULL;
- }
+ }
oldformat = format;
format &= ((AST_FORMAT_MAX_AUDIO << 1) - 1);
if (!format) {
ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
+ oh323_destroy(pvt);
+ if (cause)
+ *cause = AST_CAUSE_INCOMPATIBLE_DESTINATION;
return NULL;
}
- strncpy(tmp, dest, sizeof(tmp) - 1);
+ strncpy(tmp, dest, sizeof(tmp) - 1);
host = strchr(tmp, '@');
if (host) {
*host = '\0';
host++;
ext = tmp;
} else {
+ ext = strrchr(tmp, '/');
+ if (ext)
+ *ext++ = '\0';
host = tmp;
- ext = NULL;
}
- strtok_r(host, "/", &(h323id));
+ strtok_r(host, "/", &(h323id));
if (!ast_strlen_zero(h323id)) {
h323_set_id(h323id);
}
if (ext) {
strncpy(pvt->exten, ext, sizeof(pvt->exten) - 1);
}
- ast_log(LOG_DEBUG, "Extension: %s Host: %s\n", pvt->exten, host);
- if (!usingGk) {
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Extension: %s Host: %s\n", pvt->exten, host);
+
+ if (gatekeeper_disable) {
if (create_addr(pvt, host)) {
oh323_destroy(pvt);
+ if (cause)
+ *cause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;
return NULL;
}
}
else {
memcpy(&pvt->options, &global_options, sizeof(pvt->options));
+ pvt->jointcapability = pvt->options.capability;
+#if 0
if (pvt->rtp) {
- ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", pvt->options.nat);
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", pvt->options.nat);
ast_rtp_setnat(pvt->rtp, pvt->options.nat);
}
+#endif
if (pvt->options.dtmfmode) {
if (pvt->options.dtmfmode & H323_DTMF_RFC2833) {
pvt->nonCodecCapability |= AST_RTP_DTMF;
@@ -1129,6 +1771,8 @@ static struct ast_channel *oh323_request(const char *type, int format, void *dat
ast_mutex_unlock(&pvt->lock);
if (!tmpc) {
oh323_destroy(pvt);
+ if (cause)
+ *cause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
}
ast_update_use_count();
restart_monitor();
@@ -1136,17 +1780,15 @@ static struct ast_channel *oh323_request(const char *type, int format, void *dat
}
/** Find a call by alias */
-struct oh323_alias *find_alias(const char *source_aliases)
+static struct oh323_alias *find_alias(const char *source_aliases, int realtime)
{
struct oh323_alias *a;
- a = aliasl.aliases;
- while(a) {
- if (!strcasecmp(a->name, source_aliases)) {
- break;
- }
- a = a->next;
- }
+ a = ASTOBJ_CONTAINER_FIND(&aliasl, source_aliases);
+
+ if (!a && realtime)
+ a = realtime_alias(source_aliases);
+
return a;
}
@@ -1154,29 +1796,56 @@ struct oh323_alias *find_alias(const char *source_aliases)
* Callback for sending digits from H.323 up to asterisk
*
*/
-int send_digit(unsigned call_reference, char digit, const char *token)
+static int receive_digit(unsigned call_reference, char digit, const char *token, int duration)
{
struct oh323_pvt *pvt;
int res;
- ast_log(LOG_DEBUG, "Received Digit: %c\n", digit);
- pvt = find_call_locked(call_reference, token);
+ pvt = find_call_locked(call_reference, token);
if (!pvt) {
- ast_log(LOG_ERROR, "Private structure not found in send_digit.\n");
+ ast_log(LOG_ERROR, "Received digit '%c' (%u ms) for call %s without private structure\n", digit, duration, token);
return -1;
}
- if (pvt->owner && !ast_mutex_trylock(&pvt->owner->lock)) {
- struct ast_frame f = {
- .frametype = AST_FRAME_DTMF,
- .subclass = digit,
- .samples = 800,
- .src = "SEND_DIGIT",
- };
-
- res = ast_queue_frame(pvt->owner, &f);
- ast_mutex_unlock(&pvt->owner->lock);
+ if (h323debug)
+ ast_log(LOG_DTMF, "Received %s digit '%c' (%u ms) for call %s\n", (digit == ' ' ? "update for" : "new"), (digit == ' ' ? pvt->curDTMF : digit), duration, token);
+
+ if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
+ if (digit == '!')
+ res = ast_queue_control(pvt->owner, AST_CONTROL_FLASH);
+ else {
+ struct ast_frame f = {
+ .frametype = AST_FRAME_DTMF_END,
+ .subclass = digit,
+ .samples = duration * 8,
+ .src = "SEND_DIGIT",
+ };
+ if (digit == ' ') { /* signalUpdate message */
+ f.subclass = pvt->curDTMF;
+ if (pvt->DTMFsched >= 0) {
+ ast_sched_del(sched, pvt->DTMFsched);
+ pvt->DTMFsched = -1;
+ }
+ } else { /* Regular input or signal message */
+ if (duration) { /* This is a signal, signalUpdate follows */
+ f.frametype = AST_FRAME_DTMF_BEGIN;
+ if (pvt->DTMFsched >= 0)
+ ast_sched_del(sched, pvt->DTMFsched);
+ pvt->DTMFsched = ast_sched_add(sched, duration, oh323_simulate_dtmf_end, pvt);
+ if (h323debug)
+ ast_log(LOG_DTMF, "Scheduled DTMF END simulation for %d ms, id=%d\n", duration, pvt->DTMFsched);
+ }
+ pvt->curDTMF = digit;
+ }
+ res = ast_queue_frame(pvt->owner, &f);
+ }
+ ast_channel_unlock(pvt->owner);
} else {
- pvt->newdigit = digit;
+ if (digit == '!')
+ pvt->newcontrol = AST_CONTROL_FLASH;
+ else {
+ pvt->newduration = duration;
+ pvt->newdigit = digit;
+ }
res = 0;
}
ast_mutex_unlock(&pvt->lock);
@@ -1188,8 +1857,8 @@ int send_digit(unsigned call_reference, char digit, const char *token)
*
* Returns the local RTP information
*/
-struct rtp_info *external_rtp_create(unsigned call_reference, const char * token)
-{
+static struct rtp_info *external_rtp_create(unsigned call_reference, const char * token)
+{
struct oh323_pvt *pvt;
struct sockaddr_in us;
struct rtp_info *info;
@@ -1199,17 +1868,26 @@ struct rtp_info *external_rtp_create(unsigned call_reference, const char * token
ast_log(LOG_ERROR, "Unable to allocated info structure, this is very bad\n");
return NULL;
}
- pvt = find_call_locked(call_reference, token);
+ pvt = find_call_locked(call_reference, token);
if (!pvt) {
free(info);
ast_log(LOG_ERROR, "Unable to find call %s(%d)\n", token, call_reference);
return NULL;
}
+ if (!pvt->rtp)
+ __oh323_rtp_create(pvt);
+ if (!pvt->rtp) {
+ ast_mutex_unlock(&pvt->lock);
+ free(info);
+ ast_log(LOG_ERROR, "No RTP stream is available for call %s (%d)", token, call_reference);
+ return NULL;
+ }
/* figure out our local RTP port and tell the H.323 stack about it */
ast_rtp_get_us(pvt->rtp, &us);
ast_mutex_unlock(&pvt->lock);
- ast_inet_ntoa(info->addr, sizeof(info->addr), us.sin_addr);
+ strncpy(info->addr, ast_inet_ntoa(us.sin_addr), sizeof(info->addr));
+ info->addr[sizeof(info->addr)-1] = '\0';
info->port = ntohs(us.sin_port);
if (h323debug)
ast_log(LOG_DEBUG, "Sending RTP 'US' %s:%d\n", info->addr, info->port);
@@ -1220,26 +1898,28 @@ struct rtp_info *external_rtp_create(unsigned call_reference, const char * token
* Definition taken from rtp.c for rtpPayloadType because we need it here.
*/
struct rtpPayloadType {
- int isAstFormat; /* whether the following code is an AST_FORMAT */
+ int isAstFormat; /* whether the following code is an AST_FORMAT */
int code;
};
/**
- * Call-back function passing remote ip/port information from H.323 to asterisk
+ * Call-back function passing remote ip/port information from H.323 to asterisk
*
- * Returns nothing
+ * Returns nothing
*/
-void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int remotePort, const char *token, int pt)
+static void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int remotePort, const char *token, int pt)
{
struct oh323_pvt *pvt;
struct sockaddr_in them;
struct rtpPayloadType rtptype;
+ int nativeformats_changed;
+ enum { NEED_NONE, NEED_HOLD, NEED_UNHOLD } rtp_change = NEED_NONE;
if (h323debug)
ast_log(LOG_DEBUG, "Setting up RTP connection for %s\n", token);
/* Find the call or allocate a private structure if call not found */
- pvt = find_call_locked(call_reference, token);
+ pvt = find_call_locked(call_reference, token);
if (!pvt) {
ast_log(LOG_ERROR, "Something is wrong: rtp\n");
return;
@@ -1248,29 +1928,78 @@ void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int rem
ast_mutex_unlock(&pvt->lock);
return;
}
- rtptype = ast_rtp_lookup_pt(pvt->rtp, pt);
- pvt->nativeformats = rtptype.code;
- if (pvt->owner && !ast_mutex_trylock(&pvt->owner->lock)) {
- pvt->owner->nativeformats = pvt->nativeformats;
- ast_set_read_format(pvt->owner, pvt->owner->readformat);
- ast_set_write_format(pvt->owner, pvt->owner->writeformat);
- if (pvt->options.progress_audio)
- ast_queue_control(pvt->owner, AST_CONTROL_PROGRESS);
- ast_mutex_unlock(&pvt->owner->lock);
- }
- else {
- if (pvt->options.progress_audio)
- pvt->newcontrol = AST_CONTROL_PROGRESS;
- if (h323debug)
- ast_log(LOG_DEBUG, "RTP connection preparation for %s is pending...\n", token);
- }
+
+ if (!pvt->rtp)
+ __oh323_rtp_create(pvt);
them.sin_family = AF_INET;
/* only works for IPv4 */
- them.sin_addr.s_addr = inet_addr(remoteIp);
+ them.sin_addr.s_addr = inet_addr(remoteIp);
them.sin_port = htons(remotePort);
- ast_rtp_set_peer(pvt->rtp, &them);
+ if (them.sin_addr.s_addr) {
+ ast_rtp_set_peer(pvt->rtp, &them);
+ if (pvt->recvonly) {
+ pvt->recvonly = 0;
+ rtp_change = NEED_UNHOLD;
+ }
+ } else {
+ ast_rtp_stop(pvt->rtp);
+ if (!pvt->recvonly) {
+ pvt->recvonly = 1;
+ rtp_change = NEED_HOLD;
+ }
+ }
+
+ /* Change native format to reflect information taken from OLC/OLCAck */
+ nativeformats_changed = 0;
+ if (pt != 128 && pvt->rtp) { /* Payload type is invalid, so try to use previously decided */
+ rtptype = ast_rtp_lookup_pt(pvt->rtp, pt);
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Native format is set to %d from %d by RTP payload type %d\n", rtptype.code, pvt->nativeformats, pt);
+ if (pvt->nativeformats != rtptype.code) {
+ pvt->nativeformats = rtptype.code;
+ nativeformats_changed = 1;
+ }
+ } else if (h323debug)
+ ast_log(LOG_NOTICE, "Payload type is unknown, formats isn't changed\n");
+
+ /* Don't try to lock the channel if nothing changed */
+ if (nativeformats_changed || pvt->options.progress_audio || (rtp_change != NEED_NONE)) {
+ if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
+ /* Re-build translation path only if native format(s) has been changed */
+ if (pvt->owner->nativeformats != pvt->nativeformats) {
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Native format changed to %d from %d, read format is %d, write format is %d\n", pvt->nativeformats, pvt->owner->nativeformats, pvt->owner->readformat, pvt->owner->writeformat);
+ pvt->owner->nativeformats = pvt->nativeformats;
+ ast_set_read_format(pvt->owner, pvt->owner->readformat);
+ ast_set_write_format(pvt->owner, pvt->owner->writeformat);
+ }
+ if (pvt->options.progress_audio)
+ ast_queue_control(pvt->owner, AST_CONTROL_PROGRESS);
+ switch (rtp_change) {
+ case NEED_HOLD:
+ ast_queue_control(pvt->owner, AST_CONTROL_HOLD);
+ break;
+ case NEED_UNHOLD:
+ ast_queue_control(pvt->owner, AST_CONTROL_UNHOLD);
+ break;
+ default:
+ break;
+ }
+ ast_channel_unlock(pvt->owner);
+ }
+ else {
+ if (pvt->options.progress_audio)
+ pvt->newcontrol = AST_CONTROL_PROGRESS;
+ else if (rtp_change == NEED_HOLD)
+ pvt->newcontrol = AST_CONTROL_HOLD;
+ else if (rtp_change == NEED_UNHOLD)
+ pvt->newcontrol = AST_CONTROL_UNHOLD;
+ if (h323debug)
+ ast_log(LOG_DEBUG, "RTP connection preparation for %s is pending...\n", token);
+ }
+ }
ast_mutex_unlock(&pvt->lock);
if (h323debug)
@@ -1279,18 +2008,18 @@ void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int rem
return;
}
-/**
- * Call-back function to signal asterisk that the channel has been answered
+/**
+ * Call-back function to signal asterisk that the channel has been answered
* Returns nothing
*/
-void connection_made(unsigned call_reference, const char *token)
+static void connection_made(unsigned call_reference, const char *token)
{
struct oh323_pvt *pvt;
if (h323debug)
ast_log(LOG_DEBUG, "Call %s answered\n", token);
- pvt = find_call_locked(call_reference, token);
+ pvt = find_call_locked(call_reference, token);
if (!pvt) {
ast_log(LOG_ERROR, "Something is wrong: connection\n");
return;
@@ -1301,17 +2030,21 @@ void connection_made(unsigned call_reference, const char *token)
ast_mutex_unlock(&pvt->lock);
return;
}
- if (update_state(pvt, AST_STATE_UP, AST_CONTROL_ANSWER))
- ast_mutex_unlock(&pvt->owner->lock);
+ /* Do not send ANSWER message more than once */
+ if (!pvt->connection_established) {
+ pvt->connection_established = 1;
+ update_state(pvt, -1, AST_CONTROL_ANSWER);
+ }
ast_mutex_unlock(&pvt->lock);
return;
}
-int progress(unsigned call_reference, const char *token, int inband)
+static int progress(unsigned call_reference, const char *token, int inband)
{
struct oh323_pvt *pvt;
- ast_log(LOG_DEBUG, "Received ALERT/PROGRESS message for %s tones\n", (inband ? "inband" : "self-generated"));
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Received ALERT/PROGRESS message for %s tones\n", (inband ? "inband" : "self-generated"));
pvt = find_call_locked(call_reference, token);
if (!pvt) {
@@ -1323,8 +2056,7 @@ int progress(unsigned call_reference, const char *token, int inband)
ast_log(LOG_ERROR, "No Asterisk channel associated with private structure.\n");
return -1;
}
- if (update_state(pvt, -1, (inband ? AST_CONTROL_PROGRESS : AST_CONTROL_RINGING)))
- ast_mutex_unlock(&pvt->owner->lock);
+ update_state(pvt, -1, (inband ? AST_CONTROL_PROGRESS : AST_CONTROL_RINGING));
ast_mutex_unlock(&pvt->lock);
return 0;
@@ -1335,12 +2067,11 @@ int progress(unsigned call_reference, const char *token, int inband)
*
* Returns 1 on success
*/
-call_options_t *setup_incoming_call(call_details_t *cd)
+static call_options_t *setup_incoming_call(call_details_t *cd)
{
struct oh323_pvt *pvt;
struct oh323_user *user = NULL;
struct oh323_alias *alias = NULL;
- char iabuf[INET_ADDRSTRLEN];
if (h323debug)
ast_log(LOG_DEBUG, "Setting up incoming call for %s\n", cd->call_token);
@@ -1350,63 +2081,74 @@ call_options_t *setup_incoming_call(call_details_t *cd)
if (!pvt) {
ast_log(LOG_ERROR, "Unable to allocate private structure, this is bad.\n");
+ cleanup_call_details(cd);
return NULL;
}
/* Populate the call details in the private structure */
memcpy(&pvt->cd, cd, sizeof(pvt->cd));
memcpy(&pvt->options, &global_options, sizeof(pvt->options));
+ pvt->jointcapability = pvt->options.capability;
if (h323debug) {
ast_verbose(VERBOSE_PREFIX_3 "Setting up Call\n");
- ast_verbose(VERBOSE_PREFIX_3 "\tCall token: [%s]\n", pvt->cd.call_token);
- ast_verbose(VERBOSE_PREFIX_3 "\tCalling party name: [%s]\n", pvt->cd.call_source_name);
- ast_verbose(VERBOSE_PREFIX_3 "\tCalling party number: [%s]\n", pvt->cd.call_source_e164);
- ast_verbose(VERBOSE_PREFIX_3 "\tCalled party name: [%s]\n", pvt->cd.call_dest_alias);
- ast_verbose(VERBOSE_PREFIX_3 "\tCalled party number: [%s]\n", pvt->cd.call_dest_e164);
+ ast_verbose(VERBOSE_PREFIX_3 " \tCall token: [%s]\n", pvt->cd.call_token);
+ ast_verbose(VERBOSE_PREFIX_3 " \tCalling party name: [%s]\n", pvt->cd.call_source_name);
+ ast_verbose(VERBOSE_PREFIX_3 " \tCalling party number: [%s]\n", pvt->cd.call_source_e164);
+ ast_verbose(VERBOSE_PREFIX_3 " \tCalled party name: [%s]\n", pvt->cd.call_dest_alias);
+ ast_verbose(VERBOSE_PREFIX_3 " \tCalled party number: [%s]\n", pvt->cd.call_dest_e164);
+ if (pvt->cd.redirect_reason >= 0)
+ ast_verbose(VERBOSE_PREFIX_3 " \tRedirecting party number: [%s] (reason %d)\n", pvt->cd.redirect_number, pvt->cd.redirect_reason);
+ ast_verbose(VERBOSE_PREFIX_3 " \tCalling party IP: [%s]\n", pvt->cd.sourceIp);
}
/* Decide if we are allowing Gatekeeper routed calls*/
- if ((!strcasecmp(cd->sourceIp, gatekeeper)) && (gkroute == -1) && (usingGk)) {
+ if ((!strcasecmp(cd->sourceIp, gatekeeper)) && (gkroute == -1) && !gatekeeper_disable) {
if (!ast_strlen_zero(cd->call_dest_e164)) {
strncpy(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten) - 1);
- strncpy(pvt->context, default_context, sizeof(pvt->context) - 1);
+ strncpy(pvt->context, default_context, sizeof(pvt->context) - 1);
} else {
- alias = find_alias(cd->call_dest_alias);
+ alias = find_alias(cd->call_dest_alias, 1);
if (!alias) {
ast_log(LOG_ERROR, "Call for %s rejected, alias not found\n", cd->call_dest_alias);
+ oh323_destroy(pvt);
return NULL;
}
strncpy(pvt->exten, alias->name, sizeof(pvt->exten) - 1);
strncpy(pvt->context, alias->context, sizeof(pvt->context) - 1);
}
} else {
- /* Either this call is not from the Gatekeeper
+ /* Either this call is not from the Gatekeeper
or we are not allowing gk routed calls */
- user = find_user(cd);
+ user = find_user(cd, 1);
if (!user) {
- if (!ast_strlen_zero(pvt->cd.call_dest_e164)) {
- strncpy(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten) - 1);
- } else {
- strncpy(pvt->exten, cd->call_dest_alias, sizeof(pvt->exten) - 1);
+ if (!acceptAnonymous) {
+ ast_log(LOG_NOTICE, "Anonymous call from '%s@%s' rejected\n", pvt->cd.call_source_aliases, pvt->cd.sourceIp);
+ oh323_destroy(pvt);
+ return NULL;
}
if (ast_strlen_zero(default_context)) {
- ast_log(LOG_ERROR, "Call from '%s' rejected due to no default context\n", pvt->cd.call_source_aliases);
+ ast_log(LOG_ERROR, "Call from '%s@%s' rejected due to no default context\n", pvt->cd.call_source_aliases, pvt->cd.sourceIp);
+ oh323_destroy(pvt);
return NULL;
}
strncpy(pvt->context, default_context, sizeof(pvt->context) - 1);
- ast_log(LOG_DEBUG, "Sending %s to context [%s]\n", cd->call_source_aliases, pvt->context);
- /* XXX: Is it really required??? */
-#if 0
- memset(&pvt->options, 0, sizeof(pvt->options));
-#endif
+ if (!ast_strlen_zero(pvt->cd.call_dest_e164)) {
+ strncpy(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten) - 1);
+ } else {
+ strncpy(pvt->exten, cd->call_dest_alias, sizeof(pvt->exten) - 1);
+ }
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Sending %s@%s to context [%s] extension %s\n", cd->call_source_aliases, cd->sourceIp, pvt->context, pvt->exten);
} else {
if (user->host) {
- if (strcasecmp(cd->sourceIp, ast_inet_ntoa(iabuf, sizeof(iabuf), user->addr.sin_addr))) {
+ if (strcasecmp(cd->sourceIp, ast_inet_ntoa(user->addr.sin_addr))) {
if (ast_strlen_zero(user->context)) {
if (ast_strlen_zero(default_context)) {
ast_log(LOG_ERROR, "Call from '%s' rejected due to non-matching IP address (%s) and no default context\n", user->name, cd->sourceIp);
- return NULL;
+ oh323_destroy(pvt);
+ ASTOBJ_UNREF(user, oh323_destroy_user);
+ return NULL;
}
strncpy(pvt->context, default_context, sizeof(pvt->context) - 1);
} else {
@@ -1415,11 +2157,14 @@ call_options_t *setup_incoming_call(call_details_t *cd)
pvt->exten[0] = 'i';
pvt->exten[1] = '\0';
ast_log(LOG_ERROR, "Call from '%s' rejected due to non-matching IP address (%s)s\n", user->name, cd->sourceIp);
+ oh323_destroy(pvt);
+ ASTOBJ_UNREF(user, oh323_destroy_user);
return NULL; /* XXX: Hmmm... Why to setup context if we drop connection immediately??? */
}
}
strncpy(pvt->context, user->context, sizeof(pvt->context) - 1);
memcpy(&pvt->options, &user->options, sizeof(pvt->options));
+ pvt->jointcapability = pvt->options.capability;
if (!ast_strlen_zero(pvt->cd.call_dest_e164)) {
strncpy(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten) - 1);
} else {
@@ -1427,11 +2172,12 @@ call_options_t *setup_incoming_call(call_details_t *cd)
}
if (!ast_strlen_zero(user->accountcode)) {
strncpy(pvt->accountcode, user->accountcode, sizeof(pvt->accountcode) - 1);
- }
+ }
if (user->amaflags) {
pvt->amaflags = user->amaflags;
- }
- }
+ }
+ ASTOBJ_UNREF(user, oh323_destroy_user);
+ }
}
return &pvt->options;
}
@@ -1445,16 +2191,64 @@ static int answer_call(unsigned call_reference, const char *token)
{
struct oh323_pvt *pvt;
struct ast_channel *c = NULL;
+ enum {ext_original, ext_s, ext_i, ext_notexists} try_exten;
+ char tmp_exten[sizeof(pvt->exten)];
if (h323debug)
ast_log(LOG_DEBUG, "Preparing Asterisk to answer for %s\n", token);
/* Find the call or allocate a private structure if call not found */
- pvt = find_call_locked(call_reference, token);
+ pvt = find_call_locked(call_reference, token);
if (!pvt) {
ast_log(LOG_ERROR, "Something is wrong: answer_call\n");
return 0;
}
+ /* Check if requested extension@context pair exists in the dialplan */
+ strncpy(tmp_exten, pvt->exten, sizeof(tmp_exten));
+
+ /* Try to find best extension in specified context */
+ if ((tmp_exten[0] != '\0') && (tmp_exten[1] == '\0')) {
+ if (tmp_exten[0] == 's')
+ try_exten = ext_s;
+ else if (tmp_exten[0] == 'i')
+ try_exten = ext_i;
+ else
+ try_exten = ext_original;
+ } else
+ try_exten = ext_original;
+ do {
+ if (ast_exists_extension(NULL, pvt->context, tmp_exten, 1, NULL))
+ break;
+ switch (try_exten) {
+ case ext_original:
+ tmp_exten[0] = 's';
+ tmp_exten[1] = '\0';
+ try_exten = ext_s;
+ break;
+ case ext_s:
+ tmp_exten[0] = 'i';
+ try_exten = ext_i;
+ break;
+ case ext_i:
+ try_exten = ext_notexists;
+ break;
+ default:
+ break;
+ }
+ } while (try_exten != ext_notexists);
+
+ /* Drop the call if we don't have <exten>, s and i extensions */
+ if (try_exten == ext_notexists) {
+ ast_log(LOG_NOTICE, "Dropping call because extensions '%s', 's' and 'i' doesn't exists in context [%s]\n", pvt->exten, pvt->context);
+ ast_mutex_unlock(&pvt->lock);
+ h323_clear_call(token, AST_CAUSE_UNALLOCATED);
+ return 0;
+ } else if ((try_exten != ext_original) && (strcmp(pvt->exten, tmp_exten) != 0)) {
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Going to extension %s@%s because %s@%s isn't exists\n", tmp_exten, pvt->context, pvt->exten, pvt->context);
+ strncpy(pvt->exten, tmp_exten, sizeof(pvt->exten));
+ }
+
/* allocate a channel and tell asterisk about it */
c = __oh323_new(pvt, AST_STATE_RINGING, pvt->cd.call_token);
@@ -1469,10 +2263,10 @@ static int answer_call(unsigned call_reference, const char *token)
/**
* Call-back function to establish an outgoing H.323 call
- *
- * Returns 1 on success
+ *
+ * Returns 1 on success
*/
-int setup_outgoing_call(call_details_t *cd)
+static int setup_outgoing_call(call_details_t *cd)
{
/* Use argument here or free it immediately */
cleanup_call_details(cd);
@@ -1484,14 +2278,14 @@ int setup_outgoing_call(call_details_t *cd)
* Call-back function to signal asterisk that the channel is ringing
* Returns nothing
*/
-void chan_ringing(unsigned call_reference, const char *token)
+static void chan_ringing(unsigned call_reference, const char *token)
{
struct oh323_pvt *pvt;
if (h323debug)
ast_log(LOG_DEBUG, "Ringing on %s\n", token);
- pvt = find_call_locked(call_reference, token);
+ pvt = find_call_locked(call_reference, token);
if (!pvt) {
ast_log(LOG_ERROR, "Something is wrong: ringing\n");
return;
@@ -1501,8 +2295,7 @@ void chan_ringing(unsigned call_reference, const char *token)
ast_log(LOG_ERROR, "Channel has no owner\n");
return;
}
- if (update_state(pvt, AST_STATE_RINGING, AST_CONTROL_RINGING))
- ast_mutex_unlock(&pvt->owner->lock);
+ update_state(pvt, AST_STATE_RINGING, AST_CONTROL_RINGING);
ast_mutex_unlock(&pvt->lock);
return;
}
@@ -1512,19 +2305,20 @@ void chan_ringing(unsigned call_reference, const char *token)
* Returns nothing,
*/
static void cleanup_connection(unsigned call_reference, const char *call_token)
-{
+{
struct oh323_pvt *pvt;
- ast_log(LOG_DEBUG, "Cleaning connection to %s\n", call_token);
-
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Cleaning connection to %s\n", call_token);
+
while (1) {
- pvt = find_call_locked(call_reference, call_token);
+ pvt = find_call_locked(call_reference, call_token);
if (!pvt) {
if (h323debug)
ast_log(LOG_DEBUG, "No connection for %s\n", call_token);
return;
}
- if (!pvt->owner || !ast_mutex_trylock(&pvt->owner->lock))
+ if (!pvt->owner || !ast_channel_trylock(pvt->owner))
break;
#if 1
#ifdef DEBUG_THREADS
@@ -1548,43 +2342,49 @@ static void cleanup_connection(unsigned call_reference, const char *call_token)
}
cleanup_call_details(&pvt->cd);
pvt->alreadygone = 1;
- /* Send hangup */
+ /* Send hangup */
if (pvt->owner) {
pvt->owner->_softhangup |= AST_SOFTHANGUP_DEV;
ast_queue_hangup(pvt->owner);
- ast_mutex_unlock(&pvt->owner->lock);
+ ast_channel_unlock(pvt->owner);
}
ast_mutex_unlock(&pvt->lock);
if (h323debug)
ast_log(LOG_DEBUG, "Connection to %s cleaned\n", call_token);
- return;
+ return;
}
static void hangup_connection(unsigned int call_reference, const char *token, int cause)
{
struct oh323_pvt *pvt;
- ast_log(LOG_DEBUG, "Hanging up connection to %s with cause %d\n", token, cause);
-
- pvt = find_call_locked(call_reference, token);
+ if (h323debug) {
+ ast_log(LOG_DEBUG, "Hanging up connection to %s with cause %d\n", token, cause);
+ }
+
+ pvt = find_call_locked(call_reference, token);
if (!pvt) {
+ if (h323debug) {
+ ast_log(LOG_DEBUG, "Connection to %s already cleared\n", token);
+ }
return;
}
- if (pvt->owner && !ast_mutex_trylock(&pvt->owner->lock)) {
+ if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
pvt->owner->_softhangup |= AST_SOFTHANGUP_DEV;
pvt->owner->hangupcause = pvt->hangupcause = cause;
ast_queue_hangup(pvt->owner);
- ast_mutex_unlock(&pvt->owner->lock);
+ ast_channel_unlock(pvt->owner);
}
else {
pvt->needhangup = 1;
pvt->hangupcause = cause;
- ast_log(LOG_DEBUG, "Hangup for %s is pending\n", token);
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Hangup for %s is pending\n", token);
}
ast_mutex_unlock(&pvt->lock);
}
-void set_dtmf_payload(unsigned call_reference, const char *token, int payload)
+static void set_dtmf_payload(unsigned call_reference, const char *token, int payload)
{
struct oh323_pvt *pvt;
@@ -1596,17 +2396,34 @@ void set_dtmf_payload(unsigned call_reference, const char *token, int payload)
return;
}
if (pvt->rtp) {
- ast_rtp_set_rtpmap_type(pvt->rtp, payload, "audio", "telephone-event");
+ ast_rtp_set_rtpmap_type(pvt->rtp, payload, "audio", "telephone-event", 0);
}
+ pvt->dtmf_pt = payload;
ast_mutex_unlock(&pvt->lock);
if (h323debug)
ast_log(LOG_DEBUG, "DTMF payload on %s set to %d\n", token, payload);
}
+static void set_peer_capabilities(unsigned call_reference, const char *token, int capabilities)
+{
+ struct oh323_pvt *pvt;
+
+ if (h323debug)
+ ast_log(LOG_DEBUG, "Got remote capabilities from connection %s\n", token);
+
+ pvt = find_call_locked(call_reference, token);
+ if (!pvt)
+ return;
+ pvt->peercapability = capabilities;
+ pvt->jointcapability = pvt->options.capability & capabilities;
+ ast_mutex_unlock(&pvt->lock);
+}
+
static void set_local_capabilities(unsigned call_reference, const char *token)
{
struct oh323_pvt *pvt;
- int capability, dtmfmode;
+ int capability, dtmfmode, pref_codec;
+ struct ast_codec_pref prefs;
if (h323debug)
ast_log(LOG_DEBUG, "Setting capabilities for connection %s\n", token);
@@ -1614,10 +2431,12 @@ static void set_local_capabilities(unsigned call_reference, const char *token)
pvt = find_call_locked(call_reference, token);
if (!pvt)
return;
- capability = pvt->options.capability;
+ capability = (pvt->jointcapability) ? pvt->jointcapability : pvt->options.capability;
dtmfmode = pvt->options.dtmfmode;
+ prefs = pvt->options.prefs;
+ pref_codec = pvt->pref_codec;
ast_mutex_unlock(&pvt->lock);
- h323_set_capabilities(token, capability, dtmfmode);
+ h323_set_capabilities(token, capability, dtmfmode, &prefs, pref_codec);
if (h323debug)
ast_log(LOG_DEBUG, "Capabilities for connection %s is set\n", token);
@@ -1628,7 +2447,7 @@ static void *do_monitor(void *data)
int res;
int reloading;
struct oh323_pvt *oh323 = NULL;
-
+
for(;;) {
/* Check for a reload request */
ast_mutex_lock(&h323_reload_lock);
@@ -1643,15 +2462,32 @@ static void *do_monitor(void *data)
}
/* Check for interfaces needing to be killed */
ast_mutex_lock(&iflock);
-restartsearch:
+#if 1
+ do {
+ for (oh323 = iflist; oh323; oh323 = oh323->next) {
+ if (!ast_mutex_trylock(&oh323->lock)) {
+ if (oh323->needdestroy) {
+ __oh323_destroy(oh323);
+ break;
+ }
+ ast_mutex_unlock(&oh323->lock);
+ }
+ }
+ } while (/*oh323*/ 0);
+#else
+restartsearch:
oh323 = iflist;
while(oh323) {
- if (oh323->needdestroy) {
- __oh323_destroy(oh323);
- goto restartsearch;
+ if (!ast_mutex_trylock(&oh323->lock)) {
+ if (oh323->needdestroy) {
+ __oh323_destroy(oh323);
+ goto restartsearch;
+ }
+ ast_mutex_unlock(&oh323->lock);
+ oh323 = oh323->next;
}
- oh323 = oh323->next;
}
+#endif
ast_mutex_unlock(&iflock);
pthread_testcancel();
/* Wait for sched or io */
@@ -1659,6 +2495,9 @@ restartsearch:
if ((res < 0) || (res > 1000)) {
res = 1000;
}
+ /* Do not wait if some channel(s) is destroyed, probably, more available too */
+ if (oh323)
+ res = 1;
res = ast_io_wait(io, res);
pthread_testcancel();
ast_mutex_lock(&monlock);
@@ -1675,13 +2514,14 @@ static int restart_monitor(void)
{
pthread_attr_t attr;
/* If we're supposed to be stopped -- stay stopped */
- if (monitor_thread == AST_PTHREADT_STOP) {
- return 0;
- }
if (ast_mutex_lock(&monlock)) {
ast_log(LOG_WARNING, "Unable to lock monitor\n");
return -1;
}
+ if (monitor_thread == AST_PTHREADT_STOP) {
+ ast_mutex_unlock(&monlock);
+ return 0;
+ }
if (monitor_thread == pthread_self()) {
ast_mutex_unlock(&monlock);
ast_log(LOG_WARNING, "Cannot kill myself\n");
@@ -1690,16 +2530,16 @@ static int restart_monitor(void)
if (monitor_thread && (monitor_thread != AST_PTHREADT_NULL)) {
/* Wake up the thread */
pthread_kill(monitor_thread, SIGURG);
- } else {
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- /* Start a new monitor */
- if (ast_pthread_create(&monitor_thread, &attr, do_monitor, NULL) < 0) {
- ast_mutex_unlock(&monlock);
- ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
- return -1;
- }
-
+ } else {
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ /* Start a new monitor */
+ if (ast_pthread_create(&monitor_thread, &attr, do_monitor, NULL) < 0) {
+ monitor_thread = AST_PTHREADT_NULL;
+ ast_mutex_unlock(&monlock);
+ ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
+ return -1;
+ }
}
ast_mutex_unlock(&monlock);
return 0;
@@ -1731,7 +2571,7 @@ static int h323_do_debug(int fd, int argc, char *argv[])
return RESULT_SHOWUSAGE;
}
h323debug = 1;
- ast_cli(fd, "H323 debug enabled\n");
+ ast_cli(fd, "H.323 debug enabled\n");
return RESULT_SUCCESS;
}
@@ -1741,36 +2581,34 @@ static int h323_no_debug(int fd, int argc, char *argv[])
return RESULT_SHOWUSAGE;
}
h323debug = 0;
- ast_cli(fd, "H323 Debug disabled\n");
+ ast_cli(fd, "H.323 debug disabled\n");
return RESULT_SUCCESS;
}
static int h323_gk_cycle(int fd, int argc, char *argv[])
{
-#if 0
if (argc != 3) {
return RESULT_SHOWUSAGE;
- }
+ }
h323_gk_urq();
-
+
/* Possibly register with a GK */
if (!gatekeeper_disable) {
if (h323_set_gk(gatekeeper_discover, gatekeeper, secret)) {
ast_log(LOG_ERROR, "Gatekeeper registration failed.\n");
}
}
-#endif
return RESULT_SUCCESS;
}
static int h323_ep_hangup(int fd, int argc, char *argv[])
{
- if (argc != 3) {
- return RESULT_SHOWUSAGE;
+ if (argc != 3) {
+ return RESULT_SHOWUSAGE;
}
if (h323_soft_hangup(argv[2])) {
ast_verbose(VERBOSE_PREFIX_3 "Hangup succeeded on %s\n", argv[2]);
- } else {
+ } else {
ast_verbose(VERBOSE_PREFIX_3 "Hangup failed for %s\n", argv[2]);
}
return RESULT_SUCCESS;
@@ -1778,50 +2616,46 @@ static int h323_ep_hangup(int fd, int argc, char *argv[])
static int h323_tokens_show(int fd, int argc, char *argv[])
{
- if (argc != 3) {
- return RESULT_SHOWUSAGE;
+ if (argc != 3) {
+ return RESULT_SHOWUSAGE;
}
h323_show_tokens();
return RESULT_SUCCESS;
}
-static char trace_usage[] =
+static char trace_usage[] =
"Usage: h.323 trace <level num>\n"
" Enables H.323 stack tracing for debugging purposes\n";
-static char no_trace_usage[] =
+static char no_trace_usage[] =
"Usage: h.323 no trace\n"
" Disables H.323 stack tracing for debugging purposes\n";
-static char debug_usage[] =
+static char debug_usage[] =
"Usage: h.323 debug\n"
" Enables H.323 debug output\n";
-static char no_debug_usage[] =
+static char no_debug_usage[] =
"Usage: h.323 no debug\n"
" Disables H.323 debug output\n";
-static char show_codec_usage[] =
-"Usage: h.323 show codec\n"
-" Shows all enabled codecs\n";
-
-static char show_cycle_usage[] =
+static char show_cycle_usage[] =
"Usage: h.323 gk cycle\n"
" Manually re-register with the Gatekeper (Currently Disabled)\n";
-static char show_hangup_usage[] =
+static char show_hangup_usage[] =
"Usage: h.323 hangup <token>\n"
" Manually try to hang up call identified by <token>\n";
-static char show_tokens_usage[] =
+static char show_tokens_usage[] =
"Usage: h.323 show tokens\n"
" Print out all active call tokens\n";
static char h323_reload_usage[] =
"Usage: h323 reload\n"
-" Reloads H.323 configuration from sip.conf\n";
+" Reloads H.323 configuration from h323.conf\n";
-static struct ast_cli_entry cli_h323[] = {
+static struct ast_cli_entry cli_h323[] = {
{ { "h.323", "trace", NULL },
h323_do_trace, "Enable H.323 Stack Tracing",
trace_usage },
@@ -1838,10 +2672,6 @@ static struct ast_cli_entry cli_h323[] = {
h323_no_debug, "Disable H.323 debug",
no_debug_usage },
- { { "h.323", "show", "codecs", NULL },
- h323_show_codec, "Show enabled codecs",
- show_codec_usage },
-
{ { "h.323", "gk", "cycle", NULL },
h323_gk_cycle, "Manually re-register with the Gatekeper",
show_cycle_usage },
@@ -1853,232 +2683,23 @@ static struct ast_cli_entry cli_h323[] = {
{ { "h.323", "show", "tokens", NULL },
h323_tokens_show, "Show all active call tokens",
show_tokens_usage },
-
- { { "h.323", "reload", NULL },
- h323_reload, "Reload H.323 configuration",
- h323_reload_usage },
};
-static int update_common_options(struct ast_variable *v, struct call_options *options)
-{
- unsigned int format;
- int tmp;
-
- if (!strcasecmp(v->name, "allow")) {
- format = ast_getformatbyname(v->value);
- if (format < 1)
- ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
- else
- options->capability |= format;
- } else if (!strcasecmp(v->name, "disallow")) {
- format = ast_getformatbyname(v->value);
- if (format < 1)
- ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
- else
- options->capability &= ~format;
- } else if (!strcasecmp(v->name, "dtmfmode")) {
- if (!strcasecmp(v->value, "inband")) {
- options->dtmfmode = H323_DTMF_INBAND;
- } else if (!strcasecmp(v->value, "rfc2833")) {
- options->dtmfmode = H323_DTMF_RFC2833;
- } else {
- ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value);
- options->dtmfmode = H323_DTMF_RFC2833;
- }
- } else if (!strcasecmp(v->name, "dtmfcodec")) {
- tmp = atoi(v->value);
- if (tmp < 96)
- ast_log(LOG_WARNING, "Invalid global dtmfcodec value %s\n", v->value);
- else
- options->dtmfcodec = tmp;
- } else if (!strcasecmp(v->name, "bridge")) {
- options->bridge = ast_true(v->value);
- } else if (!strcasecmp(v->name, "nat")) {
- options->nat = ast_true(v->value);
- } else if (!strcasecmp(v->name, "noFastStart")) {
- options->noFastStart = ast_true(v->value);
- } else if (!strcasecmp(v->name, "noH245Tunneling")) {
- options->noH245Tunneling = ast_true(v->value);
- } else if (!strcasecmp(v->name, "noSilenceSuppression")) {
- options->noSilenceSuppression = ast_true(v->value);
- } else if (!strcasecmp(v->name, "progress_setup")) {
- tmp = atoi(v->value);
- if ((tmp != 0) && (tmp != 1) && (tmp != 3) && (tmp != 8)) {
- ast_log(LOG_WARNING, "Invalid value %d for progress_setup at line %d, assuming 0\n", tmp, v->lineno);
- tmp = 0;
- }
- options->progress_setup = tmp;
- } else if (!strcasecmp(v->name, "progress_alert")) {
- tmp = atoi(v->value);
- if ((tmp != 0) && (tmp != 8)) {
- ast_log(LOG_WARNING, "Invalud value %d for progress_alert at line %d, assuming 0\n", tmp, v->lineno);
- tmp = 0;
- }
- options->progress_alert = tmp;
- } else if (!strcasecmp(v->name, "progress_audio")) {
- options->progress_audio = ast_true(v->value);
- } else
- return 1;
-
- return 0;
-}
-
-static struct oh323_alias *build_alias(char *name, struct ast_variable *v)
-{
- struct oh323_alias *alias;
-
- alias = (struct oh323_alias *)malloc(sizeof(struct oh323_alias));
- if (alias) {
- memset(alias, 0, sizeof(struct oh323_alias));
- strncpy(alias->name, name, sizeof(alias->name) - 1);
- while (v) {
- if (!strcasecmp(v->name, "e164")) {
- strncpy(alias->e164, v->value, sizeof(alias->e164) - 1);
- } else if (!strcasecmp(v->name, "prefix")) {
- strncpy(alias->prefix, v->value, sizeof(alias->prefix) - 1);
- } else if (!strcasecmp(v->name, "context")) {
- strncpy(alias->context, v->value, sizeof(alias->context) - 1);
- } else if (!strcasecmp(v->name, "secret")) {
- strncpy(alias->secret, v->value, sizeof(alias->secret) - 1);
- } else {
- if (strcasecmp(v->value, "h323")) {
- ast_log(LOG_WARNING, "Keyword %s does not make sense in type=h323\n", v->value);
- }
- }
- v = v->next;
- }
- }
- return alias;
-}
-
-static struct oh323_user *build_user(char *name, struct ast_variable *v)
-{
- struct oh323_user *user;
- int format;
-
- user = (struct oh323_user *)malloc(sizeof(struct oh323_user));
- if (user) {
- memset(user, 0, sizeof(struct oh323_user));
- strncpy(user->name, name, sizeof(user->name) - 1);
- memcpy(&user->options, &global_options, sizeof(user->options));
- /* Set default context */
- strncpy(user->context, default_context, sizeof(user->context) - 1);
- while(v) {
- if (!strcasecmp(v->name, "context")) {
- strncpy(user->context, v->value, sizeof(user->context) - 1);
- } else if (!update_common_options(v, &user->options)) {
- /* dummy */
- } else if (!strcasecmp(v->name, "secret")) {
- strncpy(user->secret, v->value, sizeof(user->secret) - 1);
- } else if (!strcasecmp(v->name, "callerid")) {
- strncpy(user->callerid, v->value, sizeof(user->callerid) - 1);
- } else if (!strcasecmp(v->name, "accountcode")) {
- strncpy(user->accountcode, v->value, sizeof(user->accountcode) - 1);
- } else if (!strcasecmp(v->name, "host")) {
- if (!strcasecmp(v->value, "dynamic")) {
- ast_log(LOG_ERROR, "A dynamic host on a type=user does not make any sense\n");
- free(user);
- return NULL;
- } else if (ast_get_ip(&user->addr, v->value)) {
- free(user);
- return NULL;
- }
- /* Let us know we need to use ip authentication */
- user->host = 1;
- } else if (!strcasecmp(v->name, "amaflags")) {
- format = ast_cdr_amaflags2int(v->value);
- if (format < 0) {
- ast_log(LOG_WARNING, "Invalid AMA Flags: %s at line %d\n", v->value, v->lineno);
- } else {
- user->amaflags = format;
- }
- }
- v = v->next;
- }
- }
- return user;
-}
-
-static struct oh323_peer *build_peer(char *name, struct ast_variable *v)
+static int reload_config(int is_reload)
{
- struct oh323_peer *peer;
- struct oh323_peer *prev;
- struct ast_ha *oldha = NULL;
- int found=0;
-
- prev = NULL;
- ast_mutex_lock(&peerl.lock);
- peer = peerl.peers;
-
- while(peer) {
- if (!strcasecmp(peer->name, name)) {
- break;
- }
- prev = peer;
- peer = peer->next;
- }
-
- if (peer) {
- found++;
- /* Already in the list, remove it and it will be added back (or FREE'd) */
- if (prev) {
- prev->next = peer->next;
- } else {
- peerl.peers = peer->next;
- }
- ast_mutex_unlock(&peerl.lock);
- } else {
- ast_mutex_unlock(&peerl.lock);
- peer = (struct oh323_peer*)malloc(sizeof(struct oh323_peer));
- if (peer)
- memset(peer, 0, sizeof(struct oh323_peer));
- }
- if (peer) {
- if (!found) {
- strncpy(peer->name, name, sizeof(peer->name) - 1);
- peer->addr.sin_port = htons(h323_signalling_port);
- peer->addr.sin_family = AF_INET;
- }
- oldha = peer->ha;
- peer->ha = NULL;
- peer->addr.sin_family = AF_INET;
- memcpy(&peer->options, &global_options, sizeof(peer->options));
-
- while(v) {
- if (!update_common_options(v, &peer->options)) {
- /* dummy */
- } else if (!strcasecmp(v->name, "host")) {
- if (!strcasecmp(v->value, "dynamic")) {
- ast_log(LOG_ERROR, "Dynamic host configuration not implemented.\n");
- free(peer);
- return NULL;
- }
- if (ast_get_ip(&peer->addr, v->value)) {
- ast_log(LOG_ERROR, "Could not determine IP for %s\n", v->value);
- free(peer);
- return NULL;
- }
- } else if (!strcasecmp(v->name, "port")) {
- peer->addr.sin_port = htons(atoi(v->value));
- }
- v=v->next;
- }
- }
- return peer;
-}
-
-int reload_config(void)
-{
int format;
- struct ast_config *cfg;
+ struct ast_config *cfg, *ucfg;
struct ast_variable *v;
- struct oh323_peer *peer = NULL;
- struct oh323_user *user = NULL;
+ struct oh323_peer *peer = NULL;
+ struct oh323_user *user = NULL;
struct oh323_alias *alias = NULL;
struct ast_hostent ahp; struct hostent *hp;
char *cat;
- char *utype;
-
+ char *utype;
+ int is_user, is_peer, is_alias;
+ char _gatekeeper[100];
+ int gk_discover, gk_disable, gk_changed;
+
cfg = ast_config_load(config);
/* We *must* have a config file otherwise stop immediately */
@@ -2086,30 +2707,62 @@ int reload_config(void)
ast_log(LOG_NOTICE, "Unable to load config %s, H.323 disabled\n", config);
return 1;
}
-
- /* fire up the H.323 Endpoint */
+
+ /* fire up the H.323 Endpoint */
if (!h323_end_point_exist()) {
- h323_end_point_create();
+ h323_end_point_create();
}
- h323debug = 0;
+ strncpy(_gatekeeper, gatekeeper, sizeof(_gatekeeper));
+ gk_discover = gatekeeper_discover;
+ gk_disable = gatekeeper_disable;
memset(&bindaddr, 0, sizeof(bindaddr));
memset(&global_options, 0, sizeof(global_options));
+ global_options.fastStart = 1;
+ global_options.h245Tunneling = 1;
global_options.dtmfcodec = 101;
global_options.dtmfmode = H323_DTMF_RFC2833;
global_options.capability = GLOBAL_CAPABILITY;
global_options.bridge = 1; /* Do native bridging by default */
+ strncpy(default_context, "default", sizeof(default_context) - 1);
+ h323_signalling_port = 1720;
+ gatekeeper_disable = 1;
+ gatekeeper_discover = 0;
+ gkroute = 0;
+ userbyalias = 1;
+ acceptAnonymous = 1;
+ tos = 0;
/* Copy the default jb config over global_jbconf */
memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
- v = ast_variable_browse(cfg, "general");
- while (v) {
- /* handle jb conf */
- if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
- v = v->next;
- continue;
+ /* Load configuration from users.conf */
+ ucfg = ast_config_load("users.conf");
+ if (ucfg) {
+ struct ast_variable *gen;
+ int genhas_h323;
+ char *has_h323;
+
+ genhas_h323 = ast_true(ast_variable_retrieve(ucfg, "general", "hash323"));
+ gen = ast_variable_browse(ucfg, "general");
+ for (cat = ast_category_browse(ucfg, NULL); cat; cat = ast_category_browse(ucfg, cat)) {
+ if (strcasecmp(cat, "general")) {
+ has_h323 = ast_variable_retrieve(ucfg, cat, "hash323");
+ if (ast_true(has_h323) || (!has_h323 && genhas_h323)) {
+ user = build_user(cat, gen, ast_variable_browse(ucfg, cat), 0);
+ if (user) {
+ ASTOBJ_CONTAINER_LINK(&userl, user);
+ ASTOBJ_UNREF(user, oh323_destroy_user);
+ }
+ }
+ }
}
+ ast_config_destroy(ucfg);
+ }
+ for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
+ /* handle jb conf */
+ if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
+ continue;
/* Create the interface list */
if (!strcasecmp(v->name, "port")) {
h323_signalling_port = (int)strtol(v->value, NULL, 10);
@@ -2138,14 +2791,11 @@ int reload_config(void)
} else if (!strcasecmp(v->name, "gatekeeper")) {
if (!strcasecmp(v->value, "DISABLE")) {
gatekeeper_disable = 1;
- usingGk = 0;
} else if (!strcasecmp(v->value, "DISCOVER")) {
gatekeeper_disable = 0;
gatekeeper_discover = 1;
- usingGk = 1;
} else {
gatekeeper_disable = 0;
- usingGk = 1;
strncpy(gatekeeper, v->value, sizeof(gatekeeper) - 1);
}
} else if (!strcasecmp(v->name, "secret")) {
@@ -2154,141 +2804,143 @@ int reload_config(void)
gkroute = ast_true(v->value);
} else if (!strcasecmp(v->name, "context")) {
strncpy(default_context, v->value, sizeof(default_context) - 1);
- ast_verbose(VERBOSE_PREFIX_2 "Setting default context to %s\n", default_context);
+ ast_verbose(VERBOSE_PREFIX_2 "Setting default context to %s\n", default_context);
} else if (!strcasecmp(v->name, "UserByAlias")) {
userbyalias = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "AcceptAnonymous")) {
+ acceptAnonymous = ast_true(v->value);
} else if (!update_common_options(v, &global_options)) {
/* dummy */
}
- v = v->next;
}
-
- cat = ast_category_browse(cfg, NULL);
- while(cat) {
+
+ for (cat = ast_category_browse(cfg, NULL); cat; cat = ast_category_browse(cfg, cat)) {
if (strcasecmp(cat, "general")) {
utype = ast_variable_retrieve(cfg, cat, "type");
if (utype) {
- if (!strcasecmp(utype, "user")) {
- user = build_user(cat, ast_variable_browse(cfg, cat));
- if (user) {
- ast_mutex_lock(&userl.lock);
- user->next = userl.users;
- userl.users = user;
- ast_mutex_unlock(&userl.lock);
- }
- } else if (!strcasecmp(utype, "peer")) {
- peer = build_peer(cat, ast_variable_browse(cfg, cat));
- if (peer) {
- ast_mutex_lock(&peerl.lock);
- peer->next = peerl.peers;
- peerl.peers = peer;
- ast_mutex_unlock(&peerl.lock);
- }
- } else if (!strcasecmp(utype, "friend")) {
- user = build_user(cat, ast_variable_browse(cfg, cat));
- peer = build_peer(cat, ast_variable_browse(cfg, cat));
+ is_user = is_peer = is_alias = 0;
+ if (!strcasecmp(utype, "user"))
+ is_user = 1;
+ else if (!strcasecmp(utype, "peer"))
+ is_peer = 1;
+ else if (!strcasecmp(utype, "friend"))
+ is_user = is_peer = 1;
+ else if (!strcasecmp(utype, "h323") || !strcasecmp(utype, "alias"))
+ is_alias = 1;
+ else {
+ ast_log(LOG_WARNING, "Unknown type '%s' for '%s' in %s\n", utype, cat, config);
+ continue;
+ }
+ if (is_user) {
+ user = build_user(cat, ast_variable_browse(cfg, cat), NULL, 0);
if (user) {
- ast_mutex_lock(&userl.lock);
- user->next = userl.users;
- userl.users = user;
- ast_mutex_unlock(&userl.lock);
+ ASTOBJ_CONTAINER_LINK(&userl, user);
+ ASTOBJ_UNREF(user, oh323_destroy_user);
}
+ }
+ if (is_peer) {
+ peer = build_peer(cat, ast_variable_browse(cfg, cat), NULL, 0);
if (peer) {
- ast_mutex_lock(&peerl.lock);
- peer->next = peerl.peers;
- peerl.peers = peer;
- ast_mutex_unlock(&peerl.lock);
+ ASTOBJ_CONTAINER_LINK(&peerl, peer);
+ ASTOBJ_UNREF(peer, oh323_destroy_peer);
}
- } else if (!strcasecmp(utype, "h323") || !strcasecmp(utype, "alias")) {
- alias = build_alias(cat, ast_variable_browse(cfg, cat));
+ }
+ if (is_alias) {
+ alias = build_alias(cat, ast_variable_browse(cfg, cat), NULL, 0);
if (alias) {
- ast_mutex_lock(&aliasl.lock);
- alias->next = aliasl.aliases;
- aliasl.aliases = alias;
- ast_mutex_unlock(&aliasl.lock);
+ ASTOBJ_CONTAINER_LINK(&aliasl, alias);
+ ASTOBJ_UNREF(alias, oh323_destroy_alias);
}
- } else {
- ast_log(LOG_WARNING, "Unknown type '%s' for '%s' in %s\n", utype, cat, config);
}
} else {
ast_log(LOG_WARNING, "Section '%s' lacks type\n", cat);
}
}
- cat = ast_category_browse(cfg, cat);
}
ast_config_destroy(cfg);
/* Register our H.323 aliases if any*/
- while (alias) {
- if (h323_set_alias(alias)) {
+ ASTOBJ_CONTAINER_WRLOCK(&aliasl);
+ ASTOBJ_CONTAINER_TRAVERSE(&aliasl, 1, do {
+ ASTOBJ_RDLOCK(iterator);
+ if (h323_set_alias(iterator)) {
ast_log(LOG_ERROR, "Alias %s rejected by endpoint\n", alias->name);
- return -1;
- }
- alias = alias->next;
+ ASTOBJ_UNLOCK(iterator);
+ continue;
+ }
+ ASTOBJ_UNLOCK(iterator);
+ } while (0) );
+ ASTOBJ_CONTAINER_UNLOCK(&aliasl);
+
+ /* Don't touch GK if nothing changed because URQ will drop all existing calls */
+ gk_changed = 0;
+ if (gatekeeper_disable != gk_disable)
+ gk_changed = is_reload;
+ else if(!gatekeeper_disable && (gatekeeper_discover != gk_discover))
+ gk_changed = is_reload;
+ else if(!gatekeeper_disable && (strncmp(_gatekeeper, gatekeeper, sizeof(_gatekeeper)) != 0))
+ gk_changed = is_reload;
+ if (gk_changed) {
+ if(!gk_disable)
+ h323_gk_urq();
+ if (!gatekeeper_disable) {
+ if (h323_set_gk(gatekeeper_discover, gatekeeper, secret)) {
+ ast_log(LOG_ERROR, "Gatekeeper registration failed.\n");
+ gatekeeper_disable = 1;
+ }
+ }
}
-
return 0;
}
-void delete_users(void)
+static void delete_users(void)
{
- struct oh323_user *user, *userlast;
- struct oh323_peer *peer;
-
- /* Delete all users */
- ast_mutex_lock(&userl.lock);
- for (user=userl.users;user;) {
- userlast = user;
- user=user->next;
- free(userlast);
- }
- userl.users=NULL;
- ast_mutex_unlock(&userl.lock);
- ast_mutex_lock(&peerl.lock);
- for (peer=peerl.peers;peer;) {
- /* Assume all will be deleted, and we'll find out for sure later */
- peer->delme = 1;
- peer = peer->next;
- }
- ast_mutex_unlock(&peerl.lock);
-}
+ int pruned = 0;
-void delete_aliases(void)
-{
- struct oh323_alias *alias, *aliaslast;
-
/* Delete all users */
- ast_mutex_lock(&aliasl.lock);
- for (alias=aliasl.aliases;alias;) {
- aliaslast = alias;
- alias=alias->next;
- free(aliaslast);
+ ASTOBJ_CONTAINER_WRLOCK(&userl);
+ ASTOBJ_CONTAINER_TRAVERSE(&userl, 1, do {
+ ASTOBJ_RDLOCK(iterator);
+ ASTOBJ_MARK(iterator);
+ ++pruned;
+ ASTOBJ_UNLOCK(iterator);
+ } while (0) );
+ if (pruned) {
+ ASTOBJ_CONTAINER_PRUNE_MARKED(&userl, oh323_destroy_user);
+ }
+ ASTOBJ_CONTAINER_UNLOCK(&userl);
+
+ ASTOBJ_CONTAINER_WRLOCK(&peerl);
+ ASTOBJ_CONTAINER_TRAVERSE(&peerl, 1, do {
+ ASTOBJ_RDLOCK(iterator);
+ ASTOBJ_MARK(iterator);
+ ASTOBJ_UNLOCK(iterator);
+ } while (0) );
+ ASTOBJ_CONTAINER_UNLOCK(&peerl);
+}
+
+static void delete_aliases(void)
+{
+ int pruned = 0;
+
+ /* Delete all aliases */
+ ASTOBJ_CONTAINER_WRLOCK(&aliasl);
+ ASTOBJ_CONTAINER_TRAVERSE(&aliasl, 1, do {
+ ASTOBJ_RDLOCK(iterator);
+ ASTOBJ_MARK(iterator);
+ ++pruned;
+ ASTOBJ_UNLOCK(iterator);
+ } while (0) );
+ if (pruned) {
+ ASTOBJ_CONTAINER_PRUNE_MARKED(&aliasl, oh323_destroy_alias);
}
- aliasl.aliases=NULL;
- ast_mutex_unlock(&aliasl.lock);
+ ASTOBJ_CONTAINER_UNLOCK(&aliasl);
}
-void prune_peers(void)
+static void prune_peers(void)
{
/* Prune peers who still are supposed to be deleted */
- struct oh323_peer *peer, *peerlast, *peernext;
- ast_mutex_lock(&peerl.lock);
- peerlast = NULL;
- for (peer=peerl.peers;peer;) {
- peernext = peer->next;
- if (peer->delme) {
- free(peer);
- if (peerlast) {
- peerlast->next = peernext;
- } else {
- peerl.peers = peernext;
- }
- } else {
- peerlast = peer;
- }
- peer = peernext;
- }
- ast_mutex_unlock(&peerl.lock);
+ ASTOBJ_CONTAINER_PRUNE_MARKED(&peerl, oh323_destroy_peer);
}
static int h323_reload(int fd, int argc, char *argv[])
@@ -2309,29 +2961,42 @@ static int h323_do_reload(void)
delete_users();
delete_aliases();
prune_peers();
- reload_config();
- restart_monitor();
+ reload_config(1);
return 0;
}
-static int reload(void *mod)
+static int reload(void)
{
return h323_reload(0, 0, NULL);
}
-static struct ast_rtp *oh323_get_rtp_peer(struct ast_channel *chan)
+static struct ast_cli_entry cli_h323_reload =
+ { { "h.323", "reload", NULL },
+ h323_reload, "Reload H.323 configuration",
+ h323_reload_usage
+};
+
+static enum ast_rtp_get_result oh323_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
{
struct oh323_pvt *pvt;
- pvt = (struct oh323_pvt *) chan->tech_pvt;
- if (pvt && pvt->rtp && pvt->options.bridge) {
- return pvt->rtp;
+ enum ast_rtp_get_result res = AST_RTP_GET_FAILED;
+
+ if (!(pvt = (struct oh323_pvt *)chan->tech_pvt))
+ return res;
+
+ ast_mutex_lock(&pvt->lock);
+ if (pvt->rtp && pvt->options.bridge) {
+ *rtp = pvt->rtp;
+ res = AST_RTP_TRY_NATIVE;
}
- return NULL;
+ ast_mutex_unlock(&pvt->lock);
+
+ return res;
}
-static struct ast_rtp *oh323_get_vrtp_peer(struct ast_channel *chan)
+static enum ast_rtp_get_result oh323_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
{
- return NULL;
+ return AST_RTP_GET_FAILED;
}
static char *convertcap(int cap)
@@ -2366,21 +3031,22 @@ static int oh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, str
struct sockaddr_in them;
struct sockaddr_in us;
char *mode;
- char iabuf[INET_ADDRSTRLEN];
if (!rtp) {
return 0;
}
- mode = convertcap(chan->writeformat);
+ mode = convertcap(chan->writeformat);
pvt = (struct oh323_pvt *) chan->tech_pvt;
if (!pvt) {
ast_log(LOG_ERROR, "No Private Structure, this is bad\n");
return -1;
}
- ast_rtp_get_peer(rtp, &them);
+ ast_rtp_get_peer(rtp, &them);
ast_rtp_get_us(rtp, &us);
- h323_native_bridge(pvt->cd.call_token, ast_inet_ntoa(iabuf, sizeof(iabuf), them.sin_addr), mode);
+#if 0 /* Native bridge still isn't ready */
+ h323_native_bridge(pvt->cd.call_token, ast_inet_ntoa(them.sin_addr), mode);
+#endif
return 0;
}
@@ -2388,61 +3054,93 @@ static struct ast_rtp_protocol oh323_rtp = {
.type = "H323",
.get_rtp_info = oh323_get_rtp_peer,
.get_vrtp_info = oh323_get_vrtp_peer,
- .set_rtp_peer= oh323_set_rtp_peer,
+ .set_rtp_peer = oh323_set_rtp_peer,
};
-static int load_module(void *mod)
+static enum ast_module_load_result load_module(void)
{
int res;
- ast_mutex_init(&userl.lock);
- ast_mutex_init(&peerl.lock);
- ast_mutex_init(&aliasl.lock);
+
+ h323debug = 0;
sched = sched_context_create();
if (!sched) {
ast_log(LOG_WARNING, "Unable to create schedule context\n");
+ return AST_MODULE_LOAD_FAILURE;
}
io = io_context_create();
if (!io) {
ast_log(LOG_WARNING, "Unable to create I/O context\n");
+ return AST_MODULE_LOAD_FAILURE;
}
- res = reload_config();
+ ast_cli_register(&cli_h323_reload);
+ ASTOBJ_CONTAINER_INIT(&userl);
+ ASTOBJ_CONTAINER_INIT(&peerl);
+ ASTOBJ_CONTAINER_INIT(&aliasl);
+ res = reload_config(0);
if (res) {
return AST_MODULE_LOAD_DECLINE;
} else {
/* Make sure we can register our channel type */
if (ast_channel_register(&oh323_tech)) {
ast_log(LOG_ERROR, "Unable to register channel class 'H323'\n");
+ ast_cli_unregister(&cli_h323_reload);
h323_end_process();
- return -1;
+ io_context_destroy(io);
+ sched_context_destroy(sched);
+
+ ASTOBJ_CONTAINER_DESTROYALL(&userl, oh323_destroy_user);
+ ASTOBJ_CONTAINER_DESTROY(&userl);
+ ASTOBJ_CONTAINER_DESTROYALL(&peerl, oh323_destroy_peer);
+ ASTOBJ_CONTAINER_DESTROY(&peerl);
+ ASTOBJ_CONTAINER_DESTROYALL(&aliasl, oh323_destroy_alias);
+ ASTOBJ_CONTAINER_DESTROY(&aliasl);
+
+ return AST_MODULE_LOAD_FAILURE;
}
ast_cli_register_multiple(cli_h323, sizeof(cli_h323) / sizeof(struct ast_cli_entry));
ast_rtp_proto_register(&oh323_rtp);
/* Register our callback functions */
- h323_callback_register(setup_incoming_call,
- setup_outgoing_call,
- external_rtp_create,
- setup_rtp_connection,
- cleanup_connection,
+ h323_callback_register(setup_incoming_call,
+ setup_outgoing_call,
+ external_rtp_create,
+ setup_rtp_connection,
+ cleanup_connection,
chan_ringing,
- connection_made,
- send_digit,
+ connection_made,
+ receive_digit,
answer_call,
progress,
set_dtmf_payload,
hangup_connection,
- set_local_capabilities);
+ set_local_capabilities,
+ set_peer_capabilities);
/* start the h.323 listener */
if (h323_start_listener(h323_signalling_port, bindaddr)) {
ast_log(LOG_ERROR, "Unable to create H323 listener.\n");
- return -1;
+ ast_rtp_proto_unregister(&oh323_rtp);
+ ast_cli_unregister_multiple(cli_h323, sizeof(cli_h323) / sizeof(struct ast_cli_entry));
+ ast_cli_unregister(&cli_h323_reload);
+ h323_end_process();
+ io_context_destroy(io);
+ sched_context_destroy(sched);
+
+ ASTOBJ_CONTAINER_DESTROYALL(&userl, oh323_destroy_user);
+ ASTOBJ_CONTAINER_DESTROY(&userl);
+ ASTOBJ_CONTAINER_DESTROYALL(&peerl, oh323_destroy_peer);
+ ASTOBJ_CONTAINER_DESTROY(&peerl);
+ ASTOBJ_CONTAINER_DESTROYALL(&aliasl, oh323_destroy_alias);
+ ASTOBJ_CONTAINER_DESTROY(&aliasl);
+
+ return AST_MODULE_LOAD_FAILURE;
}
/* Possibly register with a GK */
if (!gatekeeper_disable) {
if (h323_set_gk(gatekeeper_discover, gatekeeper, secret)) {
ast_log(LOG_ERROR, "Gatekeeper registration failed.\n");
- return 0;
+ gatekeeper_disable = 1;
+ return AST_MODULE_LOAD_SUCCESS;
}
}
/* And start the monitor for the first time */
@@ -2451,15 +3149,17 @@ static int load_module(void *mod)
return res;
}
-static int unload_module(void *mod)
+static int unload_module(void)
{
struct oh323_pvt *p, *pl;
/* unregister commands */
ast_cli_unregister_multiple(cli_h323, sizeof(cli_h323) / sizeof(struct ast_cli_entry));
- ast_rtp_proto_unregister(&oh323_rtp);
+ ast_cli_unregister(&cli_h323_reload);
+
ast_channel_unregister(&oh323_tech);
-
+ ast_rtp_proto_unregister(&oh323_rtp);
+
if (!ast_mutex_lock(&iflock)) {
/* hangup all interfaces if they have an owner */
p = iflist;
@@ -2476,9 +3176,10 @@ static int unload_module(void *mod)
return -1;
}
if (!ast_mutex_lock(&monlock)) {
- if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP)) {
+ if ((monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
/* this causes a seg, anyone know why? */
- pthread_cancel(monitor_thread);
+ if (monitor_thread != pthread_self())
+ pthread_cancel(monitor_thread);
pthread_kill(monitor_thread, SIGURG);
pthread_join(monitor_thread, NULL);
}
@@ -2504,21 +3205,24 @@ static int unload_module(void *mod)
ast_log(LOG_WARNING, "Unable to lock the interface list\n");
return -1;
}
- h323_gk_urq();
+ if (!gatekeeper_disable)
+ h323_gk_urq();
h323_end_process();
io_context_destroy(io);
sched_context_destroy(sched);
- delete_users();
- delete_aliases();
- prune_peers();
- ast_mutex_destroy(&aliasl.lock);
- ast_mutex_destroy(&userl.lock);
- ast_mutex_destroy(&peerl.lock);
- return 0;
-}
+
+ ASTOBJ_CONTAINER_DESTROYALL(&userl, oh323_destroy_user);
+ ASTOBJ_CONTAINER_DESTROY(&userl);
+ ASTOBJ_CONTAINER_DESTROYALL(&peerl, oh323_destroy_peer);
+ ASTOBJ_CONTAINER_DESTROY(&peerl);
+ ASTOBJ_CONTAINER_DESTROYALL(&aliasl, oh323_destroy_alias);
+ ASTOBJ_CONTAINER_DESTROY(&aliasl);
+
+ return 0;
+}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "The NuFone Network's OpenH323 Channel Driver",
.load = load_module,
.unload = unload_module,
.reload = reload,
- );
+);
diff --git a/channels/h323/Makefile b/channels/h323/Makefile
index 2b9fb4d4c..df309e6f6 100644
--- a/channels/h323/Makefile
+++ b/channels/h323/Makefile
@@ -4,34 +4,50 @@
# Make file for OpenH323 support layer
#
-.PHONY: Makefile.ast
+.PHONY: Makefile.ast clean
+
+default:: opt
# Verify those options with main Makefile
-STDCCFLAGS += -DNDEBUG
-STDCCFLAGS += $(shell grep ^DEBUG_THREADS ../../Makefile | sed -e "s/^DEBUG_THREADS[ ]*=//" -e "s/\([^\#]*\)\#.*/\1/")
-STDCCFLAGS += -I../../include -include autoconfig.h
+STDCCFLAGS = -DNDEBUG
+STDCCFLAGS += -I../../include -include ../../include/asterisk/autoconfig.h
+STDCCFLAGS += -fPIC
#OPTCCFLAGS +=
-CFLAGS += -pipe
-TARGET += libchanh323.a
+CFLAGS = -pipe
+TARGET = libchanh323.a
TARGET += Makefile.ast
-SOURCES = ast_h323.cxx
+SOURCES = ast_h323.cxx compat_h323.cxx cisco-h225.cxx
OBJDIR = .
+OBJS =
ifndef OPENH323DIR
-OPENH323DIR=$(HOME)/openh323
+OPENH323DIR=/usr/src/OpenH323/openh323
endif
include $(OPENH323DIR)/openh323u.mak
-$(SOURCES):: $(SOURCES:.cxx=.cpp)
- ln -f $< $@
+notrace::
+ $(MAKE) NOTRACE=1 opt
+
+define module_cxx_template
+$(1):: $(2)
+ ln -f $(2) $(1)
+endef
+
+$(foreach mod,$(SOURCES),$(eval $(call module_cxx_template,$(mod),$(mod:.cxx=.cpp))))
+#$(SOURCES):: $(SOURCES:.cxx=.cpp)
+# ln -f $(patsubst %.cxx, %.cpp, $@) $@
$(SOURCES):: Makefile ../../Makefile
- touch $(SOURCES)
+ touch $@
libchanh323.a: $(OBJS)
ar crv $@ $(OBJS)
+cisco-h225.cpp:: cisco-h225.asn
+ asnparser -m CISCO_H225 -c $<
+ mv -f cisco-h225.cxx cisco-h225.cpp
+
Makefile.ast:
@echo H323CFLAGS = $(STDCCFLAGS) $(OPTCCFLAGS) $(CFLAGS) >$@.tmp
@echo H323LDFLAGS = $(CFLAGS) $(LDFLAGS) >>$@.tmp
@@ -39,4 +55,4 @@ Makefile.ast:
@if [ -r $@ ] && cmp -s $@ $@.tmp; then rm -f $@.tmp; else mv -f $@.tmp $@; fi
clean::
- rm -f ast_h323.cxx libchanh323.a Makefile.ast *.dep
+ rm -f $(SOURCES) $(TARGET) $(OBJS) Makefile.ast *.dep
diff --git a/channels/h323/README b/channels/h323/README
index ff94bc42e..875bf3668 100644
--- a/channels/h323/README
+++ b/channels/h323/README
@@ -4,13 +4,15 @@
First public release on November 10th, 2002
- Dependancies: openssl-0.9.6b+
- openssl-devel-0.9.6b+
- expat-1.95+
- expat-dev-1.95+
-
-Tested with Open H.323 version v1.17.1, PWLib v1.9.0 and GCC v3.2.2. Usage of any
-other versions is not supported.
+ Dependancies (based on OpenH323/PWLib ones):
+ openssl-0.9.6b+
+ openssl-devel-0.9.6b+
+ expat-1.95+
+ expat-dev-1.95+
+
+Tested with Open H.323 version v1.18.0, PWLib v1.10.0 and GCC v3.2.2. Usage of any
+other (especially prior OpenH323 v1.17.3 and PWLib v1.9.2) versions is not
+supported.
NOTICE: Whatever you do, DO NOT USE distrubution specific installs
of Open H.323 and PWLib. In fact, you should check to make sure
diff --git a/channels/h323/TODO b/channels/h323/TODO
index b72a9f1d1..1e114ca3b 100644
--- a/channels/h323/TODO
+++ b/channels/h323/TODO
@@ -2,11 +2,6 @@ The NuFone Network's Open H.323 Channel Driver for Asterisk
TODO:
- - Fix Gatekeeper re-registration seg (HELP)
-
- - Track down why calls to invalid extensions always
- get sent to 's' in context 'default'
-
- H.323 Native Bridging
- Gatekeeping support (started)
diff --git a/channels/h323/ast_h323.cpp b/channels/h323/ast_h323.cpp
index 4a0db06f5..7d0c01f43 100644
--- a/channels/h323/ast_h323.cpp
+++ b/channels/h323/ast_h323.cpp
@@ -7,7 +7,7 @@
* OpenH323 Channel Driver for ASTERISK PBX.
* By Jeremy McNamara
* For The NuFone Network
- *
+ *
* chan_h323 has been derived from code created by
* Michael Manousos and Mark Spencer
*
@@ -16,15 +16,15 @@
* chan_h323 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.
+ * (at your option) any later version.
*
- * chan_h323 is distributed WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
+ * chan_h323 is distributed WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Version Info: $Id$
*/
@@ -45,12 +45,14 @@ extern "C" {
#endif
#include "asterisk/logger.h"
#include "asterisk/channel.h"
+#include "asterisk/astobj.h"
#ifdef __cplusplus
}
#endif
#include "chan_h323.h"
#include "ast_h323.h"
+#include "cisco-h225.h"
/* PWlib Required Components */
#define MAJOR_VERSION 1
@@ -59,20 +61,21 @@ extern "C" {
#define BUILD_NUMBER 0
/** Counter for the number of connections */
-int channelsOpen;
-
-/* DTMF Mode */
-int mode = H323_DTMF_RFC2833;
+static int channelsOpen;
/**
* We assume that only one endPoint should exist.
* The application cannot run the h323_end_point_create() more than once
* FIXME: Singleton this, for safety
*/
-MyH323EndPoint *endPoint = NULL;
+static MyH323EndPoint *endPoint = NULL;
/** PWLib entry point */
-MyProcess *localProcess = NULL;
+static MyProcess *localProcess = NULL;
+
+static int _timerChangePipe[2];
+
+static unsigned traceOptions = PTrace::Timestamp | PTrace::Thread | PTrace::FileAndLine;
class PAsteriskLog : public PObject, public iostream {
PCLASSINFO(PAsteriskLog, PObject);
@@ -143,27 +146,62 @@ int PAsteriskLog::Buffer::sync()
return 0;
}
-#define cout (*logstream)
+static ostream &my_endl(ostream &os)
+{
+ if (logstream) {
+ PTrace::SetOptions(traceOptions);
+ return PTrace::End(os);
+ }
+ return endl(os);
+}
+
+#define cout \
+ (logstream ? (PTrace::ClearOptions((unsigned)-1), PTrace::Begin(0, __FILE__, __LINE__)) : std::cout)
+#define endl my_endl
-MyProcess::MyProcess(): PProcess("The NuFone Network's", "H.323 Channel Driver for Asterisk",
- MAJOR_VERSION, MINOR_VERSION, BUILD_TYPE, BUILD_NUMBER)
+/* Special class designed to call cleanup code on module destruction */
+class MyH323_Shutdown {
+ public:
+ MyH323_Shutdown() { };
+ ~MyH323_Shutdown()
+ {
+ h323_end_process();
+ };
+};
+
+MyProcess::MyProcess(): PProcess("The NuFone Network's",
+ "H.323 Channel Driver for Asterisk",
+ MAJOR_VERSION, MINOR_VERSION, BUILD_TYPE, BUILD_NUMBER)
{
+ /* Call shutdown when module being unload or asterisk has been stopped */
+ static MyH323_Shutdown x;
+
/* Fix missed one in PWLib */
PX_firstTimeStart = FALSE;
Resume();
}
+MyProcess::~MyProcess()
+{
+ _timerChangePipe[0] = timerChangePipe[0];
+ _timerChangePipe[1] = timerChangePipe[1];
+}
+
void MyProcess::Main()
{
+ PTrace::Initialise(PTrace::GetLevel(), NULL, traceOptions);
+ PTrace::SetStream(logstream);
+
cout << " == Creating H.323 Endpoint" << endl;
+ if (endPoint) {
+ cout << " == ENDPOINT ALREADY CREATED" << endl;
+ return;
+ }
endPoint = new MyH323EndPoint();
/* Due to a bug in the H.323 recomendation/stack we should request a sane
- amount of bandwidth from the GK - this function is ignored if not using a GK
+ amount of bandwidth from the GK - this function is ignored if not using a GK
We are requesting 128 (64k in each direction), which is the worst case codec. */
- endPoint->SetInitialBandwidth(1280);
-
- PTrace::Initialise(0, NULL, PTrace::Timestamp | PTrace::Thread | PTrace::FileAndLine);
- PTrace::SetStream(logstream);
+ endPoint->SetInitialBandwidth(1280);
}
void PAssertFunc(const char *msg)
@@ -175,122 +213,187 @@ void PAssertFunc(const char *msg)
H323_REGISTER_CAPABILITY(H323_G7231Capability, OPAL_G7231);
H323_REGISTER_CAPABILITY(AST_G729Capability, OPAL_G729);
H323_REGISTER_CAPABILITY(AST_G729ACapability, OPAL_G729A);
+H323_REGISTER_CAPABILITY(AST_GSM0610Capability, OPAL_GSM0610);
+/*
+ * Capability: G.723.1
+ */
H323_G7231Capability::H323_G7231Capability(BOOL annexA_)
- : H323AudioCapability(7, 4)
+ : H323AudioCapability(7, 4)
{
- annexA = annexA_;
+ annexA = annexA_;
}
PObject::Comparison H323_G7231Capability::Compare(const PObject & obj) const
{
- Comparison result = H323AudioCapability::Compare(obj);
- if (result != EqualTo) {
- return result;
+ Comparison result = H323AudioCapability::Compare(obj);
+ if (result != EqualTo) {
+ return result;
}
- PINDEX otherAnnexA = ((const H323_G7231Capability &)obj).annexA;
- if (annexA < otherAnnexA) {
- return LessThan;
+ PINDEX otherAnnexA = ((const H323_G7231Capability &)obj).annexA;
+ if (annexA < otherAnnexA) {
+ return LessThan;
}
- if (annexA > otherAnnexA) {
- return GreaterThan;
+ if (annexA > otherAnnexA) {
+ return GreaterThan;
}
return EqualTo;
}
PObject * H323_G7231Capability::Clone() const
{
- return new H323_G7231Capability(*this);
+ return new H323_G7231Capability(*this);
}
PString H323_G7231Capability::GetFormatName() const
{
- return OPAL_G7231;
+ return (annexA ? OPAL_G7231 "A" : OPAL_G7231);
}
unsigned H323_G7231Capability::GetSubType() const
{
- return H245_AudioCapability::e_g7231;
+ return H245_AudioCapability::e_g7231;
}
BOOL H323_G7231Capability::OnSendingPDU(H245_AudioCapability & cap,
- unsigned packetSize) const
+ unsigned packetSize) const
{
- cap.SetTag(H245_AudioCapability::e_g7231);
- H245_AudioCapability_g7231 & g7231 = cap;
- g7231.m_maxAl_sduAudioFrames = packetSize;
- g7231.m_silenceSuppression = annexA;
- return TRUE;
+ cap.SetTag(H245_AudioCapability::e_g7231);
+ H245_AudioCapability_g7231 & g7231 = cap;
+ g7231.m_maxAl_sduAudioFrames = packetSize;
+ g7231.m_silenceSuppression = annexA;
+ return TRUE;
}
BOOL H323_G7231Capability::OnReceivedPDU(const H245_AudioCapability & cap,
- unsigned & packetSize)
+ unsigned & packetSize)
{
if (cap.GetTag() != H245_AudioCapability::e_g7231) {
- return FALSE;
+ return FALSE;
}
- const H245_AudioCapability_g7231 & g7231 = cap;
- packetSize = g7231.m_maxAl_sduAudioFrames;
- annexA = g7231.m_silenceSuppression;
- return TRUE;
+ const H245_AudioCapability_g7231 & g7231 = cap;
+ packetSize = g7231.m_maxAl_sduAudioFrames;
+ annexA = g7231.m_silenceSuppression;
+ return TRUE;
}
H323Codec * H323_G7231Capability::CreateCodec(H323Codec::Direction direction) const
{
- return NULL;
+ return NULL;
}
+/*
+ * Capability: G.729
+ */
AST_G729Capability::AST_G729Capability()
- : H323AudioCapability(24, 2)
+ : H323AudioCapability(24, 2)
{
}
PObject * AST_G729Capability::Clone() const
{
- return new AST_G729Capability(*this);
+ return new AST_G729Capability(*this);
}
unsigned AST_G729Capability::GetSubType() const
{
- return H245_AudioCapability::e_g729;
+ return H245_AudioCapability::e_g729;
}
PString AST_G729Capability::GetFormatName() const
{
- return OPAL_G729;
+ return OPAL_G729;
}
H323Codec * AST_G729Capability::CreateCodec(H323Codec::Direction direction) const
{
- return NULL;
+ return NULL;
}
+/*
+ * Capability: G.729A
+ */
AST_G729ACapability::AST_G729ACapability()
- : H323AudioCapability(24, 6)
+ : H323AudioCapability(24, 6)
{
}
PObject * AST_G729ACapability::Clone() const
{
- return new AST_G729ACapability(*this);
+ return new AST_G729ACapability(*this);
}
unsigned AST_G729ACapability::GetSubType() const
{
- return H245_AudioCapability::e_g729AnnexA;
+ return H245_AudioCapability::e_g729AnnexA;
}
PString AST_G729ACapability::GetFormatName() const
{
- return OPAL_G729A;
+ return OPAL_G729A;
}
H323Codec * AST_G729ACapability::CreateCodec(H323Codec::Direction direction) const
{
- return NULL;
+ return NULL;
+}
+
+/*
+ * Capability: GSM full rate
+ */
+AST_GSM0610Capability::AST_GSM0610Capability(int comfortNoise_, int scrambled_)
+ : H323AudioCapability(24, 2)
+{
+ comfortNoise = comfortNoise_;
+ scrambled = scrambled_;
+}
+
+PObject * AST_GSM0610Capability::Clone() const
+{
+ return new AST_GSM0610Capability(*this);
+}
+
+unsigned AST_GSM0610Capability::GetSubType() const
+{
+ return H245_AudioCapability::e_gsmFullRate;
+}
+
+BOOL AST_GSM0610Capability::OnSendingPDU(H245_AudioCapability & cap,
+ unsigned packetSize) const
+{
+ cap.SetTag(H245_AudioCapability::e_gsmFullRate);
+ H245_GSMAudioCapability & gsm = cap;
+ gsm.m_audioUnitSize = packetSize;
+ gsm.m_comfortNoise = comfortNoise;
+ gsm.m_scrambled = scrambled;
+ return TRUE;
+}
+
+BOOL AST_GSM0610Capability::OnReceivedPDU(const H245_AudioCapability & cap,
+ unsigned & packetSize)
+{
+ if (cap.GetTag() != H245_AudioCapability::e_gsmFullRate)
+ return FALSE;
+ const H245_GSMAudioCapability & gsm = cap;
+ packetSize = gsm.m_audioUnitSize;
+ comfortNoise = gsm.m_comfortNoise;
+ scrambled = gsm.m_scrambled;
+
+ return TRUE;
+}
+
+PString AST_GSM0610Capability::GetFormatName() const
+{
+ return OPAL_GSM0610;
}
-/** MyH323EndPoint
+H323Codec * AST_GSM0610Capability::CreateCodec(H323Codec::Direction direction) const
+{
+ return NULL;
+}
+
+
+/** MyH323EndPoint
*/
MyH323EndPoint::MyH323EndPoint()
: H323EndPoint()
@@ -306,10 +409,13 @@ MyH323EndPoint::MyH323EndPoint()
* transport = ip.
* port = 1720.
*/
-int MyH323EndPoint::MakeCall(const PString & dest, PString & token, unsigned int *callReference, call_options_t *opts)
+int MyH323EndPoint::MyMakeCall(const PString & dest, PString & token, void *_callReference, void *_opts)
{
PString fullAddress;
MyH323Connection * connection;
+ H323Transport *transport = NULL;
+ unsigned int *callReference = (unsigned int *)_callReference;
+ call_options_t *opts = (call_options_t *)_opts;
/* Determine whether we are using a gatekeeper or not. */
if (GetGatekeeper()) {
@@ -318,28 +424,35 @@ int MyH323EndPoint::MakeCall(const PString & dest, PString & token, unsigned int
cout << " -- Making call to " << fullAddress << " using gatekeeper." << endl;
}
} else {
- fullAddress = dest;
+ fullAddress = dest;
if (h323debug) {
cout << " -- Making call to " << fullAddress << " without gatekeeper." << endl;
}
+ /* Use bindaddr for outgoing calls too if we don't use gatekeeper */
+ if (listeners.GetSize() > 0) {
+ H323TransportAddress taddr = listeners[0].GetTransportAddress();
+ PIPSocket::Address addr;
+ WORD port;
+ if (taddr.GetIpAndPort(addr, port)) {
+ /* Create own transport for specific addresses only */
+ if (addr) {
+ if (h323debug)
+ cout << "Using " << addr << " for outbound call" << endl;
+ transport = new MyH323TransportTCP(*this, addr);
+ if (!transport)
+ cout << "Unable to create transport for outgoing call" << endl;
+ }
+ } else
+ cout << "Unable to get address and port" << endl;
+ }
}
- if (!(connection = (MyH323Connection *)H323EndPoint::MakeCallLocked(fullAddress, token, opts))) {
+ if (!(connection = (MyH323Connection *)H323EndPoint::MakeCallLocked(fullAddress, token, opts, transport))) {
if (h323debug) {
cout << "Error making call to \"" << fullAddress << '"' << endl;
}
return 1;
}
- *callReference = connection->GetCallReference();
-
- if (opts->cid_num) {
- connection->ast_cid_num = PString(opts->cid_num);
- }
- if (opts->cid_name) {
- connection->ast_cid_name = PString(opts->cid_name);
- connection->SetLocalPartyName(connection->ast_cid_name);
- }
-
- connection->dtmfCodec = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec;
+ *callReference = connection->GetCallReference();
if (h323debug) {
cout << "\t-- " << GetLocalUserName() << " is calling host " << fullAddress << endl;
@@ -347,28 +460,28 @@ int MyH323EndPoint::MakeCall(const PString & dest, PString & token, unsigned int
cout << "\t-- Call reference is " << *callReference << endl;
cout << "\t-- DTMF Payload is " << connection->dtmfCodec << endl;
}
- connection->Unlock();
+ connection->Unlock();
return 0;
}
void MyH323EndPoint::SetEndpointTypeInfo( H225_EndpointType & info ) const
{
- H323EndPoint::SetEndpointTypeInfo(info);
+ H323EndPoint::SetEndpointTypeInfo(info);
if (terminalType == e_GatewayOnly){
info.RemoveOptionalField(H225_EndpointType::e_terminal);
info.IncludeOptionalField(H225_EndpointType::e_gateway);
}
- info.m_gateway.IncludeOptionalField(H225_GatewayInfo::e_protocol);
- info.m_gateway.m_protocol.SetSize(1);
- H225_SupportedProtocols &protocol=info.m_gateway.m_protocol[0];
- protocol.SetTag(H225_SupportedProtocols::e_voice);
- PINDEX as=SupportedPrefixes.GetSize();
- ((H225_VoiceCaps &)protocol).m_supportedPrefixes.SetSize(as);
- for (PINDEX p=0; p<as; p++) {
+ info.m_gateway.IncludeOptionalField(H225_GatewayInfo::e_protocol);
+ info.m_gateway.m_protocol.SetSize(1);
+ H225_SupportedProtocols &protocol=info.m_gateway.m_protocol[0];
+ protocol.SetTag(H225_SupportedProtocols::e_voice);
+ PINDEX as=SupportedPrefixes.GetSize();
+ ((H225_VoiceCaps &)protocol).m_supportedPrefixes.SetSize(as);
+ for (PINDEX p=0; p<as; p++) {
H323SetAliasAddress(SupportedPrefixes[p], ((H225_VoiceCaps &)protocol).m_supportedPrefixes[p].m_prefix, H225_AliasAddress::e_dialedDigits);
- }
+ }
}
void MyH323EndPoint::SetGateway(void)
@@ -379,7 +492,11 @@ void MyH323EndPoint::SetGateway(void)
BOOL MyH323EndPoint::ClearCall(const PString & token, H323Connection::CallEndReason reason)
{
if (h323debug) {
+#ifdef PTRACING
cout << "\t-- ClearCall: Request to clear call with token " << token << ", cause " << reason << endl;
+#else
+ cout << "\t-- ClearCall: Request to clear call with token " << token << ", cause [" << (int)reason << "]" << endl;
+#endif
}
return H323EndPoint::ClearCall(token, reason);
}
@@ -395,7 +512,7 @@ BOOL MyH323EndPoint::ClearCall(const PString & token)
void MyH323EndPoint::SendUserTone(const PString &token, char tone)
{
H323Connection *connection = NULL;
-
+
connection = FindConnectionWithLock(token);
if (connection != NULL) {
connection->SendUserInputTone(tone, 500);
@@ -413,22 +530,22 @@ void MyH323EndPoint::OnClosedLogicalChannel(H323Connection & connection, const H
}
BOOL MyH323EndPoint::OnConnectionForwarded(H323Connection & connection,
- const PString & forwardParty,
- const H323SignalPDU & pdu)
- {
- if (h323debug) {
- cout << "\t-- Call Forwarded to " << forwardParty << endl;
- }
+ const PString & forwardParty,
+ const H323SignalPDU & pdu)
+{
+ if (h323debug) {
+ cout << "\t-- Call Forwarded to " << forwardParty << endl;
+ }
return FALSE;
- }
-
+}
+
BOOL MyH323EndPoint::ForwardConnection(H323Connection & connection,
- const PString & forwardParty,
- const H323SignalPDU & pdu)
+ const PString & forwardParty,
+ const H323SignalPDU & pdu)
{
- if (h323debug) {
- cout << "\t-- Forwarding call to " << forwardParty << endl;
- }
+ if (h323debug) {
+ cout << "\t-- Forwarding call to " << forwardParty << endl;
+ }
return H323EndPoint::ForwardConnection(connection, forwardParty, pdu);
}
@@ -442,7 +559,7 @@ void MyH323EndPoint::OnConnectionEstablished(H323Connection & connection, const
}
/** OnConnectionCleared callback function is called upon the dropping of an established
- * H323 connection.
+ * H323 connection.
*/
void MyH323EndPoint::OnConnectionCleared(H323Connection & connection, const PString & clearedCallToken)
{
@@ -535,53 +652,72 @@ void MyH323EndPoint::OnConnectionCleared(H323Connection & connection, const PStr
}
break;
default:
- if (h323debug)
+ if (h323debug) {
+#ifdef PTRACING
cout << " -- Call with " << remoteName << " completed (" << connection.GetCallEndReason() << ")" << endl;
-
+#else
+ cout << " -- Call with " << remoteName << " completed ([" << (int)connection.GetCallEndReason() << "])" << endl;
+#endif
+ }
}
if (connection.IsEstablished()) {
if (h323debug) {
cout << "\t-- Call duration " << setprecision(0) << setw(5) << (PTime() - connection.GetConnectionStartTime()) << endl;
}
- }
+ }
/* Invoke the PBX application registered callback */
on_connection_cleared(connection.GetCallReference(), clearedCallToken);
return;
}
-H323Connection * MyH323EndPoint::CreateConnection(unsigned callReference, void *o)
+H323Connection * MyH323EndPoint::CreateConnection(unsigned callReference, void *userData, H323Transport *transport, H323SignalPDU *setupPDU)
{
unsigned options = 0;
- call_options_t *opts = (call_options_t *)o;
+ call_options_t *opts = (call_options_t *)userData;
+ MyH323Connection *conn;
- if (opts && opts->noFastStart) {
- options |= H323Connection::FastStartOptionDisable;
- } else {
+ if (opts && opts->fastStart) {
options |= H323Connection::FastStartOptionEnable;
- }
- if (opts && opts->noH245Tunneling) {
- options |= H323Connection::H245TunnelingOptionDisable;
} else {
+ options |= H323Connection::FastStartOptionDisable;
+ }
+ if (opts && opts->h245Tunneling) {
options |= H323Connection::H245TunnelingOptionEnable;
+ } else {
+ options |= H323Connection::H245TunnelingOptionDisable;
}
/* Disable until I can figure out the proper way to deal with this */
#if 0
- if (opts->noSilenceSuppression) {
- options |= H323Connection::SilenceSuppresionOptionDisable;
+ if (opts->silenceSuppression) {
+ options |= H323Connection::SilenceSuppresionOptionEnable;
} else {
- options |= H323Connection::SilenceSUppressionOptionEnable;
+ options |= H323Connection::SilenceSUppressionOptionDisable;
}
#endif
- return new MyH323Connection(*this, callReference, options);
+ conn = new MyH323Connection(*this, callReference, options);
+ if (conn) {
+ if (opts)
+ conn->SetCallOptions(opts, (setupPDU ? TRUE : FALSE));
+ }
+ return conn;
}
-/* MyH323Connection Implementation */
+/* MyH323Connection Implementation */
MyH323Connection::MyH323Connection(MyH323EndPoint & ep, unsigned callReference,
unsigned options)
: H323Connection(ep, callReference, options)
{
cause = -1;
+ sessionId = 0;
+ bridging = FALSE;
+ progressSetup = progressAlert = 0;
+ dtmfMode = 0;
+ dtmfCodec = (RTP_DataFrame::PayloadTypes)0;
+ redirect_reason = -1;
+#ifdef TUNNELLING
+ tunnelOptions = remoteTunnelOptions = 0;
+#endif
if (h323debug) {
cout << " == New H.323 Connection created." << endl;
}
@@ -610,7 +746,7 @@ BOOL MyH323Connection::OnReceivedProgress(const H323SignalPDU &pdu)
if (h323debug) {
cout << "\t- Progress Indicator: " << pi << endl;
}
-
+
switch(pi) {
case Q931::ProgressNotEndToEndISDN:
case Q931::ProgressInbandInformationAvailable:
@@ -625,13 +761,13 @@ BOOL MyH323Connection::OnReceivedProgress(const H323SignalPDU &pdu)
}
H323Connection::AnswerCallResponse MyH323Connection::OnAnswerCall(const PString & caller,
- const H323SignalPDU & setupPDU,
- H323SignalPDU & /*connectPDU*/)
+ const H323SignalPDU & setupPDU,
+ H323SignalPDU & connectPDU)
{
unsigned pi;
if (h323debug) {
- cout << "\t=-= In OnAnswerCall for call " << GetCallReference() << endl;
+ cout << "\t=-= In OnAnswerCall for call " << GetCallReference() << endl;
}
if (connectionState == ShuttingDownConnection)
@@ -648,27 +784,33 @@ H323Connection::AnswerCallResponse MyH323Connection::OnAnswerCall(const PString
} else if (pi == Q931::ProgressOriginNotISDN) {
pi = Q931::ProgressInbandInformationAvailable;
}
- if (pi) {
+ if (pi && alertingPDU) {
alertingPDU->GetQ931().SetProgressIndicator(pi);
}
if (h323debug) {
cout << "\t\t- Inserting PI of " << pi << " into ALERTING message" << endl;
}
+#ifdef TUNNELLING
+ if (alertingPDU)
+ EmbedTunneledInfo(*alertingPDU);
+ EmbedTunneledInfo(connectPDU);
+#endif
+
if (!on_answer_call(GetCallReference(), (const char *)GetCallToken())) {
return H323Connection::AnswerCallDenied;
}
/* The call will be answered later with "AnsweringCall()" function.
- */
- return H323Connection::AnswerCallDeferredWithMedia;
+ */
+ return ((pi || (fastStartState != FastStartDisabled)) ? AnswerCallDeferredWithMedia : AnswerCallDeferred);
}
BOOL MyH323Connection::OnAlerting(const H323SignalPDU & alertingPDU, const PString & username)
{
if (h323debug) {
- cout << "\t=-= In OnAlerting for call " << GetCallReference()
- << ": sessionId=" << sessionId << endl;
- cout << "\t-- Ringing phone for \"" << username << "\"" << endl;
+ cout << "\t=-= In OnAlerting for call " << GetCallReference()
+ << ": sessionId=" << sessionId << endl;
+ cout << "\t-- Ringing phone for \"" << username << "\"" << endl;
}
if (on_progress) {
@@ -681,7 +823,7 @@ BOOL MyH323Connection::OnAlerting(const H323SignalPDU & alertingPDU, const PStri
if (h323debug) {
cout << "\t\t- Progress Indicator: " << alertingPI << endl;
}
-
+
switch(alertingPI) {
case Q931::ProgressNotEndToEndISDN:
case Q931::ProgressInbandInformationAvailable:
@@ -692,80 +834,457 @@ BOOL MyH323Connection::OnAlerting(const H323SignalPDU & alertingPDU, const PStri
}
on_progress(GetCallReference(), (const char *)GetCallToken(), isInband);
}
- on_chan_ringing(GetCallReference(), (const char *)GetCallToken() );
- return connectionState != ShuttingDownConnection;
+ on_chan_ringing(GetCallReference(), (const char *)GetCallToken() );
+ return connectionState != ShuttingDownConnection;
}
-BOOL MyH323Connection::OnReceivedSignalSetup(const H323SignalPDU & setupPDU)
+void MyH323Connection::SetCallOptions(void *o, BOOL isIncoming)
+{
+ call_options_t *opts = (call_options_t *)o;
+
+ progressSetup = opts->progress_setup;
+ progressAlert = opts->progress_alert;
+ dtmfCodec = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec;
+ dtmfMode = opts->dtmfmode;
+
+ if (isIncoming) {
+ fastStartState = (opts->fastStart ? FastStartInitiate : FastStartDisabled);
+ h245Tunneling = (opts->h245Tunneling ? TRUE : FALSE);
+ } else {
+ SetLocalPartyName(PString(opts->cid_num));
+ SetDisplayName(PString(opts->cid_name));
+ if (opts->redirect_reason >= 0) {
+ rdnis = PString(opts->cid_rdnis);
+ redirect_reason = opts->redirect_reason;
+ }
+ }
+ tunnelOptions = opts->tunnelOptions;
+}
+
+void MyH323Connection::SetCallDetails(void *callDetails, const H323SignalPDU &setupPDU, BOOL isIncoming)
{
- call_details_t cd;
PString sourceE164;
PString destE164;
- PString sourceName;
- PString sourceAliases;
+ PString sourceAliases;
PString destAliases;
- PIPSocket::Address Ip;
- WORD sourcePort;
- char *s, *s1;
-
- if (h323debug) {
- cout << ("\t--Received SETUP message\n");
- }
+ char *s, *s1;
+ call_details_t *cd = (call_details_t *)callDetails;
- if (connectionState == ShuttingDownConnection)
- return FALSE;
+ memset(cd, 0, sizeof(*cd));
+ cd->call_reference = GetCallReference();
+ cd->call_token = strdup((const char *)GetCallToken());
- sourceAliases = setupPDU.GetSourceAliases();
- destAliases = setupPDU.GetDestinationAlias();
-
sourceE164 = "";
setupPDU.GetSourceE164(sourceE164);
- sourceName = "";
- sourceName=setupPDU.GetQ931().GetDisplayName();
+ cd->call_source_e164 = strdup((const char *)sourceE164);
+
destE164 = "";
setupPDU.GetDestinationE164(destE164);
+ cd->call_dest_e164 = strdup((const char *)destE164);
+
+ /* XXX Is it possible to have this information for outgoing calls too? XXX */
+ if (isIncoming) {
+ PString sourceName;
+ PIPSocket::Address Ip;
+ WORD sourcePort;
+ PString redirect_number;
+ unsigned redirect_reason;
+
+ sourceName = setupPDU.GetQ931().GetDisplayName();
+ cd->call_source_name = strdup((const char *)sourceName);
+
+ GetSignallingChannel()->GetRemoteAddress().GetIpAndPort(Ip, sourcePort);
+ cd->sourceIp = strdup((const char *)Ip.AsString());
+
+ if(setupPDU.GetQ931().GetRedirectingNumber(redirect_number, NULL, NULL, NULL, NULL, &redirect_reason, 0, 0, 0)) {
+ cd->redirect_number = strdup((const char *)redirect_number);
+ cd->redirect_reason = redirect_reason;
+ }
+ else
+ cd->redirect_reason = -1;
+ }
/* Convert complex strings */
- // FIXME: deal more than one source alias
- if ((s = strchr(sourceAliases, ' ')) != NULL) {
- *s = '\0';
+ // FIXME: deal more than one source alias
+ sourceAliases = setupPDU.GetSourceAliases();
+ s1 = strdup((const char *)sourceAliases);
+ if ((s = strchr(s1, ' ')) != NULL)
+ *s = '\0';
+ if ((s = strchr(s1, '\t')) != NULL)
+ *s = '\0';
+ cd->call_source_aliases = s1;
+
+ destAliases = setupPDU.GetDestinationAlias();
+ s1 = strdup((const char *)destAliases);
+ if ((s = strchr(s1, ' ')) != NULL)
+ *s = '\0';
+ if ((s = strchr(s1, '\t')) != NULL)
+ *s = '\0';
+ cd->call_dest_alias = s1;
+}
+
+#ifdef TUNNELLING
+static BOOL FetchInformationElements(Q931 &q931, const PBYTEArray &data)
+{
+ PINDEX offset = 0;
+
+ while (offset < data.GetSize()) {
+ // Get field discriminator
+ int discriminator = data[offset++];
+
+#if 0
+ /* Do not overwrite existing IEs */
+ if (q931.HasIE((Q931::InformationElementCodes)discriminator)) {
+ if ((discriminatir & 0x80) == 0)
+ offset += data[offset++];
+ if (offset > data.GetSize())
+ return FALSE;
+ continue;
+ }
+#endif
+
+ PBYTEArray * item = new PBYTEArray;
+
+ // For discriminator with high bit set there is no data
+ if ((discriminator & 0x80) == 0) {
+ int len = data[offset++];
+
+#if 0 // That is not H.225 but regular Q.931 (ISDN) IEs
+ if (discriminator == UserUserIE) {
+ // Special case of User-user field. See 7.2.2.31/H.225.0v4.
+ len <<= 8;
+ len |= data[offset++];
+
+ // we also have a protocol discriminator, which we ignore
+ offset++;
+
+ // before decrementing the length, make sure it is not zero
+ if (len == 0)
+ return FALSE;
+
+ // adjust for protocol discriminator
+ len--;
+ }
+#endif
+
+ if (offset + len > data.GetSize()) {
+ delete item;
+ return FALSE;
+ }
+
+ memcpy(item->GetPointer(len), (const BYTE *)data+offset, len);
+ offset += len;
+ }
+
+ q931.SetIE((Q931::InformationElementCodes)discriminator, *item);
+ delete item;
}
- if ((s = strchr(sourceAliases, '\t')) != NULL) {
- *s = '\0';
+ return TRUE;
+}
+
+static BOOL FetchCiscoTunneledInfo(Q931 &q931, const H323SignalPDU &pdu)
+{
+ BOOL res = FALSE;
+ const H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu;
+
+ if(uuPDU.HasOptionalField(H225_H323_UU_PDU::e_nonStandardControl)) {
+ for(int i = 0; i < uuPDU.m_nonStandardControl.GetSize(); ++i) {
+ const H225_NonStandardParameter &np = uuPDU.m_nonStandardControl[i];
+ const H225_NonStandardIdentifier &id = np.m_nonStandardIdentifier;
+ if (id.GetTag() == H225_NonStandardIdentifier::e_h221NonStandard) {
+ const H225_H221NonStandard &ni = id;
+ /* Check for Cisco */
+ if ((ni.m_t35CountryCode == 181) && (ni.m_t35Extension == 0) && (ni.m_manufacturerCode == 18)) {
+ const PBYTEArray &data = np.m_data;
+ if (h323debug)
+ cout << setprecision(0) << "Received non-standard Cisco extension data " << np.m_data << endl;
+ CISCO_H225_H323_UU_NonStdInfo c;
+ PPER_Stream strm(data);
+ if (c.Decode(strm)) {
+ BOOL haveIEs = FALSE;
+ if (h323debug)
+ cout << setprecision(0) << "H323_UU_NonStdInfo = " << c << endl;
+ if (c.HasOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_protoParam)) {
+ FetchInformationElements(q931, c.m_protoParam.m_qsigNonStdInfo.m_rawMesg);
+ haveIEs = TRUE;
+ }
+ if (c.HasOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_commonParam)) {
+ FetchInformationElements(q931, c.m_commonParam.m_redirectIEinfo.m_redirectIE);
+ haveIEs = TRUE;
+ }
+ if (haveIEs && h323debug)
+ cout << setprecision(0) << "Information elements collected:" << q931 << endl;
+ res = TRUE;
+ } else {
+ cout << "ERROR while decoding non-standard Cisco extension" << endl;
+ return FALSE;
+ }
+ }
+ }
+ }
+ }
+ return res;
+}
+
+static BOOL EmbedCiscoTunneledInfo(H323SignalPDU &pdu)
+{
+ const static Q931::InformationElementCodes codes[] =
+ { Q931::RedirectingNumberIE, Q931::FacilityIE };
+
+ BOOL res = FALSE;
+ BOOL notRedirOnly = FALSE;
+ Q931 tmpQ931;
+ Q931 &q931 = pdu.GetQ931();
+
+ for(unsigned i = 0; i < (sizeof(codes) / sizeof(codes[0])); ++i) {
+ if (q931.HasIE(codes[i])) {
+ tmpQ931.SetIE(codes[i], q931.GetIE(codes[i]));
+ q931.RemoveIE(codes[i]);
+ if (codes[i] != Q931::RedirectingNumberIE)
+ notRedirOnly = TRUE;
+ res = TRUE;
+ }
}
- if ((s1 = strchr(destAliases, ' ')) != NULL) {
- *s1 = '\0';
+ /* Have something to embed */
+ if (res) {
+ PBYTEArray msg;
+ if (!tmpQ931.Encode(msg))
+ return FALSE;
+ PBYTEArray ies(msg.GetPointer() + 5, msg.GetSize() - 5);
+
+ H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu;
+ if(!uuPDU.HasOptionalField(H225_H323_UU_PDU::e_nonStandardControl)) {
+ uuPDU.IncludeOptionalField(H225_H323_UU_PDU::e_nonStandardControl);
+ uuPDU.m_nonStandardControl.SetSize(0);
+ }
+ H225_NonStandardParameter *np = new H225_NonStandardParameter;
+ uuPDU.m_nonStandardControl.Append(np);
+ H225_NonStandardIdentifier &nsi = (*np).m_nonStandardIdentifier;
+ nsi.SetTag(H225_NonStandardIdentifier::e_h221NonStandard);
+ H225_H221NonStandard &ns = nsi;
+ ns.m_t35CountryCode = 181;
+ ns.m_t35Extension = 0;
+ ns.m_manufacturerCode = 18;
+
+ CISCO_H225_H323_UU_NonStdInfo c;
+ c.IncludeOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_version);
+ c.m_version = 0;
+
+ if (notRedirOnly) {
+ c.IncludeOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_protoParam);
+ CISCO_H225_QsigNonStdInfo &qsigInfo = c.m_protoParam.m_qsigNonStdInfo;
+ qsigInfo.m_iei = ies[0];
+ qsigInfo.m_rawMesg = ies;
+ } else {
+ c.IncludeOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_commonParam);
+ c.m_commonParam.m_redirectIEinfo.m_redirectIE = ies;
+ }
+ PPER_Stream stream;
+ c.Encode(stream);
+ stream.CompleteEncoding();
+ (*np).m_data = stream;
}
- if ((s1 = strchr(destAliases, '\t')) != NULL) {
- *s1 = '\0';
+ return res;
+}
+
+static const char OID_QSIG[] = "1.3.12.9";
+
+static BOOL FetchQSIGTunneledInfo(Q931 &q931, const H323SignalPDU &pdu)
+{
+ BOOL res = FALSE;
+ const H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu;
+ if (uuPDU.HasOptionalField(H225_H323_UU_PDU::e_tunnelledSignallingMessage)) {
+ const H225_H323_UU_PDU_tunnelledSignallingMessage &sig = uuPDU.m_tunnelledSignallingMessage;
+ const H225_TunnelledProtocol_id &proto = sig.m_tunnelledProtocolID.m_id;
+ if ((proto.GetTag() == H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) &&
+ (((const PASN_ObjectId &)proto).AsString() == OID_QSIG)) {
+ const H225_ArrayOf_PASN_OctetString &sigs = sig.m_messageContent;
+ for(int i = 0; i < sigs.GetSize(); ++i) {
+ const PASN_OctetString &msg = sigs[i];
+ if (h323debug)
+ cout << setprecision(0) << "Q.931 message data is " << msg << endl;
+ if(!q931.Decode((const PBYTEArray &)msg)) {
+ cout << "Error while decoding Q.931 message" << endl;
+ return FALSE;
+ }
+ res = TRUE;
+ if (h323debug)
+ cout << setprecision(0) << "Received QSIG message " << q931 << endl;
+ }
+ }
}
+ return res;
+}
- memset(&cd, 0, sizeof(cd));
- cd.call_reference = GetCallReference();
- cd.call_token = strdup((const char *)GetCallToken());
- cd.call_source_aliases = strdup((const char *)sourceAliases);
- cd.call_dest_alias = strdup((const char *)destAliases);
- cd.call_source_e164 = strdup((const char *)sourceE164);
- cd.call_dest_e164 = strdup((const char *)destE164);
- cd.call_source_name = strdup((const char *)sourceName);
+static H225_EndpointType *GetEndpointType(H323SignalPDU &pdu)
+{
+ if (!pdu.GetQ931().HasIE(Q931::UserUserIE))
+ return NULL;
- GetSignallingChannel()->GetRemoteAddress().GetIpAndPort(Ip, sourcePort);
- cd.sourceIp = strdup((const char *)Ip.AsString());
+ H225_H323_UU_PDU_h323_message_body &body = pdu.m_h323_uu_pdu.m_h323_message_body;
+ switch (body.GetTag()) {
+ case H225_H323_UU_PDU_h323_message_body::e_setup:
+ return &((H225_Setup_UUIE &)body).m_sourceInfo;
+ case H225_H323_UU_PDU_h323_message_body::e_callProceeding:
+ return &((H225_CallProceeding_UUIE &)body).m_destinationInfo;
+ case H225_H323_UU_PDU_h323_message_body::e_connect:
+ return &((H225_Connect_UUIE &)body).m_destinationInfo;
+ case H225_H323_UU_PDU_h323_message_body::e_alerting:
+ return &((H225_Alerting_UUIE &)body).m_destinationInfo;
+ case H225_H323_UU_PDU_h323_message_body::e_facility:
+ return &((H225_Facility_UUIE &)body).m_destinationInfo;
+ case H225_H323_UU_PDU_h323_message_body::e_progress:
+ return &((H225_Progress_UUIE &)body).m_destinationInfo;
+ }
+ return NULL;
+}
+
+static BOOL QSIGTunnelRequested(H323SignalPDU &pdu)
+{
+ H225_EndpointType *epType = GetEndpointType(pdu);
+ if (epType) {
+ if (!(*epType).HasOptionalField(H225_EndpointType::e_supportedTunnelledProtocols)) {
+ return FALSE;
+ }
+ H225_ArrayOf_TunnelledProtocol &protos = (*epType).m_supportedTunnelledProtocols;
+ for (int i = 0; i < protos.GetSize(); ++i)
+ {
+ if ((protos[i].GetTag() == H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) &&
+ (((const PASN_ObjectId &)protos[i]).AsString() == OID_QSIG)) {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+static BOOL EmbedQSIGTunneledInfo(H323SignalPDU &pdu)
+{
+ const static Q931::InformationElementCodes codes[] =
+ { Q931::RedirectingNumberIE, Q931::FacilityIE };
+
+ Q931 &q931 = pdu.GetQ931();
+ PBYTEArray message;
+
+ q931.Encode(message);
+
+ /* Remove non-standard IEs */
+ for(unsigned i = 0; i < (sizeof(codes) / sizeof(codes[0])); ++i) {
+ if (q931.HasIE(codes[i])) {
+ q931.RemoveIE(codes[i]);
+ }
+ }
+
+ H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu;
+ H225_EndpointType *epType = GetEndpointType(pdu);
+ if (epType) {
+ if (!(*epType).HasOptionalField(H225_EndpointType::e_supportedTunnelledProtocols)) {
+ (*epType).IncludeOptionalField(H225_EndpointType::e_supportedTunnelledProtocols);
+ (*epType).m_supportedTunnelledProtocols.SetSize(0);
+ }
+ H225_ArrayOf_TunnelledProtocol &protos = (*epType).m_supportedTunnelledProtocols;
+ BOOL addQSIG = TRUE;
+ for (int i = 0; i < protos.GetSize(); ++i)
+ {
+ if ((protos[i].GetTag() == H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) &&
+ (((const PASN_ObjectId &)protos[i]).AsString() == OID_QSIG)) {
+ addQSIG = FALSE;
+ break;
+ }
+ }
+ if (addQSIG) {
+ H225_TunnelledProtocol *proto = new H225_TunnelledProtocol;
+ (*proto).m_id.SetTag(H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID);
+ (PASN_ObjectId &)(proto->m_id) = OID_QSIG;
+ protos.Append(proto);
+ }
+ }
+ if (!uuPDU.HasOptionalField(H225_H323_UU_PDU::e_tunnelledSignallingMessage))
+ uuPDU.IncludeOptionalField(H225_H323_UU_PDU::e_tunnelledSignallingMessage);
+ H225_H323_UU_PDU_tunnelledSignallingMessage &sig = uuPDU.m_tunnelledSignallingMessage;
+ H225_TunnelledProtocol_id &proto = sig.m_tunnelledProtocolID.m_id;
+ if ((proto.GetTag() != H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) ||
+ (((const PASN_ObjectId &)proto).AsString() != OID_QSIG)) {
+ proto.SetTag(H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID);
+ (PASN_ObjectId &)proto = OID_QSIG;
+ sig.m_messageContent.SetSize(0);
+ }
+ PASN_OctetString *msg = new PASN_OctetString;
+ sig.m_messageContent.Append(msg);
+ *msg = message;
+ return TRUE;
+}
+
+BOOL MyH323Connection::EmbedTunneledInfo(H323SignalPDU &pdu)
+{
+ if ((tunnelOptions & H323_TUNNEL_QSIG) || (remoteTunnelOptions & H323_TUNNEL_QSIG))
+ EmbedQSIGTunneledInfo(pdu);
+ if ((tunnelOptions & H323_TUNNEL_CISCO) || (remoteTunnelOptions & H323_TUNNEL_CISCO))
+ EmbedCiscoTunneledInfo(pdu);
+
+ return TRUE;
+}
+
+/* Handle tunneled messages */
+BOOL MyH323Connection::HandleSignalPDU(H323SignalPDU &pdu)
+{
+ if (pdu.GetQ931().HasIE(Q931::UserUserIE)) {
+ Q931 tunneledInfo;
+ const Q931 *q931Info;
+
+ q931Info = NULL;
+ if (FetchCiscoTunneledInfo(tunneledInfo, pdu)) {
+ q931Info = &tunneledInfo;
+ remoteTunnelOptions |= H323_TUNNEL_CISCO;
+ }
+ if (FetchQSIGTunneledInfo(tunneledInfo, pdu)) {
+ q931Info = &tunneledInfo;
+ remoteTunnelOptions |= H323_TUNNEL_QSIG;
+ }
+ if (!(remoteTunnelOptions & H323_TUNNEL_QSIG) && QSIGTunnelRequested(pdu)) {
+ remoteTunnelOptions |= H323_TUNNEL_QSIG;
+ }
+ if (q931Info) {
+ if (q931Info->HasIE(Q931::RedirectingNumberIE)) {
+ pdu.GetQ931().SetIE(Q931::RedirectingNumberIE, q931Info->GetIE(Q931::RedirectingNumberIE));
+ if (h323debug) {
+ PString number;
+ unsigned reason;
+ if(q931Info->GetRedirectingNumber(number, NULL, NULL, NULL, NULL, &reason, 0, 0, 0))
+ cout << "Got redirection from " << number << ", reason " << reason << endl;
+ }
+ }
+ }
+ }
+
+ return H323Connection::HandleSignalPDU(pdu);
+}
+#endif
+
+BOOL MyH323Connection::OnReceivedSignalSetup(const H323SignalPDU & setupPDU)
+{
+ call_details_t cd;
+
+ if (h323debug) {
+ cout << "\t--Received SETUP message" << endl;
+ }
+
+ if (connectionState == ShuttingDownConnection)
+ return FALSE;
+
+ SetCallDetails(&cd, setupPDU, TRUE);
/* Notify Asterisk of the request */
call_options_t *res = on_incoming_call(&cd);
if (!res) {
if (h323debug) {
- cout << " -- Call Failed" << endl;
+ cout << "\t-- Call Failed" << endl;
}
return FALSE;
}
- progressSetup = res->progress_setup;
- progressAlert = res->progress_alert;
- dtmfCodec = (RTP_DataFrame::PayloadTypes)res->dtmfcodec;
-
+ SetCallOptions(res, TRUE);
return H323Connection::OnReceivedSignalSetup(setupPDU);
}
@@ -773,54 +1292,27 @@ BOOL MyH323Connection::OnReceivedSignalSetup(const H323SignalPDU & setupPDU)
BOOL MyH323Connection::OnSendSignalSetup(H323SignalPDU & setupPDU)
{
call_details_t cd;
- char *s, *s1;
- if (h323debug) {
- cout << " -- Sending SETUP message" << endl;
+ if (h323debug) {
+ cout << "\t-- Sending SETUP message" << endl;
}
if (connectionState == ShuttingDownConnection)
return FALSE;
- if (!ast_cid_num.IsEmpty()) {
- setupPDU.GetQ931().SetCallingPartyNumber(ast_cid_num);
- }
-
- if (!ast_cid_name.IsEmpty()) {
- setupPDU.GetQ931().SetDisplayName(ast_cid_name);
- }
-
- sourceAliases = setupPDU.GetSourceAliases();
- destAliases = setupPDU.GetDestinationAlias();
-
- sourceE164 = "";
- setupPDU.GetSourceE164(sourceE164);
- destE164 = "";
- setupPDU.GetDestinationE164(destE164);
+ if (progressSetup)
+ setupPDU.GetQ931().SetProgressIndicator(progressSetup);
- /* Convert complex strings */
- // FIXME: deal more than one source alias
-
- if ((s = strchr(sourceAliases, ' ')) != NULL) {
- *s = '\0';
- }
- if ((s = strchr(sourceAliases, '\t')) != NULL) {
- *s = '\0';
- }
- if ((s1 = strchr(destAliases, ' ')) != NULL) {
- *s1 = '\0';
- }
- if ((s1 = strchr(destAliases, '\t')) != NULL) {
- *s1 = '\0';
+ if (redirect_reason >= 0) {
+ setupPDU.GetQ931().SetRedirectingNumber(rdnis, 0, 0, 0, 0, redirect_reason);
+ /* OpenH323 incorrectly fills number IE when redirecting reason is specified - fix it */
+ PBYTEArray IE(setupPDU.GetQ931().GetIE(Q931::RedirectingNumberIE));
+ IE[0] = IE[0] & 0x7f;
+ IE[1] = IE[1] & 0x7f;
+ setupPDU.GetQ931().SetIE(Q931::RedirectingNumberIE, IE);
}
- memset(&cd, 0, sizeof(cd));
- cd.call_reference = GetCallReference();
- cd.call_token = strdup((const char *)GetCallToken());
- cd.call_source_aliases = strdup((const char *)sourceAliases);
- cd.call_dest_alias = strdup((const char *)destAliases);
- cd.call_source_e164 = strdup((const char *)sourceE164);
- cd.call_dest_e164 = strdup((const char *)destE164);
+ SetCallDetails(&cd, setupPDU, FALSE);
int res = on_outgoing_call(&cd);
if (!res) {
@@ -830,9 +1322,10 @@ BOOL MyH323Connection::OnSendSignalSetup(H323SignalPDU & setupPDU)
return FALSE;
}
- if (progressSetup) {
- setupPDU.GetQ931().SetProgressIndicator(progressSetup);
- }
+#ifdef TUNNELLING
+ EmbedTunneledInfo(setupPDU);
+#endif
+
return H323Connection::OnSendSignalSetup(setupPDU);
}
@@ -843,6 +1336,11 @@ BOOL MyH323Connection::OnSendReleaseComplete(H323SignalPDU & releaseCompletePDU)
}
if (cause > 0)
releaseCompletePDU.GetQ931().SetCause((Q931::CauseValues)cause);
+
+#ifdef TUNNELLING
+ EmbedTunneledInfo(releaseCompletePDU);
+#endif
+
return H323Connection::OnSendReleaseComplete(releaseCompletePDU);
}
@@ -850,14 +1348,14 @@ BOOL MyH323Connection::OnReceivedFacility(const H323SignalPDU & pdu)
{
if (h323debug) {
cout << "\t-- Received Facility message... " << endl;
- }
+ }
return H323Connection::OnReceivedFacility(pdu);
}
void MyH323Connection::OnReceivedReleaseComplete(const H323SignalPDU & pdu)
{
if (h323debug) {
- cout << "\t-- Received RELEASE COMPLETE message..." << endl;
+ cout << "\t-- Received RELEASE COMPLETE message..." << endl;
}
if (on_hangup)
on_hangup(GetCallReference(), (const char *)GetCallToken(), pdu.GetQ931().GetCause());
@@ -872,34 +1370,35 @@ BOOL MyH323Connection::OnClosingLogicalChannel(H323Channel & channel)
return H323Connection::OnClosingLogicalChannel(channel);
}
-void MyH323Connection::SendUserInputTone(char tone, unsigned duration)
+void MyH323Connection::SendUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp)
{
- if (h323debug) {
- cout << "\t-- Sending user input tone (" << tone << ") to remote" << endl;
+ SendUserInputModes mode = GetRealSendUserInputMode();
+// That is recursive call... Why?
+// on_receive_digit(GetCallReference(), tone, (const char *)GetCallToken());
+ if ((tone != ' ') || (mode == SendUserInputAsTone) || (mode == SendUserInputAsInlineRFC2833)) {
+ if (h323debug) {
+ cout << "\t-- Sending user input tone (" << tone << ") to remote" << endl;
+ }
+ H323Connection::SendUserInputTone(tone, duration);
}
- on_send_digit(GetCallReference(), tone, (const char *)GetCallToken());
- H323Connection::SendUserInputTone(tone, duration);
}
void MyH323Connection::OnUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp)
{
- if (mode == H323_DTMF_INBAND) {
+ if (dtmfMode == H323_DTMF_RFC2833) {
if (h323debug) {
cout << "\t-- Received user input tone (" << tone << ") from remote" << endl;
}
- on_send_digit(GetCallReference(), tone, (const char *)GetCallToken());
+ on_receive_digit(GetCallReference(), tone, (const char *)GetCallToken(), duration);
}
- H323Connection::OnUserInputTone(tone, duration, logicalChannel, rtpTimestamp);
}
void MyH323Connection::OnUserInputString(const PString &value)
{
- if (mode == H323_DTMF_RFC2833) {
- if (h323debug) {
- cout << "\t-- Received user input string (" << value << ") from remote." << endl;
- }
- on_send_digit(GetCallReference(), value[0], (const char *)GetCallToken());
- }
+ if (h323debug) {
+ cout << "\t-- Received user input string (" << value << ") from remote." << endl;
+ }
+ on_receive_digit(GetCallReference(), value[0], (const char *)GetCallToken(), 0);
}
void MyH323Connection::OnSendCapabilitySet(H245_TerminalCapabilitySet & pdu)
@@ -917,7 +1416,7 @@ void MyH323Connection::OnSendCapabilitySet(H245_TerminalCapabilitySet & pdu)
if (cap.GetTag() == H245_Capability::e_receiveRTPAudioTelephonyEventCapability) {
H245_AudioTelephonyEventCapability & atec = cap;
atec.m_dynamicRTPPayloadType = dtmfCodec;
- on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)dtmfCodec);
+// on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)dtmfCodec);
if (h323debug) {
cout << "\t-- Transmitting RFC2833 on payload " <<
atec.m_dynamicRTPPayloadType << endl;
@@ -934,9 +1433,42 @@ void MyH323Connection::OnSetLocalCapabilities()
}
BOOL MyH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCaps,
- const H245_MultiplexCapability * muxCap,
- H245_TerminalCapabilitySetReject & reject)
-{
+ const H245_MultiplexCapability * muxCap,
+ H245_TerminalCapabilitySetReject & reject)
+{
+ struct __codec__ {
+ unsigned int asterisk_codec;
+ unsigned int h245_cap;
+ const char *oid;
+ };
+ static const struct __codec__ codecs[] = {
+ { AST_FORMAT_G723_1, H245_AudioCapability::e_g7231 },
+ { AST_FORMAT_GSM, H245_AudioCapability::e_gsmFullRate },
+ { AST_FORMAT_ULAW, H245_AudioCapability::e_g711Ulaw64k },
+ { AST_FORMAT_ALAW, H245_AudioCapability::e_g711Alaw64k },
+ { AST_FORMAT_G729A, H245_AudioCapability::e_g729AnnexA },
+ { AST_FORMAT_G729A, H245_AudioCapability::e_g729 },
+#ifdef AST_FORMAT_MODEM
+ { AST_FORMAT_MODEM, H245_DataApplicationCapability_application::e_t38fax },
+#endif
+ { 0 }
+ };
+
+#if 0
+ static const struct __codec__ vcodecs[] = {
+#ifdef HAVE_H261
+ { AST_FORMAT_H261, H245_VideoCapability::e_h261VideoCapability },
+#endif
+#ifdef HAVE_H263
+ { AST_FORMAT_H263, H245_VideoCapability::e_h263VideoCapability },
+#endif
+#ifdef HAVE_H264
+ { AST_FORMAT_H264, H245_VideoCapability::e_genericVideoCapability, "0.0.8.241.0.0.1" },
+#endif
+ { 0 }
+ };
+#endif
+
if (!H323Connection::OnReceivedCapabilitySet(remoteCaps, muxCap, reject)) {
return FALSE;
}
@@ -945,124 +1477,258 @@ BOOL MyH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCa
if (cap != NULL) {
RTP_DataFrame::PayloadTypes pt = ((H323_UserInputCapability*)cap)->GetPayloadType();
on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)pt);
+ if ((dtmfMode == H323_DTMF_RFC2833) && (sendUserInputMode == SendUserInputAsTone))
+ sendUserInputMode = SendUserInputAsInlineRFC2833;
if (h323debug) {
cout << "\t-- Inbound RFC2833 on payload " << pt << endl;
}
}
+ int peer_capabilities = 0;
+ for (int i = 0; i < remoteCapabilities.GetSize(); ++i) {
+ unsigned int subType = remoteCapabilities[i].GetSubType();
+ if (h323debug) {
+ cout << "Peer capability is " << remoteCapabilities[i] << endl;
+ }
+ switch(remoteCapabilities[i].GetMainType()) {
+ case H323Capability::e_Audio:
+ for (int x = 0; codecs[x].asterisk_codec > 0; ++x) {
+ if (subType == codecs[x].h245_cap) {
+ if (h323debug) {
+ cout << "Found peer capability " << remoteCapabilities[i] << ", Asterisk code is " << codecs[x].asterisk_codec << endl;
+ }
+ peer_capabilities |= codecs[x].asterisk_codec;
+ }
+ }
+ break;
+#if 0
+ case H323Capability::e_Video:
+ for (int x = 0; vcodecs[x].asterisk_codec > 0; ++x) {
+ if (subType == vcodecs[x].h245_cap) {
+ H245_CapabilityIdentifier *cap = NULL;
+ H245_GenericCapability y;
+ if (vcodecs[x].oid) {
+ cap = new H245_CapabilityIdentifier(H245_CapabilityIdentifier::e_standard);
+ PASN_ObjectId &object_id = *cap;
+ object_id = vcodecs[x].oid;
+ y.m_capabilityIdentifier = *cap;
+ }
+ if ((subType != H245_VideoCapability::e_genericVideoCapability) ||
+ (vcodecs[x].oid && ((const H323GenericVideoCapability &)remoteCapabilities[i]).IsGenericMatch((const H245_GenericCapability)y))) {
+ if (h323debug) {
+ cout << "Found peer video capability " << remoteCapabilities[i] << ", Asterisk code is " << vcodecs[x].asterisk_codec << endl;
+ }
+ peer_capabilities |= vcodecs[x].asterisk_codec;
+ }
+ if (cap)
+ delete(cap);
+ }
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+ }
+ if (h323debug) {
+ char caps_str[1024];
+ cout << "Peer capabilities = " << ast_getformatname_multiple(caps_str, sizeof(caps_str), peer_capabilities) << endl;
+ }
+#if 0
+ redir_capabilities &= peer_capabilities;
+#endif
+ if (on_setpeercapabilities)
+ on_setpeercapabilities(GetCallReference(), (const char *)callToken, peer_capabilities);
+
return TRUE;
}
-H323Channel * MyH323Connection::CreateRealTimeLogicalChannel(const H323Capability & capability,
- H323Channel::Directions dir,
- unsigned sessionID,
- const H245_H2250LogicalChannelParameters * /*param*/,
- RTP_QOS * /*param*/ )
+H323Channel * MyH323Connection::CreateRealTimeLogicalChannel(const H323Capability & capability,
+ H323Channel::Directions dir,
+ unsigned sessionID,
+ const H245_H2250LogicalChannelParameters * /*param*/,
+ RTP_QOS * /*param*/ )
{
return new MyH323_ExternalRTPChannel(*this, capability, dir, sessionID);
}
/** This callback function is invoked once upon creation of each
- * channel for an H323 session
+ * channel for an H323 session
*/
BOOL MyH323Connection::OnStartLogicalChannel(H323Channel & channel)
-{
+{
/* Increase the count of channels we have open */
channelsOpen++;
if (h323debug) {
- cout << "\t-- Started logical channel: ";
- cout << ((channel.GetDirection()==H323Channel::IsTransmitter)?"sending ":((channel.GetDirection()==H323Channel::IsReceiver)?"receiving ":" "));
- cout << (const char *)(channel.GetCapability()).GetFormatName() << endl;
- cout << "\t\t-- channelsOpen = " << channelsOpen << endl;
+ cout << "\t-- Started logical channel: "
+ << ((channel.GetDirection() == H323Channel::IsTransmitter) ? "sending " : ((channel.GetDirection() == H323Channel::IsReceiver) ? "receiving " : " "))
+ << (const char *)(channel.GetCapability()).GetFormatName() << endl;
+ cout << "\t\t-- channelsOpen = " << channelsOpen << endl;
}
return connectionState != ShuttingDownConnection;
}
-void MyH323Connection::SetCapabilities(int cap, int dtmfMode)
+void MyH323Connection::SetCapabilities(int cap, int dtmf_mode, void *_prefs, int pref_codec)
{
int g711Frames = 20;
-// int gsmFrames = 4;
+ int gsmFrames = 4;
PINDEX lastcap = -1; /* last common capability index */
+ int alreadysent = 0;
+ int codec;
+ int x, y;
+ char caps_str[1024];
+ struct ast_codec_pref *prefs = (struct ast_codec_pref *)_prefs;
+ localCapabilities.RemoveAll();
+
+ if (h323debug) {
+ cout << "Setting capabilities to " << ast_getformatname_multiple(caps_str, sizeof(caps_str), cap) << endl;
+ ast_codec_pref_string(prefs, caps_str, sizeof(caps_str));
+ cout << "Capabilities in preference order is " << caps_str << endl;
+ }
+ /* Add audio codecs in preference order first, then
+ audio codecs without preference as allowed by mask */
+ for (y = 0, x = -1; x < 32 + 32; ++x) {
+ if (x < 0)
+ codec = pref_codec;
+ else if (y || (!(codec = ast_codec_pref_index(prefs, x)))) {
+ if (!y)
+ y = 1;
+ else if (y == AST_FORMAT_MAX_AUDIO)
+ break;
+ else
+ y <<= 1;
+ codec = y;
+ }
+ if (!(cap & codec) || (alreadysent & codec) || !(codec & AST_FORMAT_AUDIO_MASK))
+ continue;
+ alreadysent |= codec;
+ switch(codec) {
#if 0
- if (cap & AST_FORMAT_SPEEX) {
- /* Not real sure if Asterisk acutally supports all
- of the various different bit rates so add them
- all and figure it out later*/
-
- localCapabilities.SetCapability(0, 0, new SpeexNarrow2AudioCapability());
- localCapabilities.SetCapability(0, 0, new SpeexNarrow3AudioCapability());
- localCapabilities.SetCapability(0, 0, new SpeexNarrow4AudioCapability());
- localCapabilities.SetCapability(0, 0, new SpeexNarrow5AudioCapability());
- localCapabilities.SetCapability(0, 0, new SpeexNarrow6AudioCapability());
- }
-#endif
- if (cap & AST_FORMAT_G729A) {
- AST_G729ACapability *g729aCap;
- AST_G729Capability *g729Cap;
- lastcap = localCapabilities.SetCapability(0, 0, g729aCap = new AST_G729ACapability);
- lastcap = localCapabilities.SetCapability(0, 0, g729Cap = new AST_G729Capability);
- }
-
- if (cap & AST_FORMAT_G723_1) {
- H323_G7231Capability *g7231Cap;
- lastcap = localCapabilities.SetCapability(0, 0, g7231Cap = new H323_G7231Capability);
- }
-#if 0
- if (cap & AST_FORMAT_GSM) {
- H323_GSM0610Capability *gsmCap;
- lastcap = localCapabilities.SetCapability(0, 0, gsmCap = new H323_GSM0610Capability);
- gsmCap->SetTxFramesInPacket(gsmFrames);
- }
+ case AST_FORMAT_SPEEX:
+ /* Not real sure if Asterisk acutally supports all
+ of the various different bit rates so add them
+ all and figure it out later*/
+
+ lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow2AudioCapability());
+ lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow3AudioCapability());
+ lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow4AudioCapability());
+ lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow5AudioCapability());
+ lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow6AudioCapability());
+ break;
#endif
- if (cap & AST_FORMAT_ULAW) {
- H323_G711Capability *g711uCap;
- lastcap = localCapabilities.SetCapability(0, 0, g711uCap = new H323_G711Capability(H323_G711Capability::muLaw));
- g711uCap->SetTxFramesInPacket(g711Frames);
- }
-
- if (cap & AST_FORMAT_ALAW) {
- H323_G711Capability *g711aCap;
- lastcap = localCapabilities.SetCapability(0, 0, g711aCap = new H323_G711Capability(H323_G711Capability::ALaw));
- g711aCap->SetTxFramesInPacket(g711Frames);
+ case AST_FORMAT_G729A:
+ AST_G729ACapability *g729aCap;
+ AST_G729Capability *g729Cap;
+ lastcap = localCapabilities.SetCapability(0, 0, g729aCap = new AST_G729ACapability);
+ lastcap = localCapabilities.SetCapability(0, 0, g729Cap = new AST_G729Capability);
+ break;
+ case AST_FORMAT_G723_1:
+ H323_G7231Capability *g7231Cap;
+ lastcap = localCapabilities.SetCapability(0, 0, g7231Cap = new H323_G7231Capability(TRUE));
+ lastcap = localCapabilities.SetCapability(0, 0, g7231Cap = new H323_G7231Capability(FALSE));
+ break;
+ case AST_FORMAT_GSM:
+ AST_GSM0610Capability *gsmCap;
+ lastcap = localCapabilities.SetCapability(0, 0, gsmCap = new AST_GSM0610Capability);
+ gsmCap->SetTxFramesInPacket(gsmFrames);
+ break;
+ case AST_FORMAT_ULAW:
+ H323_G711Capability *g711uCap;
+ lastcap = localCapabilities.SetCapability(0, 0, g711uCap = new H323_G711Capability(H323_G711Capability::muLaw));
+ g711uCap->SetTxFramesInPacket(g711Frames);
+ break;
+ case AST_FORMAT_ALAW:
+ H323_G711Capability *g711aCap;
+ lastcap = localCapabilities.SetCapability(0, 0, g711aCap = new H323_G711Capability(H323_G711Capability::ALaw));
+ g711aCap->SetTxFramesInPacket(g711Frames);
+ break;
+ default:
+ alreadysent &= ~codec;
+ break;
+ }
}
lastcap++;
lastcap = localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::HookFlashH245));
lastcap++;
- mode = dtmfMode;
- if (dtmfMode == H323_DTMF_INBAND) {
- localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneH245));
- sendUserInputMode = SendUserInputAsTone;
+ dtmfMode = dtmf_mode;
+ if (dtmf_mode == H323_DTMF_INBAND) {
+ localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::BasicString));
+ sendUserInputMode = SendUserInputAsString;
} else {
- localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneRFC2833));
- sendUserInputMode = SendUserInputAsInlineRFC2833;
+ lastcap = localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneRFC2833));
+ /* Cisco sends DTMF only through h245-alphanumeric or h245-signal, no support for RFC2833 */
+ lastcap = localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneH245));
+ sendUserInputMode = SendUserInputAsTone; /* RFC2833 transmission handled at Asterisk level */
}
if (h323debug) {
- cout << "Allowed Codecs:\n\t" << setprecision(2) << localCapabilities << endl;
+ cout << "Allowed Codecs:\n\t" << setprecision(2) << localCapabilities << endl;
}
}
+BOOL MyH323Connection::StartControlChannel(const H225_TransportAddress & h245Address)
+{
+ // Check that it is an IP address, all we support at the moment
+ if (h245Address.GetTag() != H225_TransportAddress::e_ipAddress
+#if P_HAS_IPV6
+ && h245Address.GetTag() != H225_TransportAddress::e_ip6Address
+#endif
+ ) {
+ PTRACE(1, "H225\tConnect of H245 failed: Unsupported transport");
+ return FALSE;
+ }
+
+ // Already have the H245 channel up.
+ if (controlChannel != NULL)
+ return TRUE;
+
+ PIPSocket::Address addr;
+ WORD port;
+ GetSignallingChannel()->GetLocalAddress().GetIpAndPort(addr, port);
+ if (addr) {
+ if (h323debug)
+ cout << "Using " << addr << " for outbound H.245 transport" << endl;
+ controlChannel = new MyH323TransportTCP(endpoint, addr);
+ } else
+ controlChannel = new H323TransportTCP(endpoint);
+ if (!controlChannel->SetRemoteAddress(h245Address)) {
+ PTRACE(1, "H225\tCould not extract H245 address");
+ delete controlChannel;
+ controlChannel = NULL;
+ return FALSE;
+ }
+ if (!controlChannel->Connect()) {
+ PTRACE(1, "H225\tConnect of H245 failed: " << controlChannel->GetErrorText());
+ delete controlChannel;
+ controlChannel = NULL;
+ return FALSE;
+ }
+
+ controlChannel->StartControlChannel(*this);
+ return TRUE;
+}
+
/* MyH323_ExternalRTPChannel */
MyH323_ExternalRTPChannel::MyH323_ExternalRTPChannel(MyH323Connection & connection,
- const H323Capability & capability,
- Directions direction,
- unsigned id)
- : H323_ExternalRTPChannel::H323_ExternalRTPChannel(connection, capability, direction, id)
-{
+ const H323Capability & capability,
+ Directions direction,
+ unsigned id)
+ : H323_ExternalRTPChannel::H323_ExternalRTPChannel(connection, capability, direction, id)
+{
struct rtp_info *info;
/* Determine the Local (A side) IP Address and port */
- info = on_external_rtp_create(connection.GetCallReference(), (const char *)connection.GetCallToken());
+ info = on_external_rtp_create(connection.GetCallReference(), (const char *)connection.GetCallToken());
if (!info) {
cout << "\tERROR: on_external_rtp_create failure" << endl;
return;
} else {
localIpAddr = info->addr;
localPort = info->port;
- /* tell the H.323 stack */
+ /* tell the H.323 stack */
SetExternalAddress(H323TransportAddress(localIpAddr, localPort), H323TransportAddress(localIpAddr, localPort + 1));
/* clean up allocated memory */
free(info);
@@ -1071,9 +1737,9 @@ MyH323_ExternalRTPChannel::MyH323_ExternalRTPChannel(MyH323Connection & connecti
/* Get the payload code */
OpalMediaFormat format(capability.GetFormatName(), FALSE);
payloadCode = format.GetPayloadType();
-}
+}
-MyH323_ExternalRTPChannel::~MyH323_ExternalRTPChannel()
+MyH323_ExternalRTPChannel::~MyH323_ExternalRTPChannel()
{
if (h323debug) {
cout << "\tExternalRTPChannel Destroyed" << endl;
@@ -1098,42 +1764,40 @@ BOOL MyH323_ExternalRTPChannel::Start(void)
if (h323debug) {
cout << "\t\t-- remoteIpAddress: " << remoteIpAddr << endl;
cout << "\t\t-- remotePort: " << remotePort << endl;
- cout << "\t\t-- ExternalIpAddress: " << localIpAddr << endl;
+ cout << "\t\t-- ExternalIpAddress: " << localIpAddr << endl;
cout << "\t\t-- ExternalPort: " << localPort << endl;
}
/* Notify Asterisk of remote RTP information */
- on_start_rtp_channel(connection.GetCallReference(), (const char *)remoteIpAddr.AsString(), remotePort,
+ on_start_rtp_channel(connection.GetCallReference(), (const char *)remoteIpAddr.AsString(), remotePort,
(const char *)connection.GetCallToken(), (int)payloadCode);
return TRUE;
}
BOOL MyH323_ExternalRTPChannel::OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param)
{
- PIPSocket::Address remoteIpAddress;
- WORD remotePort;
-
if (h323debug) {
cout << " MyH323_ExternalRTPChannel::OnReceivedAckPDU" << endl;
}
if (H323_ExternalRTPChannel::OnReceivedAckPDU(param)) {
- GetRemoteAddress(remoteIpAddress, remotePort);
+ GetRemoteAddress(remoteIpAddr, remotePort);
if (h323debug) {
- cout << " -- remoteIpAddress: " << remoteIpAddress << endl;
+ cout << " -- remoteIpAddress: " << remoteIpAddr << endl;
cout << " -- remotePort: " << remotePort << endl;
}
- on_start_rtp_channel(connection.GetCallReference(), (const char *)remoteIpAddress.AsString(),
+ on_start_rtp_channel(connection.GetCallReference(), (const char *)remoteIpAddr.AsString(),
remotePort, (const char *)connection.GetCallToken(), (int)payloadCode);
return TRUE;
}
return FALSE;
}
+
/** IMPLEMENTATION OF C FUNCTIONS */
/**
- * The extern "C" directive takes care for
- * the ANSI-C representation of linkable symbols
+ * The extern "C" directive takes care for
+ * the ANSI-C representation of linkable symbols
*/
extern "C" {
@@ -1145,12 +1809,12 @@ int h323_end_point_exist(void)
}
return 1;
}
-
+
void h323_end_point_create(void)
{
channelsOpen = 0;
logstream = new PAsteriskLog();
- localProcess = new MyProcess();
+ localProcess = new MyProcess();
localProcess->Main();
}
@@ -1159,33 +1823,34 @@ void h323_gk_urq(void)
if (!h323_end_point_exist()) {
cout << " ERROR: [h323_gk_urq] No Endpoint, this is bad" << endl;
return;
- }
+ }
endPoint->RemoveGatekeeper();
}
void h323_debug(int flag, unsigned level)
{
if (flag) {
- PTrace:: SetLevel(level);
- } else {
- PTrace:: SetLevel(0);
- }
-}
-
-/** Installs the callback functions on behalf of the PBX application */
-void h323_callback_register(setup_incoming_cb ifunc,
- setup_outbound_cb sfunc,
- on_rtp_cb rtpfunc,
- start_rtp_cb lfunc,
- clear_con_cb clfunc,
- chan_ringing_cb rfunc,
- con_established_cb efunc,
- send_digit_cb dfunc,
- answer_call_cb acfunc,
- progress_cb pgfunc,
- rfc2833_cb dtmffunc,
- hangup_cb hangupfunc,
- setcapabilities_cb capabilityfunc)
+ PTrace:: SetLevel(level);
+ } else {
+ PTrace:: SetLevel(0);
+ }
+}
+
+/** Installs the callback functions on behalf of the PBX application */
+void h323_callback_register(setup_incoming_cb ifunc,
+ setup_outbound_cb sfunc,
+ on_rtp_cb rtpfunc,
+ start_rtp_cb lfunc,
+ clear_con_cb clfunc,
+ chan_ringing_cb rfunc,
+ con_established_cb efunc,
+ receive_digit_cb dfunc,
+ answer_call_cb acfunc,
+ progress_cb pgfunc,
+ rfc2833_cb dtmffunc,
+ hangup_cb hangupfunc,
+ setcapabilities_cb capabilityfunc,
+ setpeercapabilities_cb peercapabilityfunc)
{
on_incoming_call = ifunc;
on_outgoing_call = sfunc;
@@ -1194,18 +1859,19 @@ void h323_callback_register(setup_incoming_cb ifunc,
on_connection_cleared = clfunc;
on_chan_ringing = rfunc;
on_connection_established = efunc;
- on_send_digit = dfunc;
+ on_receive_digit = dfunc;
on_answer_call = acfunc;
on_progress = pgfunc;
on_set_rfc2833_payload = dtmffunc;
on_hangup = hangupfunc;
on_setcapabilities = capabilityfunc;
+ on_setpeercapabilities = peercapabilityfunc;
}
/**
- * Add capability to the capability table of the end point.
+ * Add capability to the capability table of the end point.
*/
-int h323_set_capabilities(const char *token, int cap, int dtmfMode)
+int h323_set_capabilities(const char *token, int cap, int dtmf_mode, struct ast_codec_pref *prefs, int pref_codec)
{
MyH323Connection *conn;
@@ -1224,7 +1890,7 @@ int h323_set_capabilities(const char *token, int cap, int dtmfMode)
cout << " ERROR: [h323_set_capabilities] Unable to find connection " << token << endl;
return 1;
}
- conn->SetCapabilities(cap, dtmfMode);
+ conn->SetCapabilities((/*conn->bridging ? conn->redir_capabilities :*/ cap), dtmf_mode, prefs, pref_codec);
conn->Unlock();
return 0;
@@ -1233,29 +1899,28 @@ int h323_set_capabilities(const char *token, int cap, int dtmfMode)
/** Start the H.323 listener */
int h323_start_listener(int listenPort, struct sockaddr_in bindaddr)
{
-
+
if (!h323_end_point_exist()) {
cout << "ERROR: [h323_start_listener] No Endpoint, this is bad!" << endl;
return 1;
}
-
+
PIPSocket::Address interfaceAddress(bindaddr.sin_addr);
if (!listenPort) {
listenPort = 1720;
}
- /** H.323 listener */
+ /** H.323 listener */
H323ListenerTCP *tcpListener;
tcpListener = new H323ListenerTCP(*endPoint, interfaceAddress, (WORD)listenPort);
if (!endPoint->StartListener(tcpListener)) {
cout << "ERROR: Could not open H.323 listener port on " << ((H323ListenerTCP *) tcpListener)->GetListenerPort() << endl;
delete tcpListener;
return 1;
-
}
cout << " == H.323 listener started" << endl;
return 0;
};
-
+
int h323_set_alias(struct oh323_alias *alias)
{
char *p;
@@ -1263,14 +1928,14 @@ int h323_set_alias(struct oh323_alias *alias)
PString h323id(alias->name);
PString e164(alias->e164);
char *prefix;
-
+
if (!h323_end_point_exist()) {
cout << "ERROR: [h323_set_alias] No Endpoint, this is bad!" << endl;
return 1;
}
cout << "== Adding alias \"" << h323id << "\" to endpoint" << endl;
- endPoint->AddAliasName(h323id);
+ endPoint->AddAliasName(h323id);
endPoint->RemoveAliasName(localProcess->GetUserName());
if (!e164.IsEmpty()) {
@@ -1306,7 +1971,7 @@ void h323_show_tokens(void)
cout << "Current call tokens: " << setprecision(2) << endPoint->GetAllConnections() << endl;
}
-/** Establish Gatekeeper communiations, if so configured,
+/** Establish Gatekeeper communiations, if so configured,
* register aliases for the H.323 endpoint to respond to.
*/
int h323_set_gk(int gatekeeper_discover, char *gatekeeper, char *secret)
@@ -1329,14 +1994,14 @@ int h323_set_gk(int gatekeeper_discover, char *gatekeeper, char *secret)
}
if (gatekeeper_discover) {
/* discover the gk using multicast */
- if (endPoint->DiscoverGatekeeper(new H323TransportUDP(*endPoint))) {
+ if (endPoint->DiscoverGatekeeper(new MyH323TransportUDP(*endPoint))) {
cout << "== Using " << (endPoint->GetGatekeeper())->GetName() << " as our Gatekeeper." << endl;
} else {
cout << "Warning: Could not find a gatekeeper." << endl;
return 1;
- }
+ }
} else {
- rasChannel = new H323TransportUDP(*endPoint);
+ rasChannel = new MyH323TransportUDP(*endPoint);
if (!rasChannel) {
cout << "Error: No RAS Channel, this is bad" << endl;
@@ -1378,7 +2043,7 @@ int h323_make_call(char *dest, call_details_t *cd, call_options_t *call_options)
return 1;
}
- res = endPoint->MakeCall(host, token, &cd->call_reference, call_options);
+ res = endPoint->MyMakeCall(host, token, &cd->call_reference, call_options);
memcpy((char *)(cd->call_token), (const unsigned char *)token, token.GetLength());
return res;
};
@@ -1411,48 +2076,47 @@ int h323_clear_call(const char *call_token, int cause)
/* Send Alerting PDU to H.323 caller */
int h323_send_alerting(const char *token)
{
- const PString currentToken(token);
- H323Connection * connection;
-
- if (h323debug) {
- cout << "\tSending alerting\n" << endl;
- }
- connection = endPoint->FindConnectionWithLock(currentToken);
- if (!connection) {
- cout << "No connection found for " << token << endl;
- return -1;
- }
- connection->AnsweringCall(H323Connection::AnswerCallPending);
- connection->Unlock();
- return 0;
+ const PString currentToken(token);
+ H323Connection * connection;
+ if (h323debug) {
+ cout << "\tSending alerting" << endl;
+ }
+ connection = endPoint->FindConnectionWithLock(currentToken);
+ if (!connection) {
+ cout << "No connection found for " << token << endl;
+ return -1;
+ }
+ connection->AnsweringCall(H323Connection::AnswerCallPending);
+ connection->Unlock();
+ return 0;
}
/* Send Progress PDU to H.323 caller */
int h323_send_progress(const char *token)
{
- const PString currentToken(token);
- H323Connection * connection;
+ const PString currentToken(token);
+ H323Connection * connection;
- connection = endPoint->FindConnectionWithLock(currentToken);
- if (!connection) {
- cout << "No connection found for " << token << endl;
- return -1;
- }
- connection->AnsweringCall(H323Connection::AnswerCallDeferredWithMedia);
- connection->Unlock();
- return 0;
+ connection = endPoint->FindConnectionWithLock(currentToken);
+ if (!connection) {
+ cout << "No connection found for " << token << endl;
+ return -1;
+ }
+ connection->AnsweringCall(H323Connection::AnswerCallDeferredWithMedia);
+ connection->Unlock();
+ return 0;
}
-/** This function tells the h.323 stack to either
- answer or deny an incoming call */
-int h323_answering_call(const char *token, int busy)
+/** This function tells the h.323 stack to either
+ answer or deny an incoming call */
+int h323_answering_call(const char *token, int busy)
{
const PString currentToken(token);
H323Connection * connection;
-
+
connection = endPoint->FindConnectionWithLock(currentToken);
-
+
if (!connection) {
cout << "No connection found for " << token << endl;
return -1;
@@ -1472,44 +2136,39 @@ int h323_answering_call(const char *token, int busy)
return 0;
}
-int h323_show_codec(int fd, int argc, char *argv[])
-{
- cout << "Allowed Codecs:\n\t" << setprecision(2) << endPoint->GetCapabilities() << endl;
- return 0;
-}
-
int h323_soft_hangup(const char *data)
{
PString token(data);
BOOL result;
- cout << "Soft hangup" << endl;
- result = endPoint->ClearCall(token);
+ cout << "Soft hangup" << endl;
+ result = endPoint->ClearCall(token);
return result;
}
-/* alas, this doesn't work :( */
+/* alas, this doesn't work :( */
void h323_native_bridge(const char *token, const char *them, char *capability)
{
H323Channel *channel;
MyH323Connection *connection = (MyH323Connection *)endPoint->FindConnectionWithLock(token);
-
+
if (!connection) {
- cout << "ERROR: No connection found, this is bad\n";
+ cout << "ERROR: No connection found, this is bad" << endl;
return;
}
- cout << "Native Bridge: them [" << them << "]" << endl;
+ cout << "Native Bridge: them [" << them << "]" << endl;
channel = connection->FindChannel(connection->sessionId, TRUE);
connection->bridging = TRUE;
connection->CloseLogicalChannelNumber(channel->GetNumber());
-
+
connection->Unlock();
return;
}
#undef cout
+#undef endl
void h323_end_process(void)
{
if (endPoint) {
@@ -1521,10 +2180,12 @@ void h323_end_process(void)
if (localProcess) {
delete localProcess;
localProcess = NULL;
+ close(_timerChangePipe[0]);
+ close(_timerChangePipe[1]);
}
- PTrace::SetLevel(0);
- PTrace::SetStream(&cout);
if (logstream) {
+ PTrace::SetLevel(0);
+ PTrace::SetStream(&cout);
delete logstream;
logstream = NULL;
}
diff --git a/channels/h323/ast_h323.h b/channels/h323/ast_h323.h
index 5bab9fc3b..b866e2cde 100644
--- a/channels/h323/ast_h323.h
+++ b/channels/h323/ast_h323.h
@@ -13,24 +13,27 @@
* chan_h323 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.
+ * (at your option) any later version.
*
- * chan_h323 is distributed WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
+ * chan_h323 is distributed WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * Version Info: $Id$
+ * Version Info: $Id$
*/
#ifndef AST_H323_H
#define AST_H323_H
+#define VERSION(a,b,c) ((a)*10000+(b)*100+(c))
+
+#if 0
/** These need to be redefined here because the C++
- side of this driver is blind to the asterisk headers */
+ side of this driver is blind to the asterisk headers */
/*! G.723.1 compression */
#define AST_FORMAT_G723_1 (1 << 0)
/*! GSM compression */
@@ -52,114 +55,149 @@
/*! SpeeX Free Compression */
#define AST_FORMAT_SPEEX (1 << 9)
/*! ILBC Free Codec */
-#define AST_FORMAT_ILBC (1 << 10)
+#define AST_FORMAT_ILBC (1 << 10)
+#endif
/**This class describes the G.723.1 codec capability.
*/
class H323_G7231Capability : public H323AudioCapability
{
- PCLASSINFO(H323_G7231Capability, H323AudioCapability);
- public:
- H323_G7231Capability(BOOL annexA = TRUE);
- Comparison Compare(const PObject & obj) const;
- PObject * Clone() const;
- virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
- unsigned GetSubType() const;
- PString GetFormatName() const;
- BOOL OnSendingPDU(H245_AudioCapability & pdu, unsigned packetSize) const;
- BOOL OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize);
- protected:
- BOOL annexA;
+ PCLASSINFO(H323_G7231Capability, H323AudioCapability);
+
+public:
+ H323_G7231Capability(BOOL annexA = TRUE);
+ Comparison Compare(const PObject & obj) const;
+ virtual PObject * Clone() const;
+ virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
+ virtual unsigned GetSubType() const;
+ virtual PString GetFormatName() const;
+ virtual BOOL OnSendingPDU(H245_AudioCapability & pdu, unsigned packetSize) const;
+ virtual BOOL OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize);
+
+protected:
+ BOOL annexA;
};
/**This class describes the (fake) G729 codec capability.
*/
class AST_G729Capability : public H323AudioCapability
{
- PCLASSINFO(AST_G729Capability, H323AudioCapability);
+ PCLASSINFO(AST_G729Capability, H323AudioCapability);
- public:
- AST_G729Capability();
- /* Create a copy of the object. */
- virtual PObject * Clone() const;
+public:
+ AST_G729Capability();
+ /* Create a copy of the object. */
+ virtual PObject * Clone() const;
- /* Create the codec instance, allocating resources as required. */
- virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
+ /* Create the codec instance, allocating resources as required. */
+ virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
- /* Get the sub-type of the capability. This is a code dependent on the
- main type of the capability.
+ /* Get the sub-type of the capability. This is a code dependent on the
+ main type of the capability.
- This returns one of the four possible combinations of mode and speed
- using the enum values of the protocol ASN H245_AudioCapability class. */
- virtual unsigned GetSubType() const;
-
- /* Get the name of the media data format this class represents. */
- virtual PString GetFormatName() const;
+ This returns one of the four possible combinations of mode and speed
+ using the enum values of the protocol ASN H245_AudioCapability class. */
+ virtual unsigned GetSubType() const;
+ /* Get the name of the media data format this class represents. */
+ virtual PString GetFormatName() const;
};
/* This class describes the VoiceAge G729A codec capability. */
class AST_G729ACapability : public H323AudioCapability
{
- PCLASSINFO(AST_G729ACapability, H323AudioCapability);
+ PCLASSINFO(AST_G729ACapability, H323AudioCapability);
- public:
- /* Create a new G.729A capability. */
- AST_G729ACapability();
+public:
+ /* Create a new G.729A capability. */
+ AST_G729ACapability();
- /* Create a copy of the object. */
- virtual PObject * Clone() const;
- /* Create the codec instance, allocating resources as required. */
- virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
+ /* Create a copy of the object. */
+ virtual PObject * Clone() const;
+ /* Create the codec instance, allocating resources as required. */
+ virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
- /* Get the sub-type of the capability. This is a code dependent on the
- main type of the capability.
+ /* Get the sub-type of the capability. This is a code dependent on the
+ main type of the capability.
- This returns one of the four possible combinations of mode and speed
- using the enum values of the protocol ASN H245_AudioCapability class. */
- virtual unsigned GetSubType() const;
+ This returns one of the four possible combinations of mode and speed
+ using the enum values of the protocol ASN H245_AudioCapability class. */
+ virtual unsigned GetSubType() const;
- /* Get the name of the media data format this class represents. */
- virtual PString GetFormatName() const;
+ /* Get the name of the media data format this class represents. */
+ virtual PString GetFormatName() const;
};
-class MyH323EndPoint : public H323EndPoint {
+/* This class describes the GSM-06.10 codec capability. */
+class AST_GSM0610Capability : public H323AudioCapability
+{
+ PCLASSINFO(AST_GSM0610Capability, H323AudioCapability);
+
+public:
+ /* Create a new GSM capability. */
+ AST_GSM0610Capability(int comfortNoise = 0, int scrambled = 0);
+
+ /* Create a copy of the object. */
+ virtual PObject * Clone() const;
+
+ /* Create the codec instance, allocating resources as required. */
+ virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
+ /* Get the sub-type of the capability. This is a code dependent on the
+ main type of the capability.
+
+ This returns one of the four possible combinations of mode and speed
+ using the enum values of the protocol ASN H245_AudioCapability class. */
+ virtual unsigned GetSubType() const;
+
+ /* Get the name of the media data format this class represents. */
+ virtual PString GetFormatName() const;
+
+ BOOL OnSendingPDU(H245_AudioCapability & pdu, unsigned packetSize) const;
+ BOOL OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize);
+
+protected:
+ int comfortNoise;
+ int scrambled;
+};
+
+class MyH323EndPoint : public H323EndPoint
+{
PCLASSINFO(MyH323EndPoint, H323EndPoint);
- public:
+public:
MyH323EndPoint();
- int MakeCall(const PString &, PString &, unsigned int *, call_options_t *opts);
+ int MyMakeCall(const PString &, PString &, void *_callReference, void *_opts);
BOOL ClearCall(const PString &, H323Connection::CallEndReason reason);
BOOL ClearCall(const PString &);
void OnClosedLogicalChannel(H323Connection &, const H323Channel &);
void OnConnectionEstablished(H323Connection &, const PString &);
void OnConnectionCleared(H323Connection &, const PString &);
- H323Connection * CreateConnection(unsigned, void *);
+ virtual H323Connection * CreateConnection(unsigned, void *, H323Transport *, H323SignalPDU *);
void SendUserTone(const PString &, char);
BOOL OnConnectionForwarded(H323Connection &, const PString &, const H323SignalPDU &);
BOOL ForwardConnection(H323Connection &, const PString &, const H323SignalPDU &);
- void SetEndpointTypeInfo( H225_EndpointType & info ) const;
- void SetGateway(void);
- PStringArray SupportedPrefixes;
+ void SetEndpointTypeInfo( H225_EndpointType & info ) const;
+ void SetGateway(void);
+ PStringArray SupportedPrefixes;
};
-class MyH323Connection : public H323Connection {
-
+class MyH323Connection : public H323Connection
+{
PCLASSINFO(MyH323Connection, H323Connection);
- public:
+public:
MyH323Connection(MyH323EndPoint &, unsigned, unsigned);
~MyH323Connection();
- H323Channel * CreateRealTimeLogicalChannel(const H323Capability &,
- H323Channel::Directions,
- unsigned,
- const H245_H2250LogicalChannelParameters *,
- RTP_QOS *);
- H323Connection::AnswerCallResponse OnAnswerCall(const PString &,
- const H323SignalPDU &,
- H323SignalPDU &);
+ H323Channel * CreateRealTimeLogicalChannel(const H323Capability &,
+ H323Channel::Directions,
+ unsigned,
+ const H245_H2250LogicalChannelParameters *,
+ RTP_QOS *);
+ H323Connection::AnswerCallResponse OnAnswerCall(const PString &,
+ const H323SignalPDU &,
+ H323SignalPDU &);
void OnReceivedReleaseComplete(const H323SignalPDU &);
BOOL OnAlerting(const H323SignalPDU &, const PString &);
BOOL OnSendReleaseComplete(H323SignalPDU &);
@@ -167,46 +205,57 @@ class MyH323Connection : public H323Connection {
BOOL OnReceivedFacility(const H323SignalPDU &);
BOOL OnSendSignalSetup(H323SignalPDU &);
BOOL OnStartLogicalChannel(H323Channel &);
- BOOL OnClosingLogicalChannel(H323Channel &);
- void SendUserInputTone(char, unsigned);
- void OnUserInputTone(char, unsigned, unsigned, unsigned);
- void OnUserInputString(const PString &value);
+ BOOL OnClosingLogicalChannel(H323Channel &);
+ virtual void SendUserInputTone(char tone, unsigned duration = 0, unsigned logicalChannel = 0, unsigned rtpTimestamp = 0);
+ virtual void OnUserInputTone(char, unsigned, unsigned, unsigned);
+ virtual void OnUserInputString(const PString &value);
BOOL OnReceivedProgress(const H323SignalPDU &);
void OnSendCapabilitySet(H245_TerminalCapabilitySet &);
void OnSetLocalCapabilities();
- void SetCapabilities(int, int);
+ void SetCapabilities(int, int, void *, int);
BOOL OnReceivedCapabilitySet(const H323Capabilities &, const H245_MultiplexCapability *,
- H245_TerminalCapabilitySetReject &);
+ H245_TerminalCapabilitySetReject &);
void SetCause(int _cause) { cause = _cause; };
+ virtual BOOL StartControlChannel(const H225_TransportAddress & h245Address);
+ void SetCallOptions(void *opts, BOOL isIncoming);
+ void SetCallDetails(void *callDetails, const H323SignalPDU &setupPDU, BOOL isIncoming);
+#ifdef TUNNELLING
+ virtual BOOL HandleSignalPDU(H323SignalPDU &pdu);
+ BOOL EmbedTunneledInfo(H323SignalPDU &pdu);
+#endif
PString sourceAliases;
PString destAliases;
PString sourceE164;
PString destE164;
+ PString rdnis;
+ int redirect_reason;
WORD sessionId;
- BOOL bridging;
+ BOOL bridging;
+#ifdef TUNNELLING
+ int remoteTunnelOptions;
+ int tunnelOptions;
+#endif
unsigned progressSetup;
unsigned progressAlert;
int cause;
RTP_DataFrame::PayloadTypes dtmfCodec;
-
- PString ast_cid_num;
- PString ast_cid_name;
+ int dtmfMode;
};
-class MyH323_ExternalRTPChannel : public H323_ExternalRTPChannel {
-
- PCLASSINFO(MyH323_ExternalRTPChannel, H323_ExternalRTPChannel);
+class MyH323_ExternalRTPChannel : public H323_ExternalRTPChannel
+{
+ PCLASSINFO(MyH323_ExternalRTPChannel, H323_ExternalRTPChannel);
- public:
+public:
MyH323_ExternalRTPChannel(
- MyH323Connection & connection,
- const H323Capability & capability,
- Directions direction,
- unsigned sessionID);
+ MyH323Connection & connection,
+ const H323Capability & capability,
+ Directions direction,
+ unsigned sessionID);
~MyH323_ExternalRTPChannel();
@@ -214,26 +263,29 @@ class MyH323_ExternalRTPChannel : public H323_ExternalRTPChannel {
BOOL Start(void);
BOOL OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param);
- protected:
+protected:
BYTE payloadCode;
PIPSocket::Address localIpAddr;
PIPSocket::Address remoteIpAddr;
- WORD localPort;
- WORD remotePort;
-};
+ WORD localPort;
+ WORD remotePort;
+};
/**
- * The MyProcess is a necessary descendant PProcess class so that the H323EndPoint
- * objected to be created from within that class. (Solves the who owns main() problem).
+ * The MyProcess is a necessary descendant PProcess class so that the H323EndPoint
+ * objected to be created from within that class. (Solves the who owns main() problem).
*/
-class MyProcess : public PProcess {
-
+class MyProcess : public PProcess
+{
PCLASSINFO(MyProcess, PProcess);
-
- public:
+
+public:
MyProcess();
- void Main();
+ ~MyProcess();
+ void Main();
};
+#include "compat_h323.h"
+
#endif /* !defined AST_H323_H */
diff --git a/channels/h323/chan_h323.h b/channels/h323/chan_h323.h
index 1ca681c77..d6be63f4f 100644
--- a/channels/h323/chan_h323.h
+++ b/channels/h323/chan_h323.h
@@ -4,8 +4,8 @@
* OpenH323 Channel Driver for ASTERISK PBX.
* By Jeremy McNamara
* For The NuFone Network
- *
- * This code has been derived from code created by
+ *
+ * This code has been derived from code created by
* Michael Manousos and Mark Spencer
*
* This file is part of the chan_h323 driver for Asterisk
@@ -13,29 +13,42 @@
* chan_h323 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.
+ * (at your option) any later version.
*
- * chan_h323 is distributed WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
+ * chan_h323 is distributed WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Version Info: $Id$
*/
#include <arpa/inet.h>
+/*
+ * Enable support for sending/reception of tunnelled Q.SIG messages and
+ * some sort of IEs (especially RedirectingNumber) which Cisco CallManager
+ * isn't like to pass in standard Q.931 message.
+ *
+ */
+#define TUNNELLING
+
+#define H323_TUNNEL_CISCO (1 << 0)
+#define H323_TUNNEL_QSIG (1 << 1)
+
/** call_option struct holds various bits
* of information for each call */
typedef struct call_options {
char cid_num[80];
char cid_name[80];
- int noFastStart;
- int noH245Tunneling;
- int noSilenceSuppression;
+ char cid_rdnis[80];
+ int redirect_reason;
+ int fastStart;
+ int h245Tunneling;
+ int silenceSuppression;
int progress_setup;
int progress_alert;
int progress_audio;
@@ -44,57 +57,58 @@ typedef struct call_options {
int capability;
int bridge;
int nat;
+ int tunnelOptions;
+ struct ast_codec_pref prefs;
} call_options_t;
/* structure to hold the valid asterisk users */
struct oh323_user {
- char name[80];
+ ASTOBJ_COMPONENTS(struct oh323_user);
+// char name[80];
char context[80];
char secret[80];
- char callerid[80];
char accountcode[AST_MAX_ACCOUNT_CODE];
int amaflags;
int host;
struct sockaddr_in addr;
struct ast_ha *ha;
call_options_t options;
- struct oh323_user *next;
};
-/* structure to hold the valid asterisk peers
+/* structure to hold the valid asterisk peers
All peers are registered to a GK if there is one */
struct oh323_peer {
- char name[80];
+ ASTOBJ_COMPONENTS(struct oh323_peer);
char mailbox[80];
int delme;
struct sockaddr_in addr;
struct ast_ha *ha;
call_options_t options;
- struct oh323_peer *next;
};
-/* structure to hold the H.323 aliases which get registered to
+/* structure to hold the H.323 aliases which get registered to
the H.323 endpoint and gatekeeper */
struct oh323_alias {
- char name[80];
+ ASTOBJ_COMPONENTS(struct oh323_alias);
char e164[20]; /* tells a GK to route this E.164 to this alias */
char prefix[500]; /* tells a GK this alias supports these prefixes */
char secret[20]; /* the H.235 password to send to the GK for authentication */
char context[80];
- struct oh323_alias *next;
};
-/** call_details struct call detail records
- to asterisk for processing and used for matching up
+/** call_details struct call detail records
+ to asterisk for processing and used for matching up
asterisk channels to acutal h.323 connections */
-typedef struct call_details {
+typedef struct call_details {
unsigned int call_reference;
- char *call_token;
+ char *call_token;
char *call_source_aliases;
char *call_dest_alias;
char *call_source_name;
char *call_source_e164;
char *call_dest_e164;
+ char *redirect_number;
+ int redirect_reason;
int presentation;
int screening;
char *sourceIp;
@@ -107,18 +121,18 @@ typedef struct rtp_info {
/* This is a callback prototype function, called pass
DTMF down the RTP. */
-typedef int (*send_digit_cb)(unsigned, char, const char *);
-extern send_digit_cb on_send_digit;
+typedef int (*receive_digit_cb)(unsigned, char, const char *, int);
+extern receive_digit_cb on_receive_digit;
/* This is a callback prototype function, called to collect
the external RTP port from Asterisk. */
typedef rtp_info_t *(*on_rtp_cb)(unsigned, const char *);
-extern on_rtp_cb on_external_rtp_create;
+extern on_rtp_cb on_external_rtp_create;
/* This is a callback prototype function, called to send
- the remote IP and RTP port from H.323 to Asterisk */
+ the remote IP and RTP port from H.323 to Asterisk */
typedef void (*start_rtp_cb)(unsigned int, const char *, int, const char *, int);
-extern start_rtp_cb on_start_rtp_channel;
+extern start_rtp_cb on_start_rtp_channel;
/* This is a callback that happens when call progress is
* made, and handles inband progress */
@@ -133,7 +147,7 @@ extern setup_incoming_cb on_incoming_call;
/* This is a callback prototype function, called upon
an outbound call. */
typedef int (*setup_outbound_cb)(call_details_t *);
-extern setup_outbound_cb on_outgoing_call;
+extern setup_outbound_cb on_outgoing_call;
/* This is a callback prototype function, called when
OnAlerting is invoked */
@@ -151,7 +165,7 @@ typedef void (*clear_con_cb)(unsigned, const char *);
extern clear_con_cb on_connection_cleared;
/* This is a callback prototype function, called when
- an H.323 call is answered */
+ an H.323 call is answered */
typedef int (*answer_call_cb)(unsigned, const char *);
extern answer_call_cb on_answer_call;
@@ -167,6 +181,9 @@ extern hangup_cb on_hangup;
typedef void (*setcapabilities_cb)(unsigned, const char *);
extern setcapabilities_cb on_setcapabilities;
+typedef void (*setpeercapabilities_cb)(unsigned, const char *, int);
+extern setpeercapabilities_cb on_setpeercapabilities;
+
/* debug flag */
extern int h323debug;
@@ -179,30 +196,31 @@ extern int h323debug;
#ifdef __cplusplus
extern "C" {
-#endif
-
+#endif
+
void h323_gk_urq(void);
void h323_end_point_create(void);
void h323_end_process(void);
int h323_end_point_exist(void);
-
+
void h323_debug(int, unsigned);
/* callback function handler*/
- void h323_callback_register(setup_incoming_cb,
- setup_outbound_cb,
- on_rtp_cb,
- start_rtp_cb,
- clear_con_cb,
- chan_ringing_cb,
- con_established_cb,
- send_digit_cb,
- answer_call_cb,
- progress_cb,
- rfc2833_cb,
- hangup_cb,
- setcapabilities_cb);
- int h323_set_capabilities(const char *, int, int);
+ void h323_callback_register(setup_incoming_cb,
+ setup_outbound_cb,
+ on_rtp_cb,
+ start_rtp_cb,
+ clear_con_cb,
+ chan_ringing_cb,
+ con_established_cb,
+ receive_digit_cb,
+ answer_call_cb,
+ progress_cb,
+ rfc2833_cb,
+ hangup_cb,
+ setcapabilities_cb,
+ setpeercapabilities_cb);
+ int h323_set_capabilities(const char *, int, int, struct ast_codec_pref *, int);
int h323_set_alias(struct oh323_alias *);
int h323_set_gk(int, char *, char *);
void h323_set_id(char *);
@@ -219,12 +237,12 @@ extern "C" {
/* H323 create and destroy sessions */
int h323_make_call(char *dest, call_details_t *cd, call_options_t *);
int h323_clear_call(const char *, int cause);
-
+
/* H.323 alerting and progress */
int h323_send_alerting(const char *token);
int h323_send_progress(const char *token);
int h323_answering_call(const char *token, int);
- int h323_soft_hangup(const char *data);
+ int h323_soft_hangup(const char *data);
int h323_show_codec(int fd, int argc, char *argv[]);
#ifdef __cplusplus
diff --git a/channels/h323/h323.conf.sample b/channels/h323/h323.conf.sample
index 164397580..e69de29bb 100644
--- a/channels/h323/h323.conf.sample
+++ b/channels/h323/h323.conf.sample
@@ -1,149 +0,0 @@
-; The NuFone Network's
-; Open H.323 driver configuration
-;
-[general]
-port = 1720
-bindaddr = 1.2.3.4 ; this SHALL contain a single, valid IP address for this machine
-;tos=lowdelay
-;
-; You may specify a global default AMA flag for iaxtel calls. It must be
-; one of 'default', 'omit', 'billing', or 'documentation'. These flags
-; are used in the generation of call detail records.
-;
-;amaflags = default
-;
-; You may specify a default account for Call Detail Records in addition
-; to specifying on a per-user basis
-;
-;accountcode=lss0101
-;
-; You can fine tune codecs here using "allow" and "disallow" clauses
-; with specific codecs. Use "all" to represent all formats.
-;
-disallow=all
-;allow=all ; turns on all installed codecs
-;disallow=g723.1 ; Hm... Proprietary, don't use it...
-allow=gsm ; Always allow GSM, it's cool :)
-;
-; User-Input Mode (DTMF)
-;
-; valid entries are: rfc2833, inband
-; default is rfc2833
-;dtmfmode=rfc2833
-;
-; Default RTP Payload to send RFC2833 DTMF on. This is used to
-; interoperate with broken gateways which cannot successfully
-; negotiate a RFC2833 payload type in the TerminalCapabilitySet.
-;
-; You may also specify on either a per-peer or per-user basis below.
-;dtmfcodec=101
-;
-; Set the gatekeeper
-; DISCOVER - Find the Gk address using multicast
-; DISABLE - Disable the use of a GK
-; <IP address> or <Host name> - The acutal IP address or hostname of your GK
-;gatekeeper = DISABLE
-;
-;
-; Tell Asterisk whether or not to accept Gatekeeper
-; routed calls or not. Normally this should always
-; be set to yes, unless you want to have finer control
-; over which users are allowed access to Asterisk.
-; Default: YES
-;
-;AllowGKRouted = yes
-;
-; Optionally you can determine a user by Source IP versus its H.323 alias.
-; Default behavour is to determine user by H.323 alias.
-;UserByAlias=no
-;
-; Default context gets used in siutations where you are using
-; the GK routed model or no type=user was found. This gives you
-; the ability to either play an invalid message or to simply not
-; use user authentication at all.
-;
-;context=default
-;------------------------------ JITTER BUFFER CONFIGURATION --------------------------
-; jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of a
- ; H323 channel. Defaults to "no". An enabled jitterbuffer will
- ; be used only if the sending side can create and the receiving
- ; side can not accept jitter. The H323 channel can accept jitter,
- ; thus an enabled jitterbuffer on the receive H323 side will only
- ; be used if the sending side can create jitter and jbforce is
- ; also set to yes.
-
-; jbforce = no ; Forces the use of a jitterbuffer on the receive side of a H323
- ; channel. Defaults to "no".
-
-; jbmaxsize = 200 ; Max length of the jitterbuffer in milliseconds.
-
-; jbresyncthreshold = 1000 ; Jump in the frame timestamps over which the jitterbuffer is
- ; resynchronized. Useful to improve the quality of the voice, with
- ; big jumps in/broken timestamps, usualy sent from exotic devices
- ; and programs. Defaults to 1000.
-
-; jbimpl = fixed ; Jitterbuffer implementation, used on the receiving side of a H323
- ; channel. Two implementations are currenlty available - "fixed"
- ; (with size always equals to jbmax-size) and "adaptive" (with
- ; variable size, actually the new jb of IAX2). Defaults to fixed.
-
-; jblog = no ; Enables jitterbuffer frame logging. Defaults to "no".
-;-----------------------------------------------------------------------------------
-;
-; H.323 Alias definitions
-;
-; Type 'h323' will register aliases to the endpoint
-; and Gatekeeper, if there is one.
-;
-; Example: if someone calls time@your.asterisk.box.com
-; Asterisk will send the call to the extension 'time'
-; in the context default
-;
-; [default]
-; exten => time,1,Answer
-; exten => time,2,Playback,current-time
-;
-; Keyword's 'prefix' and 'e164' are only make sense when
-; used with a gatekeeper. You can specify either a prefix
-; or E.164 this endpoint is responsible for terminating.
-;
-; Example: The H.323 alias 'det-gw' will tell the gatekeeper
-; to route any call with the prefix 1248 to this alias. Keyword
-; e164 is used when you want to specifiy a full telephone
-; number. So a call to the number 18102341212 would be
-; routed to the H.323 alias 'time'.
-;
-;[time]
-;type=h323
-;e164=18102341212
-;context=default
-;
-;[det-gw]
-;type=h323
-;prefix=1248,1313
-;context=detroit
-;
-;
-; Inbound H.323 calls from BillyBob would land in the incoming
-; context with a maximum of 4 concurrent incoming calls
-;
-;
-; Note: If keyword 'incominglimit' are omitted Asterisk will not
-; enforce any maximum number of concurrent calls.
-;
-;[BillyBob]
-;type=user
-;host=192.168.1.1
-;context=incoming
-;incominglimit=4
-;
-;
-; Outbound H.323 call to Larry using SlowStart
-;
-[Larry]
-type=peer
-host=192.168.2.1
-noFastStart=yes
-
-
-
diff --git a/configure.ac b/configure.ac
index 7f7fa4904..167a402be 100644
--- a/configure.ac
+++ b/configure.ac
@@ -195,6 +195,7 @@ AST_EXT_LIB_SETUP([POPT], [popt], [popt])
AST_EXT_LIB_SETUP([PGSQL], [PostgreSQL], [postgres])
AST_EXT_LIB_SETUP([PRI], [ISDN PRI], [pri])
AST_EXT_LIB_SETUP([PWLIB], [PWlib], [pwlib])
+AST_EXT_LIB_SETUP([OPENH323], [OpenH323], [h323])
AST_EXT_LIB_SETUP([QT], [Qt], [qt])
AST_EXT_LIB_SETUP([RADIUS], [Radius Client], [radius])
AST_EXT_LIB_SETUP([SPEEX], [Speex], [speex])
@@ -701,49 +702,58 @@ AST_EXT_LIB_CHECK([POPT], [popt], [poptStrerror], [popt.h])
AST_EXT_LIB_CHECK([PRI], [pri], [pri_call], [libpri.h])
-PLATFORM_PTLIB="ptlib_${OSTYPE}_${MACHTYPE}_r"
if test "${USE_PWLIB}" != "no"; then
- AC_MSG_CHECKING(for existence of pwlib)
-
- saved_cppflags="${CPPFLAGS}"
- saved_libs="${LIBS}"
- LIBS="${LIBS} -L${PWLIB_DIR} -l${PLATFORM_PTLIB}"
- CPPFLAGS="${CPPFLAGS} -I${PWLIB_DIR}/include"
-
- AC_LINK_IFELSE(
- [
- AC_LANG_PROGRAM(
- [#include "ptime.h"],
- [int q = PTime::IsDaylightSaving();])
- ],
- [ AC_MSG_RESULT(yes)
- ac_cv_lib_pwlib="yes"
- ],
- [ AC_MSG_RESULT(no)
- ac_cv_lib_pwlib="no"
- ]
- )
+ if test ! -z "${PWLIB_DIR}"; then
+ PWLIBDIR="${PWLIB_DIR}"
+ fi
+ AST_CHECK_PWLIB()
+ AST_CHECK_PWLIB_VERSION([PWLib], [PWLIB], [ptbuildopts.h], [1], [9], [2])
+
+ if test "${HAS_PWLIB:-unset}" != "unset"; then
+ AST_CHECK_OPENH323_PLATFORM()
- LIBS="${saved_libs}"
- CPPFLAGS="${saved_cppflags}"
+ PLATFORM_PWLIB="pt_${PWLIB_PLATFORM}_r"
- if test "${ac_cv_lib_pwlib}" = "yes"; then
- PWLIB_LIB="-l{PLATFORM_PWLIB}"
- if test "${PWLIB_DIR}" != ""; then
- PWLIB_LIB="-L${PWLIB_DIR}/lib ${PWLIB_LIB}"
- PWLIB_INCLUDE="-I${PWLIB_DIR}/include"
- fi
- PBX_PWLIB=1
- AC_DEFINE([HAVE_PWLIB], 1, [Define if your system has the pwlib libraries.])
- elif test ! -z "${PWLIB_MANDATORY}"; then
- AC_MSG_NOTICE(***)
- AC_MSG_NOTICE(*** The PWLIB installation on this system appears to be broken.)
- AC_MSG_NOTICE(*** Either correct the installation, or run configure)
- AC_MSG_NOTICE(*** including --without-pwlib)
- exit 1
- fi
+ AST_CHECK_PWLIB_BUILD([PWLib], [PWLIB],
+ [Define if your system has the PWLib libraries.],
+ [#include "ptlib.h"],
+ [BOOL q = PTime::IsDaylightSavings();])
+ fi
+fi
+
+if test "${USE_PWLIB}" != "no" -a "x${ac_cv_lib_PWLIB}" != "xyes" -a ! -z "${PWLIB_MANDATORY}"; then
+ AC_MSG_NOTICE(***)
+ AC_MSG_NOTICE(*** The PWLIB installation on this system appears to be broken.)
+ AC_MSG_NOTICE(*** Either correct the installation, or run configure)
+ AC_MSG_NOTICE(*** including --without-pwlib)
+ exit 1
fi
+if test "${PBX_PWLIB}" = "1" -a "${USE_OPENH323}" != "no" ; then
+ if test ! -z "${OPENH323_DIR}"; then
+ OPENH323DIR="${OPENH323_DIR}"
+ fi
+ AST_CHECK_OPENH323()
+ AST_CHECK_PWLIB_VERSION([OpenH323], [OPENH323], [openh323buildopts.h], [1], [17], [3])
+ AST_CHECK_OPENH323_BUILD()
+ PLATFORM_OPENH323="h323_${PWLIB_PLATFORM}_${OPENH323_SUFFIX}"
+ AST_CHECK_PWLIB_BUILD([OpenH323], [OPENH323],
+ [Define if your system has the OpenH323 libraries.],
+ [#include "ptlib.h"
+ #include "h323.h"
+ #include "h323ep.h"],
+ [H323EndPoint ep = H323EndPoint();],
+ [${PWLIB_INCLUDE}], [${PWLIB_LIB}])
+fi
+if test "${USE_OPENH323}" != "no" -a "x${ac_cv_lib_OPENH323}" != "xyes" -a ! -z "${OPENH323_MANDATORY}"; then
+ AC_MSG_NOTICE(***)
+ AC_MSG_NOTICE(*** The PWLIB installation on this system appears to be broken.)
+ AC_MSG_NOTICE(*** Either correct the installation, or run configure)
+ AC_MSG_NOTICE(*** including --without-pwlib)
+ exit 1
+fi
+
+
AC_LANG_PUSH(C++)
if test "${USE_QT}" != "no"; then
@@ -1000,7 +1010,7 @@ AC_SUBST(PBX_CURL)
AC_SUBST(CURL_INCLUDE)
AC_SUBST(CURL_LIB)
-AC_CONFIG_FILES([build_tools/menuselect-deps makeopts])
+AC_CONFIG_FILES([build_tools/menuselect-deps makeopts channels/h323/Makefile])
AC_OUTPUT
if test "x${silent}" != "xyes" ; then
diff --git a/doc/realtime.txt b/doc/realtime.txt
index af592024a..b9bfad0f9 100644
--- a/doc/realtime.txt
+++ b/doc/realtime.txt
@@ -52,6 +52,11 @@ the ones in static configuration.
With caching, the device stays in memory for a specified time. More
information about this is to be found in the sip.conf sample file.
+* Realtime H.323 friends
+------------------------
+Like SIP realtime friends, H.323 friends aslo can be configured using
+dynamic realtime objects.
+
* New function in the dial plan: The Realtime Switch
----------------------------------------------------
The realtime switch is more than a port of functionality in v1.0 to the
diff --git a/main/Makefile b/main/Makefile
index c1b397803..da2197f9b 100644
--- a/main/Makefile
+++ b/main/Makefile
@@ -115,6 +115,13 @@ AST_EMBED_LDFLAGS:=$(foreach dep,$(EMBED_LDFLAGS),$(value $(dep)))
AST_EMBED_LIBS:=$(foreach dep,$(EMBED_LIBS),$(value $(dep)))
OBJS:=$(sort $(OBJS))
+ifneq ($(wildcard ../channels/h323/Makefile.ast),)
+ include ../channels/h323/Makefile.ast
+else
+ H323LDFLAGS=
+ H323LDLIBS=
+endif
+
asterisk: $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS)
@$(ASTTOPDIR)/build_tools/make_build_h > $(ASTTOPDIR)/include/asterisk/build.h.tmp
@if cmp -s $(ASTTOPDIR)/include/asterisk/build.h.tmp $(ASTTOPDIR)/include/asterisk/build.h ; then echo ; else \
@@ -123,7 +130,7 @@ asterisk: $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS)
@rm -f $(ASTTOPDIR)/include/asterisk/build.h.tmp
@$(CC) -c -o buildinfo.o $(CFLAGS) buildinfo.c
$(ECHO_PREFIX) echo " [LD] $^ -> $@"
- $(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o asterisk $(ASTLINK) $(AST_EMBED_LDFLAGS) $(LDFLAGS) $^ buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS)
+ $(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o asterisk $(ASTLINK) $(AST_EMBED_LDFLAGS) $(LDFLAGS) $(H323LDFLAGS) $^ buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(H323LDLIBS)
clean::
rm -f asterisk