aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/channels/h323
diff options
context:
space:
mode:
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2008-01-19 00:19:29 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2008-01-19 00:19:29 +0000
commitf8247040e6231c4b3b5099ea3a526348b7941566 (patch)
tree0cc92ad6ebf6ae49a62f6e7ef8ec819121d63630 /trunk/channels/h323
parentd88e56c61ce2042544c1a8a71c93b69ab2e6ffba (diff)
Creating tag for the release of asterisk-1.6.0-beta1v1.6.0-beta1
git-svn-id: http://svn.digium.com/svn/asterisk/tags/1.6.0-beta1@99163 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'trunk/channels/h323')
-rw-r--r--trunk/channels/h323/ChangeLog43
-rw-r--r--trunk/channels/h323/INSTALL.openh32318
-rw-r--r--trunk/channels/h323/Makefile.in48
-rw-r--r--trunk/channels/h323/README144
-rw-r--r--trunk/channels/h323/TODO9
-rw-r--r--trunk/channels/h323/ast_h323.cxx2637
-rw-r--r--trunk/channels/h323/ast_h323.h189
-rw-r--r--trunk/channels/h323/caps_h323.cxx383
-rw-r--r--trunk/channels/h323/caps_h323.h172
-rw-r--r--trunk/channels/h323/chan_h323.h269
-rw-r--r--trunk/channels/h323/cisco-h225.asn74
-rw-r--r--trunk/channels/h323/cisco-h225.cxx853
-rw-r--r--trunk/channels/h323/cisco-h225.h299
-rw-r--r--trunk/channels/h323/compat_h323.cxx138
-rw-r--r--trunk/channels/h323/compat_h323.h94
-rw-r--r--trunk/channels/h323/noexport.map5
16 files changed, 5375 insertions, 0 deletions
diff --git a/trunk/channels/h323/ChangeLog b/trunk/channels/h323/ChangeLog
new file mode 100644
index 000000000..ddbf08193
--- /dev/null
+++ b/trunk/channels/h323/ChangeLog
@@ -0,0 +1,43 @@
+Build
+ -- Hold lock when creating new H.323 channel to sync the audio channels
+ -- Decrement usage counter when appropriate
+ -- Actually unregister everything in unload_module
+ -- Add IP based authentication using 'host'in type=user's
+0.1.0
+ -- Intergration into the mainline Asterisk codebase
+ -- Remove reduandant debug info
+ -- Add Caller*id support
+ -- Inband DTMF
+ -- Retool port usage (to avoid possible seg fault condition)
+0.0.6
+ -- Configurable support for user-input (DTMF)
+ -- Reworked Gatekeeper support
+ -- Native bridging (but is still broken, help!)
+ -- Locally implement a non-broken G.723.1 Capability
+ -- Utilize the cleaner RTP method implemented by Mark
+ -- AllowGkRouted, thanks to Panny from http://hotlinks.co.uk
+ -- Clened up inbound call flow
+ -- Prefix, E.164 and Gateway support
+ -- Multi-homed support
+ -- Killed more seg's
+0.0.5
+ -- Added H.323 Alias support
+ -- Clened up inbound call flow
+ -- Fixed RTP port logic
+ -- Stomped on possible seg fault conditions thanks to Iain Stevenson
+0.0.4
+ -- Fixed one-way audio on inbound calls. Found
+ race condition in monitor thread.
+
+0.0.3
+ -- Changed name to chan_h323
+ -- Also renamed file names to futher avoid confusion
+
+0.0.2
+ -- First public offering
+ -- removed most hardcoded values
+ -- lots of changes to alias/exension operation
+
+0.0.1
+ -- initial build, lots of hardcoded crap
+ -- Proof of concept for External RTP
diff --git a/trunk/channels/h323/INSTALL.openh323 b/trunk/channels/h323/INSTALL.openh323
new file mode 100644
index 000000000..f46c37905
--- /dev/null
+++ b/trunk/channels/h323/INSTALL.openh323
@@ -0,0 +1,18 @@
+To build Open H.323 see:
+
+http://www.openh323.org/build.html#unix
+
+You only need to do 'make opt'. Anything else you will be simply waisting time and HD space.
+Also, you will notice they never tell you to 'make install' so don't do it.
+
+
+On FreeBSD, the Makefiles are configured to
+locate the compiled openh323 port, if it has
+been built. Here is one way to build
+openh323 and ptlib on such that the Makefiles
+find it:
+ # cd /usr/ports/net/openh323
+ # make
+It is not necessary to install the port. The
+asterisk makefiles do not use any files
+installed by the port.
diff --git a/trunk/channels/h323/Makefile.in b/trunk/channels/h323/Makefile.in
new file mode 100644
index 000000000..083250f55
--- /dev/null
+++ b/trunk/channels/h323/Makefile.in
@@ -0,0 +1,48 @@
+#
+# Makefile
+#
+# Make file for OpenH323 support layer
+#
+
+.PHONY: Makefile.ast clean
+
+default:: @OPENH323_BUILD@
+
+# Verify those options with main Makefile
+STDCCFLAGS = -DNDEBUG
+STDCCFLAGS += -I../../include -include ../../include/asterisk/autoconfig.h
+STDCCFLAGS += -fPIC
+#OPTCCFLAGS +=
+CFLAGS = -pipe
+TARGET = libchanh323.a
+TARGET += Makefile.ast
+SOURCES = ast_h323.cxx compat_h323.cxx cisco-h225.cxx caps_h323.cxx
+OBJDIR = .
+OBJS =
+
+ifndef OPENH323DIR
+OPENH323DIR=@OPENH323DIR@
+endif
+
+include $(OPENH323DIR)/openh323u.mak
+
+notrace::
+ $(MAKE) NOTRACE=1 opt
+
+$(SOURCES):: Makefile ../../Makefile
+ touch $@
+
+libchanh323.a: $(OBJS)
+ ar crv $@ $(OBJS)
+
+cisco-h225.cxx:: cisco-h225.asn
+ asnparser -m CISCO_H225 -c $<
+
+Makefile.ast:
+ @echo H323CFLAGS = $(STDCCFLAGS) $(OPTCCFLAGS) $(CFLAGS) >$@.tmp
+ @echo H323LDFLAGS = $(CFLAGS) $(LDFLAGS) >>$@.tmp
+ @echo H323LDLIBS = $(LDLIBS) $(ENDLDLIBS) $(ENDLDFLAGS) >>$@.tmp
+ @if [ -r $@ ] && cmp -s $@ $@.tmp; then rm -f $@.tmp; else mv -f $@.tmp $@; fi
+
+clean::
+ rm -f $(TARGET) $(OBJS) Makefile.ast *.dep
diff --git a/trunk/channels/h323/README b/trunk/channels/h323/README
new file mode 100644
index 000000000..875bf3668
--- /dev/null
+++ b/trunk/channels/h323/README
@@ -0,0 +1,144 @@
+ Open H.323 Channel Driver for Asterisk
+ By Jeremy McNamara
+ For The NuFone Network
+
+ First public release on November 10th, 2002
+
+ 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
+your distro did not install them for you without your knowledge.
+
+
+To compile this code
+--------------------
+Once PWLib and Open H.323 have been compiled per their specific build
+instructions, issue a make in the asterisk/channels/h323 directory with
+argument used to build PWLib and OpenH323 (for example, make opt), then go
+back to the Asterisk source top level directory and issue a make install.
+
+
+The most common compile error
+----------------------------
+If you receive ANYTHING that says 'undefined symbol' you are experiencing
+typical version skew. For example:
+
+libh323_linux_x86_r.so.1: undefined symbol: GetNumberValueAt__C14PAbstractArrayi
+
+You need to search and destroy every version of libh323 and libpt then
+completely recompile everything
+
+Example commands to make sure everything gets cleaned and then
+rebult in proper order:
+
+cd /path/to/pwlib
+./configure
+make clean opt
+cd /path/to/openh323
+./configure
+make clean opt
+cd /path/to/asterisk/channels/h323
+make opt
+cd /path/to/asterisk
+make install
+
+
+Most common run-time error
+-------------------------
+libpt_linux_x86_r.so.1: cannot open shared object file: No such
+file or directory
+
+You have not set the LD_LIBRARY_PATH environment variable.
+
+Example environment for sh/bash:
+
+PWLIBDIR=$HOME/pwlib
+export PWLIBDIR
+OPENH323DIR=$HOME/openh323
+export OPENH323DIR
+LD_LIBRARY_PATH=$PWLIBDIR/lib:$OPENH323DIR/lib
+export LD_LIBRARY_PATH
+
+We recomend puting the above directives into your /etc/profile so
+you do not have to remember to export those values every time you
+want to recompile. Make sure to logout and log back in, so your
+envrionment can pick up the new variables.
+
+
+Upgrading Asterisk
+-----------------
+After you cvs update (or make update) Asterisk you have to go into
+asterisk/channels/h323 and issue a make clean all, before compiling the
+rest of asterisk. Doing this process every time you upgrade Asterisk
+will ensure a sane build.
+
+
+Dialing an H.323 channel
+------------------------
+Without a gatekeeper:
+exten => _1NXXNXXXXXX,1,Dial,H323/${EXTEN}@peer
+or
+exten => _1NXXNXXXXXX,1,Dial,H323/${EXTEN}@ip.or.hostname
+
+'peer' is defined in h323.conf as:
+
+[peer]
+type=peer
+host=1.2.3.4
+disallow=all
+allow=ulaw
+
+Using a gatekeeper:
+exten => _1NXXNXXXXXX,1,Dial,H323/${EXTEN}
+
+When using a gatekeeper you cannot utilize the type=peer features,
+since the H.323 spec states that when a Gatekeeper is part of an H.323 network,
+the Gatekeeper shall be used for all communication.
+
+
+Developer Contact
+----------------
+If you have trouble contact 'JerJer' in #Asterisk on
+irc.freenode.net and/or send reasonable debug information to support@nufone.net.
+
+If are lucky enough to segfault this code please run a
+backtrace and send the gory details. Segmentation faults are not
+tolerated, no matter what Distro you run (even debian)!
+
+a simple bt example:
+
+# /usr/sbin/asterisk -vvvgc
+...
+[chan_h323.so]
+Segmentation Fault (core dumped)
+
+# ls core.*
+core.1976
+
+# gdb /usr/sbin/asterisk core.1976
+...lots of useless garbage here...
+(gdb) bt
+
+Send whatever shows up right after the 'bt'
+
+Also, a full debug screen output is almost needed. Make sure you are
+in the full console mode (-c) and turn on 'h.323 debug' or worst case
+senerio 'h.323 trace 4'. A nice way to capture debug info is with
+script (man script).
+
+If you are motivated to update/fix this code please submit a
+disclaimer along with the patch to the Asterisk bug
+tracker: http://bugs.digium.com/
+
+
+Jeremy McNamara
+The NuFone Network
diff --git a/trunk/channels/h323/TODO b/trunk/channels/h323/TODO
new file mode 100644
index 000000000..1e114ca3b
--- /dev/null
+++ b/trunk/channels/h323/TODO
@@ -0,0 +1,9 @@
+The NuFone Network's Open H.323 Channel Driver for Asterisk
+
+ TODO:
+
+ - H.323 Native Bridging
+
+ - Gatekeeping support (started)
+
+ - Acutally implement the options for broken H.323 stacks
diff --git a/trunk/channels/h323/ast_h323.cxx b/trunk/channels/h323/ast_h323.cxx
new file mode 100644
index 000000000..fd7d35dff
--- /dev/null
+++ b/trunk/channels/h323/ast_h323.cxx
@@ -0,0 +1,2637 @@
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+/*
+ * ast_h323.cpp
+ *
+ * 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
+ *
+ * This file is part of the chan_h323 driver for Asterisk
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * Version Info: $Id$
+ */
+#include <arpa/inet.h>
+
+#include <list>
+#include <string>
+#include <algorithm>
+
+#include <ptlib.h>
+#include <h323.h>
+#include <h323pdu.h>
+#include <h323neg.h>
+#include <mediafmt.h>
+#include <lid.h>
+#ifdef H323_H450
+#include "h4501.h"
+#include "h4504.h"
+#include "h45011.h"
+#include "h450pdu.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "asterisk/compat.h"
+#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"
+#include "caps_h323.h"
+
+/* PWlib Required Components */
+#define MAJOR_VERSION 1
+#define MINOR_VERSION 0
+#define BUILD_TYPE ReleaseCode
+#define BUILD_NUMBER 0
+
+/** Counter for the number of connections */
+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
+ */
+static MyH323EndPoint *endPoint = NULL;
+
+/** PWLib entry point */
+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);
+
+ public:
+ PAsteriskLog() : iostream(cout.rdbuf()) { init(&buffer); }
+ ~PAsteriskLog() { flush(); }
+
+ private:
+ PAsteriskLog(const PAsteriskLog &) : iostream(cout.rdbuf()) { }
+ PAsteriskLog & operator=(const PAsteriskLog &) { return *this; }
+
+ class Buffer : public streambuf {
+ public:
+ virtual int overflow(int=EOF);
+ virtual int underflow();
+ virtual int sync();
+ PString string;
+ } buffer;
+ friend class Buffer;
+};
+
+static PAsteriskLog *logstream = NULL;
+
+int PAsteriskLog::Buffer::overflow(int c)
+{
+ if (pptr() >= epptr()) {
+ int ppos = pptr() - pbase();
+ char *newptr = string.GetPointer(string.GetSize() + 2000);
+ setp(newptr, newptr + string.GetSize() - 1);
+ pbump(ppos);
+ }
+ if (c != EOF) {
+ *pptr() = (char)c;
+ pbump(1);
+ }
+ return 0;
+}
+
+int PAsteriskLog::Buffer::underflow()
+{
+ return EOF;
+}
+
+int PAsteriskLog::Buffer::sync()
+{
+ char *str = strdup(string);
+ char *s, *s1;
+ char c;
+
+ /* Pass each line with different ast_verbose() call */
+ for (s = str; s && *s; s = s1) {
+ s1 = strchr(s, '\n');
+ if (!s1)
+ s1 = s + strlen(s);
+ else
+ s1++;
+ c = *s1;
+ *s1 = '\0';
+ ast_verbose("%s", s);
+ *s1 = c;
+ }
+ free(str);
+
+ string = PString();
+ char *base = string.GetPointer(2000);
+ setp(base, base + string.GetSize() - 1);
+ return 0;
+}
+
+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
+
+/* 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 Networks",
+ "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
+ We are requesting 128 (64k in each direction), which is the worst case codec. */
+ endPoint->SetInitialBandwidth(1280);
+}
+
+void PAssertFunc(const char *msg)
+{
+ ast_log(LOG_ERROR, "%s\n", msg);
+ /* XXX: Probably we need to crash here */
+}
+
+
+/** MyH323EndPoint
+ */
+MyH323EndPoint::MyH323EndPoint()
+ : H323EndPoint()
+{
+ /* Capabilities will be negotiated on per-connection basis */
+ capabilities.RemoveAll();
+
+ /* Reset call setup timeout to some more reasonable value than 1 minute */
+ signallingChannelCallTimeout = PTimeInterval(0, 0, 10); /* 10 minutes */
+}
+
+/** The fullAddress parameter is used directly in the MakeCall method so
+ * the General form for the fullAddress argument is :
+ * [alias@][transport$]host[:port]
+ * default values: alias = the same value as host.
+ * transport = ip.
+ * port = 1720.
+ */
+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()) {
+ fullAddress = dest;
+ if (h323debug) {
+ cout << " -- Making call to " << fullAddress << " using gatekeeper." << endl;
+ }
+ } else {
+ 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, transport))) {
+ if (h323debug) {
+ cout << "Error making call to \"" << fullAddress << '"' << endl;
+ }
+ return 1;
+ }
+ *callReference = connection->GetCallReference();
+
+ if (h323debug) {
+ cout << "\t-- " << GetLocalUserName() << " is calling host " << fullAddress << endl;
+ cout << "\t-- Call token is " << (const char *)token << endl;
+ cout << "\t-- Call reference is " << *callReference << endl;
+#ifdef PTRACING
+ cout << "\t-- DTMF Payload is " << connection->dtmfCodec << endl;
+#endif
+ }
+ connection->Unlock();
+ return 0;
+}
+
+void MyH323EndPoint::SetEndpointTypeInfo( H225_EndpointType & info ) const
+{
+ 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++) {
+ H323SetAliasAddress(SupportedPrefixes[p], ((H225_VoiceCaps &)protocol).m_supportedPrefixes[p].m_prefix, H225_AliasAddress::e_dialedDigits);
+ }
+}
+
+void MyH323EndPoint::SetGateway(void)
+{
+ terminalType = e_GatewayOnly;
+}
+
+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);
+}
+
+BOOL MyH323EndPoint::ClearCall(const PString & token)
+{
+ if (h323debug) {
+ cout << "\t-- ClearCall: Request to clear call with token " << token << endl;
+ }
+ return H323EndPoint::ClearCall(token, H323Connection::EndedByLocalUser);
+}
+
+void MyH323EndPoint::SendUserTone(const PString &token, char tone)
+{
+ H323Connection *connection = NULL;
+
+ connection = FindConnectionWithLock(token);
+ if (connection != NULL) {
+ connection->SendUserInputTone(tone, 500);
+ connection->Unlock();
+ }
+}
+
+void MyH323EndPoint::OnClosedLogicalChannel(H323Connection & connection, const H323Channel & channel)
+{
+ channelsOpen--;
+ if (h323debug) {
+ cout << "\t\tchannelsOpen = " << channelsOpen << endl;
+ }
+ H323EndPoint::OnClosedLogicalChannel(connection, channel);
+}
+
+BOOL MyH323EndPoint::OnConnectionForwarded(H323Connection & connection,
+ 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)
+{
+ if (h323debug) {
+ cout << "\t-- Forwarding call to " << forwardParty << endl;
+ }
+ return H323EndPoint::ForwardConnection(connection, forwardParty, pdu);
+}
+
+void MyH323EndPoint::OnConnectionEstablished(H323Connection & connection, const PString & estCallToken)
+{
+ if (h323debug) {
+ cout << "\t=-= In OnConnectionEstablished for call " << connection.GetCallReference() << endl;
+ cout << "\t\t-- Connection Established with \"" << connection.GetRemotePartyName() << "\"" << endl;
+ }
+ on_connection_established(connection.GetCallReference(), (const char *)connection.GetCallToken());
+}
+
+/** OnConnectionCleared callback function is called upon the dropping of an established
+ * H323 connection.
+ */
+void MyH323EndPoint::OnConnectionCleared(H323Connection & connection, const PString & clearedCallToken)
+{
+ PString remoteName = connection.GetRemotePartyName();
+
+ switch (connection.GetCallEndReason()) {
+ case H323Connection::EndedByCallForwarded:
+ if (h323debug) {
+ cout << "-- " << remoteName << " has forwarded the call" << endl;
+ }
+ break;
+ case H323Connection::EndedByRemoteUser:
+ if (h323debug) {
+ cout << "-- " << remoteName << " has cleared the call" << endl;
+ }
+ break;
+ case H323Connection::EndedByCallerAbort:
+ if (h323debug) {
+ cout << "-- " << remoteName << " has stopped calling" << endl;
+ }
+ break;
+ case H323Connection::EndedByRefusal:
+ if (h323debug) {
+ cout << "-- " << remoteName << " did not accept your call" << endl;
+ }
+ break;
+ case H323Connection::EndedByRemoteBusy:
+ if (h323debug) {
+ cout << "-- " << remoteName << " was busy" << endl;
+ }
+ break;
+ case H323Connection::EndedByRemoteCongestion:
+ if (h323debug) {
+ cout << "-- Congested link to " << remoteName << endl;
+ }
+ break;
+ case H323Connection::EndedByNoAnswer:
+ if (h323debug) {
+ cout << "-- " << remoteName << " did not answer your call" << endl;
+ }
+ break;
+ case H323Connection::EndedByTransportFail:
+ if (h323debug) {
+ cout << "-- Call with " << remoteName << " ended abnormally" << endl;
+ }
+ break;
+ case H323Connection::EndedByCapabilityExchange:
+ if (h323debug) {
+ cout << "-- Could not find common codec with " << remoteName << endl;
+ }
+ break;
+ case H323Connection::EndedByNoAccept:
+ if (h323debug) {
+ cout << "-- Did not accept incoming call from " << remoteName << endl;
+ }
+ break;
+ case H323Connection::EndedByAnswerDenied:
+ if (h323debug) {
+ cout << "-- Refused incoming call from " << remoteName << endl;
+ }
+ break;
+ case H323Connection::EndedByNoUser:
+ if (h323debug) {
+ cout << "-- Remote endpoint could not find user: " << remoteName << endl;
+ }
+ break;
+ case H323Connection::EndedByNoBandwidth:
+ if (h323debug) {
+ cout << "-- Call to " << remoteName << " aborted, insufficient bandwidth." << endl;
+ }
+ break;
+ case H323Connection::EndedByUnreachable:
+ if (h323debug) {
+ cout << "-- " << remoteName << " could not be reached." << endl;
+ }
+ break;
+ case H323Connection::EndedByHostOffline:
+ if (h323debug) {
+ cout << "-- " << remoteName << " is not online." << endl;
+ }
+ break;
+ case H323Connection::EndedByNoEndPoint:
+ if (h323debug) {
+ cout << "-- No phone running for " << remoteName << endl;
+ }
+ break;
+ case H323Connection::EndedByConnectFail:
+ if (h323debug) {
+ cout << "-- Transport error calling " << remoteName << endl;
+ }
+ break;
+ default:
+ 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 *userData, H323Transport *transport, H323SignalPDU *setupPDU)
+{
+ unsigned options = 0;
+ call_options_t *opts = (call_options_t *)userData;
+ MyH323Connection *conn;
+
+ if (opts && opts->fastStart) {
+ options |= H323Connection::FastStartOptionEnable;
+ } 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->silenceSuppression) {
+ options |= H323Connection::SilenceSuppresionOptionEnable;
+ } else {
+ options |= H323Connection::SilenceSUppressionOptionDisable;
+ }
+#endif
+ conn = new MyH323Connection(*this, callReference, options);
+ if (conn) {
+ if (opts)
+ conn->SetCallOptions(opts, (setupPDU ? TRUE : FALSE));
+ }
+ return conn;
+}
+
+/* MyH323Connection Implementation */
+MyH323Connection::MyH323Connection(MyH323EndPoint & ep, unsigned callReference,
+ unsigned options)
+ : H323Connection(ep, callReference, options)
+{
+#ifdef H323_H450
+ /* Dispatcher will free out all registered handlers */
+ if (h450dispatcher)
+ delete h450dispatcher;
+ h450dispatcher = new H450xDispatcher(*this);
+ h4502handler = new H4502Handler(*this, *h450dispatcher);
+ h4504handler = new MyH4504Handler(*this, *h450dispatcher);
+ h4506handler = new H4506Handler(*this, *h450dispatcher);
+ h45011handler = new H45011Handler(*this, *h450dispatcher);
+#endif
+ cause = -1;
+ sessionId = 0;
+ bridging = FALSE;
+ holdHandling = progressSetup = progressAlert = 0;
+ dtmfMode = 0;
+ dtmfCodec[0] = dtmfCodec[1] = (RTP_DataFrame::PayloadTypes)0;
+ redirect_reason = -1;
+ transfer_capability = -1;
+#ifdef TUNNELLING
+ tunnelOptions = remoteTunnelOptions = 0;
+#endif
+ if (h323debug) {
+ cout << " == New H.323 Connection created." << endl;
+ }
+ return;
+}
+
+MyH323Connection::~MyH323Connection()
+{
+ if (h323debug) {
+ cout << " == H.323 Connection deleted." << endl;
+ }
+ return;
+}
+
+BOOL MyH323Connection::OnReceivedProgress(const H323SignalPDU &pdu)
+{
+ BOOL isInband;
+ unsigned pi;
+
+ if (!H323Connection::OnReceivedProgress(pdu)) {
+ return FALSE;
+ }
+
+ if (!pdu.GetQ931().GetProgressIndicator(pi))
+ pi = 0;
+ if (h323debug) {
+ cout << "\t- Progress Indicator: " << pi << endl;
+ }
+
+ switch(pi) {
+ case Q931::ProgressNotEndToEndISDN:
+ case Q931::ProgressInbandInformationAvailable:
+ isInband = TRUE;
+ break;
+ default:
+ isInband = FALSE;
+ }
+ on_progress(GetCallReference(), (const char *)GetCallToken(), isInband);
+
+ return connectionState != ShuttingDownConnection;
+}
+
+BOOL MyH323Connection::MySendProgress()
+{
+ /* The code taken from H323Connection::AnsweringCall() but ALWAYS send
+ PROGRESS message, including slow start operations */
+ H323SignalPDU progressPDU;
+ H225_Progress_UUIE &prog = progressPDU.BuildProgress(*this);
+
+ if (!mediaWaitForConnect) {
+ if (SendFastStartAcknowledge(prog.m_fastStart))
+ prog.IncludeOptionalField(H225_Progress_UUIE::e_fastStart);
+ else {
+ if (connectionState == ShuttingDownConnection)
+ return FALSE;
+
+ /* Do early H.245 start */
+ earlyStart = TRUE;
+ if (!h245Tunneling) {
+ if (!H323Connection::StartControlChannel())
+ return FALSE;
+ prog.IncludeOptionalField(H225_Progress_UUIE::e_h245Address);
+ controlChannel->SetUpTransportPDU(prog.m_h245Address, TRUE);
+ }
+ }
+ }
+ progressPDU.GetQ931().SetProgressIndicator(Q931::ProgressInbandInformationAvailable);
+
+#ifdef TUNNELLING
+ EmbedTunneledInfo(progressPDU);
+#endif
+ HandleTunnelPDU(&progressPDU);
+ WriteSignalPDU(progressPDU);
+
+ return TRUE;
+}
+
+H323Connection::AnswerCallResponse MyH323Connection::OnAnswerCall(const PString & caller,
+ const H323SignalPDU & setupPDU,
+ H323SignalPDU & connectPDU)
+{
+ unsigned pi;
+
+ if (h323debug) {
+ cout << "\t=-= In OnAnswerCall for call " << GetCallReference() << endl;
+ }
+
+ if (connectionState == ShuttingDownConnection)
+ return H323Connection::AnswerCallDenied;
+
+ if (!setupPDU.GetQ931().GetProgressIndicator(pi)) {
+ pi = 0;
+ }
+ if (h323debug) {
+ cout << "\t\t- Progress Indicator: " << pi << endl;
+ }
+ if (progressAlert) {
+ pi = progressAlert;
+ } else if (pi == Q931::ProgressOriginNotISDN) {
+ pi = Q931::ProgressInbandInformationAvailable;
+ }
+ 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 ((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;
+ }
+
+ if (on_progress) {
+ BOOL isInband;
+ unsigned alertingPI;
+
+ if (!alertingPDU.GetQ931().GetProgressIndicator(alertingPI)) {
+ alertingPI = 0;
+ }
+ if (h323debug) {
+ cout << "\t\t- Progress Indicator: " << alertingPI << endl;
+ }
+
+ switch(alertingPI) {
+ case Q931::ProgressNotEndToEndISDN:
+ case Q931::ProgressInbandInformationAvailable:
+ isInband = TRUE;
+ break;
+ default:
+ isInband = FALSE;
+ }
+ on_progress(GetCallReference(), (const char *)GetCallToken(), isInband);
+ }
+ on_chan_ringing(GetCallReference(), (const char *)GetCallToken() );
+ return connectionState != ShuttingDownConnection;
+}
+
+void MyH323Connection::SetCallOptions(void *o, BOOL isIncoming)
+{
+ call_options_t *opts = (call_options_t *)o;
+
+ progressSetup = opts->progress_setup;
+ progressAlert = opts->progress_alert;
+ holdHandling = opts->holdHandling;
+ dtmfCodec[0] = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec[0];
+ dtmfCodec[1] = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec[1];
+ 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;
+ }
+ cid_presentation = opts->presentation;
+ cid_ton = opts->type_of_number;
+ if (opts->transfer_capability >= 0) {
+ transfer_capability = opts->transfer_capability;
+ }
+ }
+ tunnelOptions = opts->tunnelOptions;
+}
+
+void MyH323Connection::SetCallDetails(void *callDetails, const H323SignalPDU &setupPDU, BOOL isIncoming)
+{
+ PString sourceE164;
+ PString destE164;
+ PString sourceAliases;
+ PString destAliases;
+ char *s, *s1;
+ call_details_t *cd = (call_details_t *)callDetails;
+
+ memset(cd, 0, sizeof(*cd));
+ cd->call_reference = GetCallReference();
+ cd->call_token = strdup((const char *)GetCallToken());
+
+ sourceE164 = "";
+ setupPDU.GetSourceE164(sourceE164);
+ 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;
+ unsigned plan, type, screening, presentation;
+ Q931::InformationTransferCapability capability;
+ unsigned transferRate, codingStandard, userInfoLayer1;
+
+ /* Fetch presentation and type information about calling party's number */
+ if (setupPDU.GetQ931().GetCallingPartyNumber(sourceName, &plan, &type, &presentation, &screening, 0, 0)) {
+ /* Construct fields back */
+ cd->type_of_number = (type << 4) | plan;
+ cd->presentation = (presentation << 5) | screening;
+ } else if (cd->call_source_e164[0]) {
+ cd->type_of_number = 0; /* UNKNOWN */
+ cd->presentation = 0x03; /* ALLOWED NETWORK NUMBER - Default */
+ if (setupPDU.GetQ931().HasIE(Q931::UserUserIE)) {
+ const H225_Setup_UUIE &setup_uuie = setupPDU.m_h323_uu_pdu.m_h323_message_body;
+ if (setup_uuie.HasOptionalField(H225_Setup_UUIE::e_presentationIndicator))
+ cd->presentation = (cd->presentation & 0x9f) | (((unsigned int)setup_uuie.m_presentationIndicator.GetTag()) << 5);
+ if (setup_uuie.HasOptionalField(H225_Setup_UUIE::e_screeningIndicator))
+ cd->presentation = (cd->presentation & 0xe0) | (((unsigned int)setup_uuie.m_screeningIndicator.GetValue()) & 0x1f);
+ }
+ } else {
+ cd->type_of_number = 0; /* UNKNOWN */
+ cd->presentation = 0x43; /* NUMBER NOT AVAILABLE */
+ }
+
+ 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;
+
+ /* Fetch Q.931's transfer capability */
+ if (((Q931 &)setupPDU.GetQ931()).GetBearerCapabilities(capability, transferRate, &codingStandard, &userInfoLayer1))
+ cd->transfer_capability = ((unsigned int)capability & 0x1f) | (codingStandard << 5);
+ else
+ cd->transfer_capability = 0x00; /* ITU coding of Speech */
+
+ /* Don't show local username as called party name */
+ SetDisplayName(cd->call_dest_e164);
+ }
+
+ /* Convert complex strings */
+ // 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;
+ }
+ 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 struct {
+ Q931::InformationElementCodes ie;
+ BOOL dontDelete;
+ } codes[] = {
+ { Q931::RedirectingNumberIE, },
+ { Q931::FacilityIE, },
+// { Q931::CallingPartyNumberIE, TRUE },
+ };
+
+ 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].ie)) {
+ tmpQ931.SetIE(codes[i].ie, q931.GetIE(codes[i].ie));
+ if (!codes[i].dontDelete)
+ q931.RemoveIE(codes[i].ie);
+ if (codes[i].ie != Q931::RedirectingNumberIE)
+ notRedirOnly = TRUE;
+ res = TRUE;
+ }
+ }
+ /* 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;
+ }
+ 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;
+}
+
+static H225_EndpointType *GetEndpointType(H323SignalPDU &pdu)
+{
+ if (!pdu.GetQ931().HasIE(Q931::UserUserIE))
+ return NULL;
+
+ 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) &&
+ (((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 << "\t-- Call Failed" << endl;
+ }
+ return FALSE;
+ }
+
+ SetCallOptions(res, TRUE);
+
+ /* Disable fastStart if requested by remote side */
+ if (h245Tunneling && !setupPDU.m_h323_uu_pdu.m_h245Tunneling) {
+ masterSlaveDeterminationProcedure->Stop();
+ capabilityExchangeProcedure->Stop();
+ PTRACE(3, "H225\tFast Start DISABLED!");
+ h245Tunneling = FALSE;
+ }
+
+ return H323Connection::OnReceivedSignalSetup(setupPDU);
+}
+
+BOOL MyH323Connection::OnSendSignalSetup(H323SignalPDU & setupPDU)
+{
+ call_details_t cd;
+
+ if (h323debug) {
+ cout << "\t-- Sending SETUP message" << endl;
+ }
+
+ if (connectionState == ShuttingDownConnection)
+ return FALSE;
+
+ if (progressSetup)
+ setupPDU.GetQ931().SetProgressIndicator(progressSetup);
+
+ 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);
+ }
+
+ if (transfer_capability)
+ setupPDU.GetQ931().SetBearerCapabilities((Q931::InformationTransferCapability)(transfer_capability & 0x1f), 1, ((transfer_capability >> 5) & 3));
+
+ SetCallDetails(&cd, setupPDU, FALSE);
+
+ int res = on_outgoing_call(&cd);
+ if (!res) {
+ if (h323debug) {
+ cout << "\t-- Call Failed" << endl;
+ }
+ return FALSE;
+ }
+
+ /* OpenH323 will build calling party information with default
+ type and presentation information, so build it to be recorded
+ by embedding routines */
+ setupPDU.GetQ931().SetCallingPartyNumber(GetLocalPartyName(), (cid_ton >> 4) & 0x07,
+ cid_ton & 0x0f, (cid_presentation >> 5) & 0x03, cid_presentation & 0x1f);
+ setupPDU.GetQ931().SetDisplayName(GetDisplayName());
+
+#ifdef TUNNELLING
+ EmbedTunneledInfo(setupPDU);
+#endif
+
+ return H323Connection::OnSendSignalSetup(setupPDU);
+}
+
+static BOOL BuildFastStartList(const H323Channel & channel,
+ H225_ArrayOf_PASN_OctetString & array,
+ H323Channel::Directions reverseDirection)
+{
+ H245_OpenLogicalChannel open;
+ const H323Capability & capability = channel.GetCapability();
+
+ if (channel.GetDirection() != reverseDirection) {
+ if (!capability.OnSendingPDU(open.m_forwardLogicalChannelParameters.m_dataType))
+ return FALSE;
+ }
+ else {
+ if (!capability.OnSendingPDU(open.m_reverseLogicalChannelParameters.m_dataType))
+ return FALSE;
+
+ open.m_forwardLogicalChannelParameters.m_multiplexParameters.SetTag(
+ H245_OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters::e_none);
+ open.m_forwardLogicalChannelParameters.m_dataType.SetTag(H245_DataType::e_nullData);
+ open.IncludeOptionalField(H245_OpenLogicalChannel::e_reverseLogicalChannelParameters);
+ }
+
+ if (!channel.OnSendingPDU(open))
+ return FALSE;
+
+ PTRACE(4, "H225\tBuild fastStart:\n " << setprecision(2) << open);
+ PINDEX last = array.GetSize();
+ array.SetSize(last+1);
+ array[last].EncodeSubType(open);
+
+ PTRACE(3, "H225\tBuilt fastStart for " << capability);
+ return TRUE;
+}
+
+H323Connection::CallEndReason MyH323Connection::SendSignalSetup(const PString & alias,
+ const H323TransportAddress & address)
+{
+ // Start the call, first state is asking gatekeeper
+ connectionState = AwaitingGatekeeperAdmission;
+
+ // Indicate the direction of call.
+ if (alias.IsEmpty())
+ remotePartyName = remotePartyAddress = address;
+ else {
+ remotePartyName = alias;
+ remotePartyAddress = alias + '@' + address;
+ }
+
+ // Start building the setup PDU to get various ID's
+ H323SignalPDU setupPDU;
+ H225_Setup_UUIE & setup = setupPDU.BuildSetup(*this, address);
+
+#ifdef H323_H450
+ h450dispatcher->AttachToSetup(setupPDU);
+#endif
+
+ // Save the identifiers generated by BuildSetup
+ setupPDU.GetQ931().GetCalledPartyNumber(remotePartyNumber);
+
+ H323TransportAddress gatekeeperRoute = address;
+
+ // Check for gatekeeper and do admission check if have one
+ H323Gatekeeper * gatekeeper = endpoint.GetGatekeeper();
+ H225_ArrayOf_AliasAddress newAliasAddresses;
+ if (gatekeeper != NULL) {
+ H323Gatekeeper::AdmissionResponse response;
+ response.transportAddress = &gatekeeperRoute;
+ response.aliasAddresses = &newAliasAddresses;
+ if (!gkAccessTokenOID)
+ response.accessTokenData = &gkAccessTokenData;
+ while (!gatekeeper->AdmissionRequest(*this, response, alias.IsEmpty())) {
+ PTRACE(1, "H225\tGatekeeper refused admission: "
+ << (response.rejectReason == UINT_MAX
+ ? PString("Transport error")
+ : H225_AdmissionRejectReason(response.rejectReason).GetTagName()));
+#ifdef H323_H450
+ h4502handler->onReceivedAdmissionReject(H4501_GeneralErrorList::e_notAvailable);
+#endif
+
+ switch (response.rejectReason) {
+ case H225_AdmissionRejectReason::e_calledPartyNotRegistered:
+ return EndedByNoUser;
+ case H225_AdmissionRejectReason::e_requestDenied:
+ return EndedByNoBandwidth;
+ case H225_AdmissionRejectReason::e_invalidPermission:
+ case H225_AdmissionRejectReason::e_securityDenial:
+ return EndedBySecurityDenial;
+ case H225_AdmissionRejectReason::e_resourceUnavailable:
+ return EndedByRemoteBusy;
+ case H225_AdmissionRejectReason::e_incompleteAddress:
+ if (OnInsufficientDigits())
+ break;
+ // Then default case
+ default:
+ return EndedByGatekeeper;
+ }
+
+ PString lastRemotePartyName = remotePartyName;
+ while (lastRemotePartyName == remotePartyName) {
+ Unlock(); // Release the mutex as can deadlock trying to clear call during connect.
+ digitsWaitFlag.Wait();
+ if (!Lock()) // Lock while checking for shutting down.
+ return EndedByCallerAbort;
+ }
+ }
+ mustSendDRQ = TRUE;
+ if (response.gatekeeperRouted) {
+ setup.IncludeOptionalField(H225_Setup_UUIE::e_endpointIdentifier);
+ setup.m_endpointIdentifier = gatekeeper->GetEndpointIdentifier();
+ gatekeeperRouted = TRUE;
+ }
+ }
+
+#ifdef H323_TRANSNEXUS_OSP
+ // check for OSP server (if not using GK)
+ if (gatekeeper == NULL) {
+ OpalOSP::Provider * ospProvider = endpoint.GetOSPProvider();
+ if (ospProvider != NULL) {
+ OpalOSP::Transaction * transaction = new OpalOSP::Transaction();
+ if (transaction->Open(*ospProvider) != 0) {
+ PTRACE(1, "H225\tCannot create OSP transaction");
+ return EndedByOSPRefusal;
+ }
+
+ OpalOSP::Transaction::DestinationInfo destInfo;
+ if (!AuthoriseOSPTransaction(*transaction, destInfo)) {
+ delete transaction;
+ return EndedByOSPRefusal;
+ }
+
+ // save the transaction for use by the call
+ ospTransaction = transaction;
+
+ // retreive the call information
+ gatekeeperRoute = destInfo.destinationAddress;
+ newAliasAddresses.Append(new H225_AliasAddress(destInfo.calledNumber));
+
+ // insert the token
+ setup.IncludeOptionalField(H225_Setup_UUIE::e_tokens);
+ destInfo.InsertToken(setup.m_tokens);
+ }
+ }
+#endif
+
+ // Update the field e_destinationAddress in the SETUP PDU to reflect the new
+ // alias received in the ACF (m_destinationInfo).
+ if (newAliasAddresses.GetSize() > 0) {
+ setup.IncludeOptionalField(H225_Setup_UUIE::e_destinationAddress);
+ setup.m_destinationAddress = newAliasAddresses;
+
+ // Update the Q.931 Information Element (if is an E.164 address)
+ PString e164 = H323GetAliasAddressE164(newAliasAddresses);
+ if (!e164)
+ remotePartyNumber = e164;
+ }
+
+ if (addAccessTokenToSetup && !gkAccessTokenOID && !gkAccessTokenData.IsEmpty()) {
+ PString oid1, oid2;
+ PINDEX comma = gkAccessTokenOID.Find(',');
+ if (comma == P_MAX_INDEX)
+ oid1 = oid2 = gkAccessTokenOID;
+ else {
+ oid1 = gkAccessTokenOID.Left(comma);
+ oid2 = gkAccessTokenOID.Mid(comma+1);
+ }
+ setup.IncludeOptionalField(H225_Setup_UUIE::e_tokens);
+ PINDEX last = setup.m_tokens.GetSize();
+ setup.m_tokens.SetSize(last+1);
+ setup.m_tokens[last].m_tokenOID = oid1;
+ setup.m_tokens[last].IncludeOptionalField(H235_ClearToken::e_nonStandard);
+ setup.m_tokens[last].m_nonStandard.m_nonStandardIdentifier = oid2;
+ setup.m_tokens[last].m_nonStandard.m_data = gkAccessTokenData;
+ }
+
+ if (!signallingChannel->SetRemoteAddress(gatekeeperRoute)) {
+ PTRACE(1, "H225\tInvalid "
+ << (gatekeeperRoute != address ? "gatekeeper" : "user")
+ << " supplied address: \"" << gatekeeperRoute << '"');
+ connectionState = AwaitingTransportConnect;
+ return EndedByConnectFail;
+ }
+
+ // Do the transport connect
+ connectionState = AwaitingTransportConnect;
+
+ // Release the mutex as can deadlock trying to clear call during connect.
+ Unlock();
+
+ signallingChannel->SetWriteTimeout(100);
+
+ BOOL connectFailed = !signallingChannel->Connect();
+
+ // Lock while checking for shutting down.
+ if (!Lock())
+ return EndedByCallerAbort;
+
+ // See if transport connect failed, abort if so.
+ if (connectFailed) {
+ connectionState = NoConnectionActive;
+ switch (signallingChannel->GetErrorNumber()) {
+ case ENETUNREACH :
+ return EndedByUnreachable;
+ case ECONNREFUSED :
+ return EndedByNoEndPoint;
+ case ETIMEDOUT :
+ return EndedByHostOffline;
+ }
+ return EndedByConnectFail;
+ }
+
+ PTRACE(3, "H225\tSending Setup PDU");
+ connectionState = AwaitingSignalConnect;
+
+ // Put in all the signalling addresses for link
+ setup.IncludeOptionalField(H225_Setup_UUIE::e_sourceCallSignalAddress);
+ signallingChannel->SetUpTransportPDU(setup.m_sourceCallSignalAddress, TRUE);
+ if (!setup.HasOptionalField(H225_Setup_UUIE::e_destCallSignalAddress)) {
+ setup.IncludeOptionalField(H225_Setup_UUIE::e_destCallSignalAddress);
+ signallingChannel->SetUpTransportPDU(setup.m_destCallSignalAddress, FALSE);
+ }
+
+ // If a standard call do Fast Start (if required)
+ if (setup.m_conferenceGoal.GetTag() == H225_Setup_UUIE_conferenceGoal::e_create) {
+
+ // Get the local capabilities before fast start is handled
+ OnSetLocalCapabilities();
+
+ // Ask the application what channels to open
+ PTRACE(3, "H225\tCheck for Fast start by local endpoint");
+ fastStartChannels.RemoveAll();
+ OnSelectLogicalChannels();
+
+ // If application called OpenLogicalChannel, put in the fastStart field
+ if (!fastStartChannels.IsEmpty()) {
+ PTRACE(3, "H225\tFast start begun by local endpoint");
+ for (PINDEX i = 0; i < fastStartChannels.GetSize(); i++)
+ BuildFastStartList(fastStartChannels[i], setup.m_fastStart, H323Channel::IsReceiver);
+ if (setup.m_fastStart.GetSize() > 0)
+ setup.IncludeOptionalField(H225_Setup_UUIE::e_fastStart);
+ }
+
+ // Search the capability set and see if we have video capability
+ for (PINDEX i = 0; i < localCapabilities.GetSize(); i++) {
+ switch (localCapabilities[i].GetMainType()) {
+ case H323Capability::e_Audio:
+ case H323Capability::e_UserInput:
+ break;
+
+ default: // Is video or other data (eg T.120)
+ setupPDU.GetQ931().SetBearerCapabilities(Q931::TransferUnrestrictedDigital, 6);
+ i = localCapabilities.GetSize(); // Break out of the for loop
+ break;
+ }
+ }
+ }
+
+ if (!OnSendSignalSetup(setupPDU))
+ return EndedByNoAccept;
+
+ // Do this again (was done when PDU was constructed) in case
+ // OnSendSignalSetup() changed something.
+// setupPDU.SetQ931Fields(*this, TRUE);
+ setupPDU.GetQ931().GetCalledPartyNumber(remotePartyNumber);
+
+ fastStartState = FastStartDisabled;
+ BOOL set_lastPDUWasH245inSETUP = FALSE;
+
+ if (h245Tunneling && doH245inSETUP) {
+ h245TunnelTxPDU = &setupPDU;
+
+ // Try and start the master/slave and capability exchange through the tunnel
+ // Note: this used to be disallowed but is now allowed as of H323v4
+ BOOL ok = StartControlNegotiations();
+
+ h245TunnelTxPDU = NULL;
+
+ if (!ok)
+ return EndedByTransportFail;
+
+ if (setup.m_fastStart.GetSize() > 0) {
+ // Now if fast start as well need to put this in setup specific field
+ // and not the generic H.245 tunneling field
+ setup.IncludeOptionalField(H225_Setup_UUIE::e_parallelH245Control);
+ setup.m_parallelH245Control = setupPDU.m_h323_uu_pdu.m_h245Control;
+ setupPDU.m_h323_uu_pdu.RemoveOptionalField(H225_H323_UU_PDU::e_h245Control);
+ set_lastPDUWasH245inSETUP = TRUE;
+ }
+ }
+
+ // Send the initial PDU
+ setupTime = PTime();
+ if (!WriteSignalPDU(setupPDU))
+ return EndedByTransportFail;
+
+ // WriteSignalPDU always resets lastPDUWasH245inSETUP.
+ // So set it here if required
+ if (set_lastPDUWasH245inSETUP)
+ lastPDUWasH245inSETUP = TRUE;
+
+ // Set timeout for remote party to answer the call
+ signallingChannel->SetReadTimeout(endpoint.GetSignallingChannelCallTimeout());
+
+ return NumCallEndReasons;
+}
+
+
+BOOL MyH323Connection::OnSendReleaseComplete(H323SignalPDU & releaseCompletePDU)
+{
+ if (h323debug) {
+ cout << "\t-- Sending RELEASE COMPLETE" << endl;
+ }
+ if (cause > 0)
+ releaseCompletePDU.GetQ931().SetCause((Q931::CauseValues)cause);
+
+#ifdef TUNNELLING
+ EmbedTunneledInfo(releaseCompletePDU);
+#endif
+
+ return H323Connection::OnSendReleaseComplete(releaseCompletePDU);
+}
+
+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;
+ }
+ if (on_hangup)
+ on_hangup(GetCallReference(), (const char *)GetCallToken(), pdu.GetQ931().GetCause());
+ return H323Connection::OnReceivedReleaseComplete(pdu);
+}
+
+BOOL MyH323Connection::OnClosingLogicalChannel(H323Channel & channel)
+{
+ if (h323debug) {
+ cout << "\t-- Closing logical channel..." << endl;
+ }
+ return H323Connection::OnClosingLogicalChannel(channel);
+}
+
+void MyH323Connection::SendUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp)
+{
+ 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);
+ }
+}
+
+void MyH323Connection::OnUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp)
+{
+ /* Why we should check this? */
+ if ((dtmfMode & (H323_DTMF_CISCO | H323_DTMF_RFC2833 | H323_DTMF_SIGNAL)) != 0) {
+ if (h323debug) {
+ cout << "\t-- Received user input tone (" << tone << ") from remote" << endl;
+ }
+ on_receive_digit(GetCallReference(), tone, (const char *)GetCallToken(), duration);
+ }
+}
+
+void MyH323Connection::OnUserInputString(const PString &value)
+{
+ 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)
+{
+ PINDEX i;
+
+ H323Connection::OnSendCapabilitySet(pdu);
+
+ H245_ArrayOf_CapabilityTableEntry & tables = pdu.m_capabilityTable;
+ for(i = 0; i < tables.GetSize(); i++)
+ {
+ H245_CapabilityTableEntry & entry = tables[i];
+ if (entry.HasOptionalField(H245_CapabilityTableEntry::e_capability)) {
+ H245_Capability & cap = entry.m_capability;
+ if (cap.GetTag() == H245_Capability::e_receiveRTPAudioTelephonyEventCapability) {
+ H245_AudioTelephonyEventCapability & atec = cap;
+ atec.m_dynamicRTPPayloadType = dtmfCodec[0];
+// on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)dtmfCodec[0]);
+#ifdef PTRACING
+ if (h323debug) {
+ cout << "\t-- Receiving RFC2833 on payload " <<
+ atec.m_dynamicRTPPayloadType << endl;
+ }
+#endif
+ }
+ }
+ }
+}
+
+void MyH323Connection::OnSetLocalCapabilities()
+{
+ if (on_setcapabilities)
+ on_setcapabilities(GetCallReference(), (const char *)callToken);
+}
+
+BOOL MyH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCaps,
+ const H245_MultiplexCapability * muxCap,
+ H245_TerminalCapabilitySetReject & reject)
+{
+ struct __codec__ {
+ unsigned int asterisk_codec;
+ unsigned int h245_cap;
+ const char *oid;
+ const char *formatName;
+ };
+ 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 },
+ { AST_FORMAT_G726_AAL2, H245_AudioCapability::e_nonStandard, NULL, CISCO_G726r32 },
+#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
+ struct ast_codec_pref prefs;
+ RTP_DataFrame::PayloadTypes pt;
+
+ if (!H323Connection::OnReceivedCapabilitySet(remoteCaps, muxCap, reject)) {
+ return FALSE;
+ }
+
+ memset(&prefs, 0, sizeof(prefs));
+ 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) && (!codecs[x].formatName || (!strcmp(codecs[x].formatName, (const char *)remoteCapabilities[i].GetFormatName())))) {
+ int ast_codec = codecs[x].asterisk_codec;
+ int ms = 0;
+ if (!(peer_capabilities & ast_codec)) {
+ struct ast_format_list format;
+ ast_codec_pref_append(&prefs, ast_codec);
+ format = ast_codec_pref_getsize(&prefs, ast_codec);
+ if ((ast_codec == AST_FORMAT_ALAW) || (ast_codec == AST_FORMAT_ULAW)) {
+ ms = remoteCapabilities[i].GetTxFramesInPacket();
+ if (ms > 60)
+ ms = format.cur_ms;
+ } else
+ ms = remoteCapabilities[i].GetTxFramesInPacket() * format.inc_ms;
+ ast_codec_pref_setsize(&prefs, ast_codec, ms);
+ }
+ if (h323debug) {
+ cout << "Found peer capability " << remoteCapabilities[i] << ", Asterisk code is " << ast_codec << ", frame size (in ms) is " << ms << endl;
+ }
+ peer_capabilities |= ast_codec;
+ }
+ }
+ break;
+ case H323Capability::e_Data:
+ if (!strcmp((const char *)remoteCapabilities[i].GetFormatName(), CISCO_DTMF_RELAY)) {
+ pt = remoteCapabilities[i].GetPayloadType();
+ if ((dtmfMode & H323_DTMF_CISCO) != 0) {
+ on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)pt, 1);
+// if (sendUserInputMode == SendUserInputAsTone)
+// sendUserInputMode = SendUserInputAsInlineRFC2833;
+ }
+#ifdef PTRACING
+ if (h323debug) {
+ cout << "\t-- Outbound Cisco RTP DTMF on payload " << pt << endl;
+ }
+#endif
+ }
+ break;
+ case H323Capability::e_UserInput:
+ if (!strcmp((const char *)remoteCapabilities[i].GetFormatName(), H323_UserInputCapability::SubTypeNames[H323_UserInputCapability::SignalToneRFC2833])) {
+ pt = remoteCapabilities[i].GetPayloadType();
+ if ((dtmfMode & H323_DTMF_RFC2833) != 0) {
+ on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)pt, 0);
+// if (sendUserInputMode == SendUserInputAsTone)
+// sendUserInputMode = SendUserInputAsInlineRFC2833;
+ }
+#ifdef PTRACING
+ if (h323debug) {
+ cout << "\t-- Outbound RFC2833 on payload " << pt << endl;
+ }
+#endif
+ }
+ 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], caps2_str[1024];
+ ast_codec_pref_string(&prefs, caps2_str, sizeof(caps2_str));
+ cout << "Peer capabilities = " << ast_getformatname_multiple(caps_str, sizeof(caps_str), peer_capabilities)
+ << ", ordered list is " << caps2_str << endl;
+ }
+#if 0
+ redir_capabilities &= peer_capabilities;
+#endif
+ if (on_setpeercapabilities)
+ on_setpeercapabilities(GetCallReference(), (const char *)callToken, peer_capabilities, &prefs);
+
+ return TRUE;
+}
+
+H323Channel * MyH323Connection::CreateRealTimeLogicalChannel(const H323Capability & capability,
+ H323Channel::Directions dir,
+ unsigned sessionID,
+ const H245_H2250LogicalChannelParameters * /*param*/,
+ RTP_QOS * /*param*/ )
+{
+ /* Do not open tx channel when transmitter has been paused by empty TCS */
+ if ((dir == H323Channel::IsTransmitter) && transmitterSidePaused)
+ return NULL;
+
+ return new MyH323_ExternalRTPChannel(*this, capability, dir, sessionID);
+}
+
+/** This callback function is invoked once upon creation of each
+ * 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: "
+ << ((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 caps, int dtmf_mode, void *_prefs, int pref_codec)
+{
+ 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;
+ struct ast_format_list format;
+ int frames_per_packet;
+ int max_frames_per_packet;
+ H323Capability *cap;
+
+ localCapabilities.RemoveAll();
+
+ if (h323debug) {
+ cout << "Setting capabilities to " << ast_getformatname_multiple(caps_str, sizeof(caps_str), caps) << 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
+ y <<= 1;
+ codec = y;
+ }
+ if (!(caps & codec) || (alreadysent & codec) || !(codec & AST_FORMAT_AUDIO_MASK))
+ continue;
+ alreadysent |= codec;
+ format = ast_codec_pref_getsize(prefs, codec);
+ frames_per_packet = (format.inc_ms ? format.cur_ms / format.inc_ms : format.cur_ms);
+ max_frames_per_packet = (format.inc_ms ? format.max_ms / format.inc_ms : 0);
+ switch(codec) {
+#if 0
+ 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
+ case AST_FORMAT_G729A:
+ AST_G729ACapability *g729aCap;
+ AST_G729Capability *g729Cap;
+ lastcap = localCapabilities.SetCapability(0, 0, g729aCap = new AST_G729ACapability(frames_per_packet));
+ lastcap = localCapabilities.SetCapability(0, 0, g729Cap = new AST_G729Capability(frames_per_packet));
+ if (max_frames_per_packet) {
+ g729aCap->SetTxFramesInPacket(max_frames_per_packet);
+ g729Cap->SetTxFramesInPacket(max_frames_per_packet);
+ }
+ break;
+ case AST_FORMAT_G723_1:
+ AST_G7231Capability *g7231Cap;
+ lastcap = localCapabilities.SetCapability(0, 0, g7231Cap = new AST_G7231Capability(frames_per_packet, TRUE));
+ if (max_frames_per_packet)
+ g7231Cap->SetTxFramesInPacket(max_frames_per_packet);
+ lastcap = localCapabilities.SetCapability(0, 0, g7231Cap = new AST_G7231Capability(frames_per_packet, FALSE));
+ if (max_frames_per_packet)
+ g7231Cap->SetTxFramesInPacket(max_frames_per_packet);
+ break;
+ case AST_FORMAT_GSM:
+ AST_GSM0610Capability *gsmCap;
+ lastcap = localCapabilities.SetCapability(0, 0, gsmCap = new AST_GSM0610Capability(frames_per_packet));
+ if (max_frames_per_packet)
+ gsmCap->SetTxFramesInPacket(max_frames_per_packet);
+ break;
+ case AST_FORMAT_ULAW:
+ AST_G711Capability *g711uCap;
+ lastcap = localCapabilities.SetCapability(0, 0, g711uCap = new AST_G711Capability(format.cur_ms, H323_G711Capability::muLaw));
+ if (format.max_ms)
+ g711uCap->SetTxFramesInPacket(format.max_ms);
+ break;
+ case AST_FORMAT_ALAW:
+ AST_G711Capability *g711aCap;
+ lastcap = localCapabilities.SetCapability(0, 0, g711aCap = new AST_G711Capability(format.cur_ms, H323_G711Capability::ALaw));
+ if (format.max_ms)
+ g711aCap->SetTxFramesInPacket(format.max_ms);
+ break;
+ case AST_FORMAT_G726_AAL2:
+ AST_CiscoG726Capability *g726Cap;
+ lastcap = localCapabilities.SetCapability(0, 0, g726Cap = new AST_CiscoG726Capability(frames_per_packet));
+ if (max_frames_per_packet)
+ g726Cap->SetTxFramesInPacket(max_frames_per_packet);
+ break;
+ default:
+ alreadysent &= ~codec;
+ break;
+ }
+ }
+
+ cap = new H323_UserInputCapability(H323_UserInputCapability::HookFlashH245);
+ if (cap && cap->IsUsable(*this)) {
+ lastcap++;
+ lastcap = localCapabilities.SetCapability(0, lastcap, cap);
+ } else if (cap)
+ delete cap; /* Capability is not usable */
+
+ dtmfMode = dtmf_mode;
+ if (h323debug) {
+ cout << "DTMF mode is " << (int)dtmfMode << endl;
+ }
+ if (dtmfMode) {
+ lastcap++;
+ if (dtmfMode == H323_DTMF_INBAND) {
+ cap = new H323_UserInputCapability(H323_UserInputCapability::BasicString);
+ if (cap && cap->IsUsable(*this)) {
+ lastcap = localCapabilities.SetCapability(0, lastcap, cap);
+ } else if (cap)
+ delete cap; /* Capability is not usable */
+ sendUserInputMode = SendUserInputAsString;
+ } else {
+ if ((dtmfMode & H323_DTMF_RFC2833) != 0) {
+ cap = new H323_UserInputCapability(H323_UserInputCapability::SignalToneRFC2833);
+ if (cap && cap->IsUsable(*this))
+ lastcap = localCapabilities.SetCapability(0, lastcap, cap);
+ else {
+ dtmfMode |= H323_DTMF_SIGNAL;
+ if (cap)
+ delete cap; /* Capability is not usable */
+ }
+ }
+ if ((dtmfMode & H323_DTMF_CISCO) != 0) {
+ /* Try Cisco's RTP DTMF relay too, but prefer RFC2833 or h245-signal */
+ cap = new AST_CiscoDtmfCapability();
+ if (cap && cap->IsUsable(*this)) {
+ lastcap = localCapabilities.SetCapability(0, lastcap, cap);
+ /* We cannot send Cisco RTP DTMFs, use h245-signal instead */
+ dtmfMode |= H323_DTMF_SIGNAL;
+ } else {
+ dtmfMode |= H323_DTMF_SIGNAL;
+ if (cap)
+ delete cap; /* Capability is not usable */
+ }
+ }
+ if ((dtmfMode & H323_DTMF_SIGNAL) != 0) {
+ /* Cisco usually sends DTMF correctly only through h245-alphanumeric or h245-signal */
+ cap = new H323_UserInputCapability(H323_UserInputCapability::SignalToneH245);
+ if (cap && cap->IsUsable(*this))
+ lastcap = localCapabilities.SetCapability(0, lastcap, cap);
+ else if (cap)
+ delete cap; /* Capability is not usable */
+ }
+ sendUserInputMode = SendUserInputAsTone; /* RFC2833 transmission handled at Asterisk level */
+ }
+ }
+
+ if (h323debug) {
+ cout << "Allowed Codecs for " << GetCallToken() << " (" << GetSignallingChannel()->GetLocalAddress() << "):\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;
+}
+
+#ifdef H323_H450
+void MyH323Connection::OnReceivedLocalCallHold(int linkedId)
+{
+ if (on_hold)
+ on_hold(GetCallReference(), (const char *)GetCallToken(), 1);
+}
+
+void MyH323Connection::OnReceivedLocalCallRetrieve(int linkedId)
+{
+ if (on_hold)
+ on_hold(GetCallReference(), (const char *)GetCallToken(), 0);
+}
+#endif
+
+void MyH323Connection::MyHoldCall(BOOL isHold)
+{
+ if (((holdHandling & H323_HOLD_NOTIFY) != 0) || ((holdHandling & H323_HOLD_Q931ONLY) != 0)) {
+ PBYTEArray x ((const BYTE *)(isHold ? "\xF9" : "\xFA"), 1);
+ H323SignalPDU signal;
+ signal.BuildNotify(*this);
+ signal.GetQ931().SetIE((Q931::InformationElementCodes)39 /* Q931::NotifyIE */, x);
+ if (h323debug)
+ cout << "Sending " << (isHold ? "HOLD" : "RETRIEVE") << " notification: " << signal << endl;
+ if ((holdHandling & H323_HOLD_Q931ONLY) != 0) {
+ PBYTEArray rawData;
+ signal.GetQ931().RemoveIE(Q931::UserUserIE);
+ signal.GetQ931().Encode(rawData);
+ signallingChannel->WritePDU(rawData);
+ } else
+ WriteSignalPDU(signal);
+ }
+#ifdef H323_H450
+ if ((holdHandling & H323_HOLD_H450) != 0) {
+ if (isHold)
+ h4504handler->HoldCall(TRUE);
+ else if (IsLocalHold())
+ h4504handler->RetrieveCall();
+ }
+#endif
+}
+
+
+/* MyH323_ExternalRTPChannel */
+MyH323_ExternalRTPChannel::MyH323_ExternalRTPChannel(MyH323Connection & connection,
+ 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());
+ if (!info) {
+ cout << "\tERROR: on_external_rtp_create failure" << endl;
+ return;
+ } else {
+ localIpAddr = info->addr;
+ localPort = info->port;
+ /* tell the H.323 stack */
+ SetExternalAddress(H323TransportAddress(localIpAddr, localPort), H323TransportAddress(localIpAddr, localPort + 1));
+ /* clean up allocated memory */
+ free(info);
+ }
+
+ /* Get the payload code */
+ OpalMediaFormat format(capability.GetFormatName(), FALSE);
+ payloadCode = format.GetPayloadType();
+}
+
+MyH323_ExternalRTPChannel::~MyH323_ExternalRTPChannel()
+{
+ if (h323debug) {
+ cout << "\tExternalRTPChannel Destroyed" << endl;
+ }
+}
+
+BOOL MyH323_ExternalRTPChannel::Start(void)
+{
+ /* Call ancestor first */
+ if (!H323_ExternalRTPChannel::Start()) {
+ return FALSE;
+ }
+
+ if (h323debug) {
+ cout << "\t\tExternal RTP Session Starting" << endl;
+ cout << "\t\tRTP channel id " << sessionID << " parameters:" << endl;
+ }
+
+ /* Collect the remote information */
+ H323_ExternalRTPChannel::GetRemoteAddress(remoteIpAddr, remotePort);
+
+ if (h323debug) {
+ cout << "\t\t-- remoteIpAddress: " << remoteIpAddr << endl;
+ cout << "\t\t-- remotePort: " << remotePort << 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,
+ (const char *)connection.GetCallToken(), (int)payloadCode);
+ return TRUE;
+}
+
+BOOL MyH323_ExternalRTPChannel::OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param)
+{
+ if (h323debug) {
+ cout << " MyH323_ExternalRTPChannel::OnReceivedAckPDU" << endl;
+ }
+
+ if (H323_ExternalRTPChannel::OnReceivedAckPDU(param)) {
+ GetRemoteAddress(remoteIpAddr, remotePort);
+ if (h323debug) {
+ cout << " -- remoteIpAddress: " << remoteIpAddr << endl;
+ cout << " -- remotePort: " << remotePort << endl;
+ }
+ on_start_rtp_channel(connection.GetCallReference(), (const char *)remoteIpAddr.AsString(),
+ remotePort, (const char *)connection.GetCallToken(), (int)payloadCode);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#ifdef H323_H450
+MyH4504Handler::MyH4504Handler(MyH323Connection &_conn, H450xDispatcher &_disp)
+ :H4504Handler(_conn, _disp)
+{
+ conn = &_conn;
+}
+
+void MyH4504Handler::OnReceivedLocalCallHold(int linkedId)
+{
+ if (conn) {
+ conn->Lock();
+ conn->OnReceivedLocalCallHold(linkedId);
+ conn->Unlock();
+ }
+}
+
+void MyH4504Handler::OnReceivedLocalCallRetrieve(int linkedId)
+{
+ if (conn) {
+ conn->Lock();
+ conn->OnReceivedLocalCallRetrieve(linkedId);
+ conn->Unlock();
+ }
+}
+#endif
+
+
+/** IMPLEMENTATION OF C FUNCTIONS */
+
+/**
+ * The extern "C" directive takes care for
+ * the ANSI-C representation of linkable symbols
+ */
+
+extern "C" {
+
+int h323_end_point_exist(void)
+{
+ if (!endPoint) {
+ return 0;
+ }
+ return 1;
+}
+
+void h323_end_point_create(void)
+{
+ channelsOpen = 0;
+ logstream = new PAsteriskLog();
+ localProcess = new MyProcess();
+ localProcess->Main();
+}
+
+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,
+ receive_digit_cb dfunc,
+ answer_call_cb acfunc,
+ progress_cb pgfunc,
+ rfc2833_cb dtmffunc,
+ hangup_cb hangupfunc,
+ setcapabilities_cb capabilityfunc,
+ setpeercapabilities_cb peercapabilityfunc,
+ onhold_cb holdfunc)
+{
+ on_incoming_call = ifunc;
+ on_outgoing_call = sfunc;
+ on_external_rtp_create = rtpfunc;
+ on_start_rtp_channel = lfunc;
+ on_connection_cleared = clfunc;
+ on_chan_ringing = rfunc;
+ on_connection_established = efunc;
+ 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;
+ on_hold = holdfunc;
+}
+
+/**
+ * Add capability to the capability table of the end point.
+ */
+int h323_set_capabilities(const char *token, int cap, int dtmf_mode, struct ast_codec_pref *prefs, int pref_codec)
+{
+ MyH323Connection *conn;
+
+ if (!h323_end_point_exist()) {
+ cout << " ERROR: [h323_set_capablities] No Endpoint, this is bad" << endl;
+ return 1;
+ }
+ if (!token || !*token) {
+ cout << " ERROR: [h323_set_capabilities] Invalid call token specified." << endl;
+ return 1;
+ }
+
+ PString myToken(token);
+ conn = (MyH323Connection *)endPoint->FindConnectionWithLock(myToken);
+ if (!conn) {
+ cout << " ERROR: [h323_set_capabilities] Unable to find connection " << token << endl;
+ return 1;
+ }
+ conn->SetCapabilities((/*conn->bridging ? conn->redir_capabilities :*/ cap), dtmf_mode, prefs, pref_codec);
+ conn->Unlock();
+
+ return 0;
+}
+
+/** 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 */
+ 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;
+ char *num;
+ 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->RemoveAliasName(localProcess->GetUserName());
+
+ if (!e164.IsEmpty()) {
+ cout << "== Adding E.164 \"" << e164 << "\" to endpoint" << endl;
+ endPoint->AddAliasName(e164);
+ }
+ if (strlen(alias->prefix)) {
+ p = prefix = strdup(alias->prefix);
+ while((num = strsep(&p, ",")) != (char *)NULL) {
+ cout << "== Adding Prefix \"" << num << "\" to endpoint" << endl;
+ endPoint->SupportedPrefixes += PString(num);
+ endPoint->SetGateway();
+ }
+ if (prefix)
+ free(prefix);
+ }
+ return 0;
+}
+
+void h323_set_id(char *id)
+{
+ PString h323id(id);
+
+ if (h323debug) {
+ cout << " == Using '" << h323id << "' as our H.323ID for this call" << endl;
+ }
+ /* EVIL HACK */
+ endPoint->SetLocalUserName(h323id);
+}
+
+void h323_show_tokens(void)
+{
+ cout << "Current call tokens: " << setprecision(2) << endPoint->GetAllConnections() << endl;
+}
+
+/** 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)
+{
+ PString gkName = PString(gatekeeper);
+ PString pass = PString(secret);
+ H323TransportUDP *rasChannel;
+
+ if (!h323_end_point_exist()) {
+ cout << "ERROR: [h323_set_gk] No Endpoint, this is bad!" << endl;
+ return 1;
+ }
+
+ if (!gatekeeper) {
+ cout << "Error: Gatekeeper cannot be NULL" << endl;
+ return 1;
+ }
+ if (strlen(secret)) {
+ endPoint->SetGatekeeperPassword(pass);
+ }
+ if (gatekeeper_discover) {
+ /* discover the gk using multicast */
+ 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 MyH323TransportUDP(*endPoint);
+
+ if (!rasChannel) {
+ cout << "Error: No RAS Channel, this is bad" << endl;
+ return 1;
+ }
+ if (endPoint->SetGatekeeper(gkName, rasChannel)) {
+ cout << "== Using " << (endPoint->GetGatekeeper())->GetName() << " as our Gatekeeper." << endl;
+ } else {
+ cout << "Error registering with gatekeeper \"" << gkName << "\". " << endl;
+ /* XXX Maybe we should fire a new thread to attempt to re-register later and not kill asterisk here? */
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/** Send a DTMF tone over the H323Connection with the
+ * specified token.
+ */
+void h323_send_tone(const char *call_token, char tone)
+{
+ if (!h323_end_point_exist()) {
+ cout << "ERROR: [h323_send_tone] No Endpoint, this is bad!" << endl;
+ return;
+ }
+ PString token = PString(call_token);
+ endPoint->SendUserTone(token, tone);
+}
+
+/** Make a call to the remote endpoint.
+ */
+int h323_make_call(char *dest, call_details_t *cd, call_options_t *call_options)
+{
+ int res;
+ PString token;
+ PString host(dest);
+
+ if (!h323_end_point_exist()) {
+ return 1;
+ }
+
+ res = endPoint->MyMakeCall(host, token, &cd->call_reference, call_options);
+ memcpy((char *)(cd->call_token), (const unsigned char *)token, token.GetLength());
+ return res;
+};
+
+int h323_clear_call(const char *call_token, int cause)
+{
+ H225_ReleaseCompleteReason dummy;
+ H323Connection::CallEndReason r = H323Connection::EndedByLocalUser;
+ MyH323Connection *connection;
+ const PString currentToken(call_token);
+
+ if (!h323_end_point_exist()) {
+ return 1;
+ }
+
+ if (cause) {
+ r = H323TranslateToCallEndReason((Q931::CauseValues)(cause), dummy);
+ }
+
+ connection = (MyH323Connection *)endPoint->FindConnectionWithLock(currentToken);
+ if (connection) {
+ connection->SetCause(cause);
+ connection->SetCallEndReason(r);
+ connection->Unlock();
+ }
+ endPoint->ClearCall(currentToken, r);
+ return 0;
+};
+
+/* 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" << 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;
+
+ connection = endPoint->FindConnectionWithLock(currentToken);
+ if (!connection) {
+ cout << "No connection found for " << token << endl;
+ return -1;
+ }
+#if 1
+ ((MyH323Connection *)connection)->MySendProgress();
+#else
+ connection->AnsweringCall(H323Connection::AnswerCallDeferredWithMedia);
+#endif
+ 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)
+{
+ const PString currentToken(token);
+ H323Connection * connection;
+
+ connection = endPoint->FindConnectionWithLock(currentToken);
+
+ if (!connection) {
+ cout << "No connection found for " << token << endl;
+ return -1;
+ }
+ if (!busy) {
+ if (h323debug) {
+ cout << "\tAnswering call " << token << endl;
+ }
+ connection->AnsweringCall(H323Connection::AnswerCallNow);
+ } else {
+ if (h323debug) {
+ cout << "\tdenying call " << token << endl;
+ }
+ connection->AnsweringCall(H323Connection::AnswerCallDenied);
+ }
+ connection->Unlock();
+ return 0;
+}
+
+int h323_soft_hangup(const char *data)
+{
+ PString token(data);
+ BOOL result;
+ cout << "Soft hangup" << endl;
+ result = endPoint->ClearCall(token);
+ return result;
+}
+
+/* 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" << endl;
+ return;
+ }
+
+ cout << "Native Bridge: them [" << them << "]" << endl;
+
+ channel = connection->FindChannel(connection->sessionId, TRUE);
+ connection->bridging = TRUE;
+ connection->CloseLogicalChannelNumber(channel->GetNumber());
+
+ connection->Unlock();
+ return;
+
+}
+
+int h323_hold_call(const char *token, int is_hold)
+{
+ MyH323Connection *conn = (MyH323Connection *)endPoint->FindConnectionWithLock(token);
+ if (!conn) {
+ cout << "ERROR: No connection found, this is bad" << endl;
+ return -1;
+ }
+ conn->MyHoldCall((BOOL)is_hold);
+ conn->Unlock();
+ return 0;
+}
+
+#undef cout
+#undef endl
+void h323_end_process(void)
+{
+ if (endPoint) {
+ endPoint->ClearAllCalls();
+ endPoint->RemoveListener(NULL);
+ delete endPoint;
+ endPoint = NULL;
+ }
+ if (localProcess) {
+ delete localProcess;
+ localProcess = NULL;
+ close(_timerChangePipe[0]);
+ close(_timerChangePipe[1]);
+ }
+ if (logstream) {
+ PTrace::SetLevel(0);
+ PTrace::SetStream(&cout);
+ delete logstream;
+ logstream = NULL;
+ }
+}
+
+} /* extern "C" */
+
diff --git a/trunk/channels/h323/ast_h323.h b/trunk/channels/h323/ast_h323.h
new file mode 100644
index 000000000..39af427ae
--- /dev/null
+++ b/trunk/channels/h323/ast_h323.h
@@ -0,0 +1,189 @@
+/*
+ * ast_h323.h
+ *
+ * OpenH323 Channel Driver for ASTERISK PBX.
+ * By Jeremy McNamara
+ * For The NuFone Network
+ *
+ * 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
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * Version Info: $Id$
+ */
+
+#ifndef AST_H323_H
+#define AST_H323_H
+
+#define VERSION(a,b,c) ((a)*10000+(b)*100+(c))
+
+class MyH323EndPoint : public H323EndPoint
+{
+ PCLASSINFO(MyH323EndPoint, H323EndPoint);
+
+public:
+ MyH323EndPoint();
+ 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 &);
+ 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;
+};
+
+class MyH323Connection : public H323Connection
+{
+ PCLASSINFO(MyH323Connection, H323Connection);
+
+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 &);
+ void OnReceivedReleaseComplete(const H323SignalPDU &);
+ BOOL OnAlerting(const H323SignalPDU &, const PString &);
+ BOOL OnSendReleaseComplete(H323SignalPDU &);
+ BOOL OnReceivedSignalSetup(const H323SignalPDU &);
+ BOOL OnReceivedFacility(const H323SignalPDU &);
+ BOOL OnSendSignalSetup(H323SignalPDU &);
+ BOOL OnStartLogicalChannel(H323Channel &);
+ 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 &);
+ BOOL MySendProgress();
+ void OnSendCapabilitySet(H245_TerminalCapabilitySet &);
+ void OnSetLocalCapabilities();
+ void SetCapabilities(int, int, void *, int);
+ BOOL OnReceivedCapabilitySet(const H323Capabilities &, const H245_MultiplexCapability *,
+ 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);
+ virtual H323Connection::CallEndReason SendSignalSetup(const PString&, const H323TransportAddress&);
+#ifdef TUNNELLING
+ virtual BOOL HandleSignalPDU(H323SignalPDU &pdu);
+ BOOL EmbedTunneledInfo(H323SignalPDU &pdu);
+#endif
+#ifdef H323_H450
+ virtual void OnReceivedLocalCallHold(int linkedId);
+ virtual void OnReceivedLocalCallRetrieve(int linkedId);
+#endif
+ void MyHoldCall(BOOL localHold);
+
+ PString sourceAliases;
+ PString destAliases;
+ PString sourceE164;
+ PString destE164;
+ int cid_presentation;
+ int cid_ton;
+ PString rdnis;
+ int redirect_reason;
+ int transfer_capability;
+
+ WORD sessionId;
+ BOOL bridging;
+#ifdef TUNNELLING
+ int remoteTunnelOptions;
+ int tunnelOptions;
+#endif
+
+ unsigned holdHandling;
+ unsigned progressSetup;
+ unsigned progressAlert;
+ int cause;
+
+ RTP_DataFrame::PayloadTypes dtmfCodec[2];
+ int dtmfMode;
+};
+
+class MyH323_ExternalRTPChannel : public H323_ExternalRTPChannel
+{
+ PCLASSINFO(MyH323_ExternalRTPChannel, H323_ExternalRTPChannel);
+
+public:
+ MyH323_ExternalRTPChannel(
+ MyH323Connection & connection,
+ const H323Capability & capability,
+ Directions direction,
+ unsigned sessionID);
+
+ ~MyH323_ExternalRTPChannel();
+
+ /* Overrides */
+ BOOL Start(void);
+ BOOL OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param);
+
+protected:
+ BYTE payloadCode;
+
+ PIPSocket::Address localIpAddr;
+ PIPSocket::Address remoteIpAddr;
+ 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).
+ */
+class MyProcess : public PProcess
+{
+ PCLASSINFO(MyProcess, PProcess);
+
+public:
+ MyProcess();
+ ~MyProcess();
+ void Main();
+};
+
+#ifdef H323_H450
+#include <h450pdu.h>
+
+class MyH4504Handler : public H4504Handler
+{
+ PCLASSINFO(MyH4504Handler, H4504Handler);
+
+public:
+ MyH4504Handler(MyH323Connection &_conn, H450xDispatcher &_disp);
+ virtual void OnReceivedLocalCallHold(int linkedId);
+ virtual void OnReceivedLocalCallRetrieve(int linkedId);
+
+private:
+ MyH323Connection *conn;
+};
+#endif
+
+#include "compat_h323.h"
+
+#endif /* !defined AST_H323_H */
diff --git a/trunk/channels/h323/caps_h323.cxx b/trunk/channels/h323/caps_h323.cxx
new file mode 100644
index 000000000..ebb90f3f2
--- /dev/null
+++ b/trunk/channels/h323/caps_h323.cxx
@@ -0,0 +1,383 @@
+#include <ptlib.h>
+#include <h323.h>
+#include <h245.h>
+#include "ast_h323.h"
+#include "caps_h323.h"
+
+#define DEFINE_G711_CAPABILITY(cls, code, capName) \
+class cls : public AST_G711Capability { \
+public: \
+ cls() : AST_G711Capability(240, code) { } \
+}; \
+H323_REGISTER_CAPABILITY(cls, capName) \
+
+DEFINE_G711_CAPABILITY(AST_G711ALaw64Capability, H323_G711Capability::ALaw, OPAL_G711_ALAW_64K);
+DEFINE_G711_CAPABILITY(AST_G711uLaw64Capability, H323_G711Capability::muLaw, OPAL_G711_ULAW_64K);
+H323_REGISTER_CAPABILITY(AST_G7231Capability, OPAL_G7231);
+H323_REGISTER_CAPABILITY(AST_G729Capability, OPAL_G729);
+H323_REGISTER_CAPABILITY(AST_G729ACapability, OPAL_G729A);
+H323_REGISTER_CAPABILITY(AST_GSM0610Capability, OPAL_GSM0610);
+H323_REGISTER_CAPABILITY(AST_CiscoG726Capability, CISCO_G726r32);
+H323_REGISTER_CAPABILITY(AST_CiscoDtmfCapability, CISCO_DTMF_RELAY);
+
+OPAL_MEDIA_FORMAT_DECLARE(OpalG711ALaw64kFormat,
+ OPAL_G711_ALAW_64K,
+ OpalMediaFormat::DefaultAudioSessionID,
+ RTP_DataFrame::PCMA,
+ TRUE, // Needs jitter
+ 64000, // bits/sec
+ 8, // bytes/frame
+ 8, // 1 millisecond/frame
+ OpalMediaFormat::AudioTimeUnits,
+ 0);
+OPAL_MEDIA_FORMAT_DECLARE(OpalG711uLaw64kFormat,
+ OPAL_G711_ULAW_64K,
+ OpalMediaFormat::DefaultAudioSessionID,
+ RTP_DataFrame::PCMU,
+ TRUE, // Needs jitter
+ 64000, // bits/sec
+ 8, // bytes/frame
+ 8, // 1 millisecond/frame
+ OpalMediaFormat::AudioTimeUnits,
+ 0);
+OPAL_MEDIA_FORMAT_DECLARE(OpalG729Format,
+ OPAL_G729,
+ OpalMediaFormat::DefaultAudioSessionID,
+ RTP_DataFrame::G729,
+ TRUE, // Needs jitter
+ 8000, // bits/sec
+ 10, // bytes
+ 80, // 10 milliseconds
+ OpalMediaFormat::AudioTimeUnits,
+ 0);
+OPAL_MEDIA_FORMAT_DECLARE(OpalG729AFormat,
+ OPAL_G729 "A",
+ OpalMediaFormat::DefaultAudioSessionID,
+ RTP_DataFrame::G729,
+ TRUE, // Needs jitter
+ 8000, // bits/sec
+ 10, // bytes
+ 80, // 10 milliseconds
+ OpalMediaFormat::AudioTimeUnits,
+ 0);
+OPAL_MEDIA_FORMAT_DECLARE(OpalG7231_6k3Format,
+ OPAL_G7231_6k3,
+ OpalMediaFormat::DefaultAudioSessionID,
+ RTP_DataFrame::G7231,
+ TRUE, // Needs jitter
+ 6400, // bits/sec
+ 24, // bytes
+ 240, // 30 milliseconds
+ OpalMediaFormat::AudioTimeUnits,
+ 0);
+OPAL_MEDIA_FORMAT_DECLARE(OpalG7231A_6k3Format,
+ OPAL_G7231A_6k3,
+ OpalMediaFormat::DefaultAudioSessionID,
+ RTP_DataFrame::G7231,
+ TRUE, // Needs jitter
+ 6400, // bits/sec
+ 24, // bytes
+ 240, // 30 milliseconds
+ OpalMediaFormat::AudioTimeUnits,
+ 0);
+OPAL_MEDIA_FORMAT_DECLARE(OpalGSM0610Format,
+ OPAL_GSM0610,
+ OpalMediaFormat::DefaultAudioSessionID,
+ RTP_DataFrame::GSM,
+ TRUE, // Needs jitter
+ 13200, // bits/sec
+ 33, // bytes
+ 160, // 20 milliseconds
+ OpalMediaFormat::AudioTimeUnits,
+ 0);
+OPAL_MEDIA_FORMAT_DECLARE(OpalCiscoG726Format,
+ CISCO_G726r32,
+ OpalMediaFormat::DefaultAudioSessionID,
+ RTP_DataFrame::G726,
+ TRUE, // Needs jitter
+ 32000, // bits/sec
+ 4, // bytes
+ 8, // 1 millisecond
+ OpalMediaFormat::AudioTimeUnits,
+ 0);
+#if 0
+OPAL_MEDIA_FORMAT_DECLARE(OpalCiscoDTMFRelayFormat,
+ CISCO_DTMF_RELAY,
+ OpalMediaFormat::DefaultAudioSessionID,
+ (RTP_DataFrame::PayloadTypes)121, // Choose this for Cisco IOS compatibility
+ TRUE, // Needs jitter
+ 100, // bits/sec
+ 4, // bytes/frame
+ 8*150, // 150 millisecond
+ OpalMediaFormat::AudioTimeUnits,
+ 0);
+#endif
+
+/*
+ * Capability: G.711
+ */
+AST_G711Capability::AST_G711Capability(int rx_frames, H323_G711Capability::Mode m, H323_G711Capability::Speed s)
+ : H323AudioCapability(rx_frames, 30) // 240ms max, 30ms desired
+{
+ mode = m;
+ speed = s;
+}
+
+
+PObject * AST_G711Capability::Clone() const
+{
+ return new AST_G711Capability(*this);
+}
+
+
+unsigned AST_G711Capability::GetSubType() const
+{
+ static const unsigned G711SubType[2][2] = {
+ { H245_AudioCapability::e_g711Alaw64k, H245_AudioCapability::e_g711Alaw56k },
+ { H245_AudioCapability::e_g711Ulaw64k, H245_AudioCapability::e_g711Ulaw56k }
+ };
+ return G711SubType[mode][speed];
+}
+
+
+PString AST_G711Capability::GetFormatName() const
+{
+ static const char * const G711Name[2][2] = {
+ { OPAL_G711_ALAW_64K, OPAL_G711_ALAW_56K },
+ { OPAL_G711_ULAW_64K, OPAL_G711_ULAW_56K },
+ };
+ return G711Name[mode][speed];
+}
+
+
+H323Codec * AST_G711Capability::CreateCodec(H323Codec::Direction direction) const
+{
+ return NULL;
+}
+
+
+/*
+ * Capability: G.723.1
+ */
+AST_G7231Capability::AST_G7231Capability(int rx_frames, BOOL annexA_)
+ : H323AudioCapability(rx_frames, 4)
+{
+ annexA = annexA_;
+}
+
+PObject::Comparison AST_G7231Capability::Compare(const PObject & obj) const
+{
+ Comparison result = H323AudioCapability::Compare(obj);
+ if (result != EqualTo) {
+ return result;
+ }
+ PINDEX otherAnnexA = ((const AST_G7231Capability &)obj).annexA;
+ if (annexA < otherAnnexA) {
+ return LessThan;
+ }
+ if (annexA > otherAnnexA) {
+ return GreaterThan;
+ }
+ return EqualTo;
+}
+
+PObject * AST_G7231Capability::Clone() const
+{
+ return new AST_G7231Capability(*this);
+}
+
+PString AST_G7231Capability::GetFormatName() const
+{
+ return (annexA ? OPAL_G7231 "A" : OPAL_G7231);
+}
+
+unsigned AST_G7231Capability::GetSubType() const
+{
+ return H245_AudioCapability::e_g7231;
+}
+
+BOOL AST_G7231Capability::OnSendingPDU(H245_AudioCapability & cap,
+ 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;
+}
+
+BOOL AST_G7231Capability::OnReceivedPDU(const H245_AudioCapability & cap,
+ unsigned & packetSize)
+{
+ if (cap.GetTag() != H245_AudioCapability::e_g7231) {
+ return FALSE;
+ }
+ const H245_AudioCapability_g7231 & g7231 = cap;
+ packetSize = g7231.m_maxAl_sduAudioFrames;
+ annexA = g7231.m_silenceSuppression;
+ return TRUE;
+}
+
+H323Codec * AST_G7231Capability::CreateCodec(H323Codec::Direction direction) const
+{
+ return NULL;
+}
+
+/*
+ * Capability: G.729
+ */
+AST_G729Capability::AST_G729Capability(int rx_frames)
+ : H323AudioCapability(rx_frames, 2)
+{
+}
+
+PObject * AST_G729Capability::Clone() const
+{
+ return new AST_G729Capability(*this);
+}
+
+unsigned AST_G729Capability::GetSubType() const
+{
+ return H245_AudioCapability::e_g729;
+}
+
+PString AST_G729Capability::GetFormatName() const
+{
+ return OPAL_G729;
+}
+
+H323Codec * AST_G729Capability::CreateCodec(H323Codec::Direction direction) const
+{
+ return NULL;
+}
+
+/*
+ * Capability: G.729A
+ */
+AST_G729ACapability::AST_G729ACapability(int rx_frames)
+ : H323AudioCapability(rx_frames, 6)
+{
+}
+
+PObject * AST_G729ACapability::Clone() const
+{
+ return new AST_G729ACapability(*this);
+}
+
+unsigned AST_G729ACapability::GetSubType() const
+{
+ return H245_AudioCapability::e_g729AnnexA;
+}
+
+PString AST_G729ACapability::GetFormatName() const
+{
+ return OPAL_G729A;
+}
+
+H323Codec * AST_G729ACapability::CreateCodec(H323Codec::Direction direction) const
+{
+ return NULL;
+}
+
+/*
+ * Capability: GSM full rate
+ */
+AST_GSM0610Capability::AST_GSM0610Capability(int rx_frames, int comfortNoise_, int scrambled_)
+ : H323AudioCapability(rx_frames, 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 * 33;
+ 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 + 32) / 33;
+ comfortNoise = gsm.m_comfortNoise;
+ scrambled = gsm.m_scrambled;
+
+ return TRUE;
+}
+
+PString AST_GSM0610Capability::GetFormatName() const
+{
+ return OPAL_GSM0610;
+}
+
+H323Codec * AST_GSM0610Capability::CreateCodec(H323Codec::Direction direction) const
+{
+ return NULL;
+}
+
+/*
+ * Capability: G.726 32 Kbps
+ */
+AST_CiscoG726Capability::AST_CiscoG726Capability(int rx_frames)
+ : H323NonStandardAudioCapability(rx_frames, 240,
+ 181, 0, 18,
+ (const BYTE *)"G726r32", 0)
+{
+}
+
+PObject *AST_CiscoG726Capability::Clone() const
+{
+ return new AST_CiscoG726Capability(*this);
+}
+
+H323Codec *AST_CiscoG726Capability::CreateCodec(H323Codec::Direction direction) const
+{
+ return NULL;
+}
+
+PString AST_CiscoG726Capability::GetFormatName() const
+{
+ return PString(CISCO_G726r32);
+}
+
+/*
+ * Capability: Cisco RTP DTMF Relay
+ */
+AST_CiscoDtmfCapability::AST_CiscoDtmfCapability()
+ : H323NonStandardDataCapability(0, 181, 0, 18, (const BYTE *)"RtpDtmfRelay", 0)
+{
+ rtpPayloadType = (RTP_DataFrame::PayloadTypes)121;
+}
+
+PObject *AST_CiscoDtmfCapability::Clone() const
+{
+ return new AST_CiscoDtmfCapability(*this);
+}
+
+H323Codec *AST_CiscoDtmfCapability::CreateCodec(H323Codec::Direction direction) const
+{
+ return NULL;
+}
+
+PString AST_CiscoDtmfCapability::GetFormatName() const
+{
+ return PString(CISCO_DTMF_RELAY);
+}
diff --git a/trunk/channels/h323/caps_h323.h b/trunk/channels/h323/caps_h323.h
new file mode 100644
index 000000000..8058054db
--- /dev/null
+++ b/trunk/channels/h323/caps_h323.h
@@ -0,0 +1,172 @@
+#ifndef __AST_H323CAPS_H
+#define __AST_H323CAPS_H
+
+/**This class describes the G.711 codec capability.
+ */
+class AST_G711Capability : public H323AudioCapability
+{
+ PCLASSINFO(AST_G711Capability, H323AudioCapability);
+
+public:
+ AST_G711Capability(int rx_frames = 125, H323_G711Capability::Mode _mode = H323_G711Capability::muLaw, H323_G711Capability::Speed _speed = H323_G711Capability::At64k);
+ virtual PObject *Clone() const;
+ virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
+ virtual unsigned GetSubType() const;
+ virtual PString GetFormatName() const;
+
+protected:
+ H323_G711Capability::Mode mode;
+ H323_G711Capability::Speed speed;
+};
+
+/**This class describes the G.723.1 codec capability.
+ */
+class AST_G7231Capability : public H323AudioCapability
+{
+ PCLASSINFO(AST_G7231Capability, H323AudioCapability);
+
+public:
+ AST_G7231Capability(int rx_frames = 7, 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);
+
+public:
+ AST_G729Capability(int rx_frames = 24);
+ /* 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;
+};
+
+/* This class describes the VoiceAge G729A codec capability. */
+class AST_G729ACapability : public H323AudioCapability
+{
+ PCLASSINFO(AST_G729ACapability, H323AudioCapability);
+
+public:
+ /* Create a new G.729A capability. */
+ AST_G729ACapability(int rx_frames = 24);
+
+ /* 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;
+};
+
+/* 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 rx_frames = 24, 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;
+};
+
+#define CISCO_G726r32 "G726r32"
+
+class AST_CiscoG726Capability : public H323NonStandardAudioCapability {
+ PCLASSINFO(AST_CiscoG726Capability, H323NonStandardAudioCapability);
+
+public:
+ /* Create a new Cisco G.726 capability */
+ AST_CiscoG726Capability(int rx_frames = 80);
+
+ /* 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 name of the media data format this class represents. */
+ virtual PString GetFormatName() const;
+};
+
+#define CISCO_DTMF_RELAY "UserInput/RtpDtmfRelay"
+
+class AST_CiscoDtmfCapability : public H323NonStandardDataCapability
+{
+ PCLASSINFO(AST_CiscoDtmfCapability, H323NonStandardDataCapability);
+
+public:
+ /* Create a new Cisco RTP DTMF Relay capability */
+ AST_CiscoDtmfCapability();
+
+ /* 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 name of the media data format this class represents. */
+ virtual PString GetFormatName() const;
+
+ virtual H323Channel *CreateChannel(H323Connection &,
+ H323Channel::Directions,
+ unsigned,
+ const H245_H2250LogicalChannelParameters *) const
+ {
+ return NULL;
+ }
+};
+
+#endif /* __AST_H323CAPS_H */
diff --git a/trunk/channels/h323/chan_h323.h b/trunk/channels/h323/chan_h323.h
new file mode 100644
index 000000000..62b670fda
--- /dev/null
+++ b/trunk/channels/h323/chan_h323.h
@@ -0,0 +1,269 @@
+/*
+ * chan_h323.h
+ *
+ * OpenH323 Channel Driver for ASTERISK PBX.
+ * By Jeremy McNamara
+ * For The NuFone Network
+ *
+ * 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
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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)
+
+#define H323_HOLD_NOTIFY (1 << 0)
+#define H323_HOLD_Q931ONLY (1 << 1)
+#define H323_HOLD_H450 (1 << 2)
+
+/** call_option struct holds various bits
+ * of information for each call */
+typedef struct call_options {
+ char cid_num[80];
+ char cid_name[80];
+ char cid_rdnis[80];
+ int redirect_reason;
+ int presentation;
+ int type_of_number;
+ int transfer_capability;
+ int fastStart;
+ int h245Tunneling;
+ int silenceSuppression;
+ int progress_setup;
+ int progress_alert;
+ int progress_audio;
+ int dtmfcodec[2];
+ int dtmfmode;
+ int capability;
+ int bridge;
+ int nat;
+ int tunnelOptions;
+ int holdHandling;
+ struct ast_codec_pref prefs;
+} call_options_t;
+
+/* structure to hold the valid asterisk users */
+struct oh323_user {
+ ASTOBJ_COMPONENTS(struct oh323_user);
+// char name[80];
+ char context[80];
+ char secret[80];
+ char accountcode[AST_MAX_ACCOUNT_CODE];
+ int amaflags;
+ int host;
+ struct sockaddr_in addr;
+ struct ast_ha *ha;
+ call_options_t options;
+};
+
+/* structure to hold the valid asterisk peers
+ All peers are registered to a GK if there is one */
+struct oh323_peer {
+ ASTOBJ_COMPONENTS(struct oh323_peer);
+ char mailbox[80];
+ int delme;
+ struct sockaddr_in addr;
+ struct ast_ha *ha;
+ call_options_t options;
+};
+
+/* structure to hold the H.323 aliases which get registered to
+ the H.323 endpoint and gatekeeper */
+struct oh323_alias {
+ 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];
+};
+
+/** 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 {
+ unsigned int call_reference;
+ 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 type_of_number;
+ int transfer_capability;
+ char *sourceIp;
+} call_details_t;
+
+typedef struct rtp_info {
+ char addr[32];
+ unsigned int port;
+} rtp_info_t;
+
+/* This is a callback prototype function, called pass
+ DTMF down the RTP. */
+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;
+
+/* This is a callback prototype function, called to send
+ 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;
+
+/* This is a callback that happens when call progress is
+ * made, and handles inband progress */
+typedef int (*progress_cb)(unsigned, const char *, int);
+extern progress_cb on_progress;
+
+/* This is a callback prototype function, called upon
+ an incoming call happens. */
+typedef call_options_t *(*setup_incoming_cb)(call_details_t *);
+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;
+
+/* This is a callback prototype function, called when
+ OnAlerting is invoked */
+typedef void (*chan_ringing_cb)(unsigned, const char *);
+extern chan_ringing_cb on_chan_ringing;
+
+/* This is a callback protoype function, called when
+ OnConnectionEstablished is inovked */
+typedef void (*con_established_cb)(unsigned, const char *);
+extern con_established_cb on_connection_established;
+
+/* This is a callback prototype function, called when
+ OnConnectionCleared callback is invoked */
+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 */
+typedef int (*answer_call_cb)(unsigned, const char *);
+extern answer_call_cb on_answer_call;
+
+/* This is a callback prototype function, called when
+ we know which RTP payload type RFC2833 will be
+ transmitted */
+typedef void (*rfc2833_cb)(unsigned, const char *, int, int);
+extern rfc2833_cb on_set_rfc2833_payload;
+
+typedef void (*hangup_cb)(unsigned, const char *, int);
+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, struct ast_codec_pref *);
+extern setpeercapabilities_cb on_setpeercapabilities;
+
+typedef void (*onhold_cb)(unsigned, const char *, int);
+extern onhold_cb on_hold;
+
+/* debug flag */
+extern int h323debug;
+
+#define H323_DTMF_RFC2833 (1 << 0)
+#define H323_DTMF_CISCO (1 << 1)
+#define H323_DTMF_SIGNAL (1 << 2)
+#define H323_DTMF_INBAND (1 << 3)
+
+#define H323_DTMF_RFC2833_PT 101
+#define H323_DTMF_CISCO_PT 121
+
+#ifndef BOOL
+#define BOOL int
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#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,
+ receive_digit_cb,
+ answer_call_cb,
+ progress_cb,
+ rfc2833_cb,
+ hangup_cb,
+ setcapabilities_cb,
+ setpeercapabilities_cb,
+ onhold_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 *);
+ void h323_show_tokens(void);
+
+ /* H323 listener related funcions */
+ int h323_start_listener(int, struct sockaddr_in);
+
+ void h323_native_bridge(const char *, const char *, char *);
+
+ /* Send a DTMF tone to remote endpoint */
+ void h323_send_tone(const char *call_token, char tone);
+
+ /* 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_show_codec(int fd, int argc, char *argv[]);
+ int h323_hold_call(const char *token, int);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/trunk/channels/h323/cisco-h225.asn b/trunk/channels/h323/cisco-h225.asn
new file mode 100644
index 000000000..1372e67d5
--- /dev/null
+++ b/trunk/channels/h323/cisco-h225.asn
@@ -0,0 +1,74 @@
+CISCO-H225-MESSAGES DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+H323_UU_NonStdInfo ::= SEQUENCE
+{
+ version INTEGER OPTIONAL,
+ protoParam ProtoParam OPTIONAL,
+ commonParam CommonParam OPTIONAL,
+ ...,
+ dummy1 OCTET STRING OPTIONAL,
+ progIndParam ProgIndParam OPTIONAL,
+ callMgrParam CallMgrParam OPTIONAL,
+ callSignallingParam CallSignallingParam OPTIONAL,
+ dummy2 OCTET STRING OPTIONAL,
+ callPreserveParam CallPreserveParam OPTIONAL
+}
+
+CommonParam ::= SEQUENCE
+{
+ redirectIEinfo RedirectIEinfo,
+ ...
+}
+
+RedirectIEinfo ::= SEQUENCE
+{
+ redirectIE OCTET STRING,
+ ...
+}
+
+ProgIndParam ::= SEQUENCE
+{
+ progIndIEinfo ProgIndIEinfo,
+ ...
+}
+
+ProgIndIEinfo ::= SEQUENCE
+{
+ progIndIE OCTET STRING,
+ ...
+}
+
+ProtoParam ::= SEQUENCE
+{
+ qsigNonStdInfo QsigNonStdInfo,
+ ...
+}
+
+QsigNonStdInfo ::= SEQUENCE
+{
+ iei INTEGER,
+ rawMesg OCTET STRING,
+ ...
+}
+
+CallMgrParam ::= SEQUENCE
+{
+ interclusterVersion INTEGER,
+ enterpriseID OCTET STRING,
+ ...
+}
+
+CallPreserveParam ::= SEQUENCE
+{
+ callPreserveIE BOOLEAN,
+ ...
+}
+
+CallSignallingParam ::= SEQUENCE
+{
+ connectedNumber OCTET STRING (1..127) OPTIONAL,
+ ...
+}
+
+END
diff --git a/trunk/channels/h323/cisco-h225.cxx b/trunk/channels/h323/cisco-h225.cxx
new file mode 100644
index 000000000..37adc4e87
--- /dev/null
+++ b/trunk/channels/h323/cisco-h225.cxx
@@ -0,0 +1,853 @@
+//
+// cisco-h225.cxx
+//
+// Code automatically generated by asnparse.
+//
+
+#ifdef P_USE_PRAGMA
+#pragma implementation "cisco-h225.h"
+#endif
+
+#include <ptlib.h>
+#include "cisco-h225.h"
+
+#define new PNEW
+
+
+#if ! H323_DISABLE_CISCO_H225
+
+//
+// RedirectIEinfo
+//
+
+CISCO_H225_RedirectIEinfo::CISCO_H225_RedirectIEinfo(unsigned tag, PASN_Object::TagClass tagClass)
+ : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
+{
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_RedirectIEinfo::PrintOn(ostream & strm) const
+{
+ int indent = strm.precision() + 2;
+ strm << "{\n";
+ strm << setw(indent+13) << "redirectIE = " << setprecision(indent) << m_redirectIE << '\n';
+ strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_RedirectIEinfo::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(PIsDescendant(&obj, CISCO_H225_RedirectIEinfo), PInvalidCast);
+#endif
+ const CISCO_H225_RedirectIEinfo & other = (const CISCO_H225_RedirectIEinfo &)obj;
+
+ Comparison result;
+
+ if ((result = m_redirectIE.Compare(other.m_redirectIE)) != EqualTo)
+ return result;
+
+ return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_RedirectIEinfo::GetDataLength() const
+{
+ PINDEX length = 0;
+ length += m_redirectIE.GetObjectLength();
+ return length;
+}
+
+
+BOOL CISCO_H225_RedirectIEinfo::Decode(PASN_Stream & strm)
+{
+ if (!PreambleDecode(strm))
+ return FALSE;
+
+ if (!m_redirectIE.Decode(strm))
+ return FALSE;
+
+ return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_RedirectIEinfo::Encode(PASN_Stream & strm) const
+{
+ PreambleEncode(strm);
+
+ m_redirectIE.Encode(strm);
+
+ UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_RedirectIEinfo::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(IsClass(CISCO_H225_RedirectIEinfo::Class()), PInvalidCast);
+#endif
+ return new CISCO_H225_RedirectIEinfo(*this);
+}
+
+
+//
+// ProgIndIEinfo
+//
+
+CISCO_H225_ProgIndIEinfo::CISCO_H225_ProgIndIEinfo(unsigned tag, PASN_Object::TagClass tagClass)
+ : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
+{
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_ProgIndIEinfo::PrintOn(ostream & strm) const
+{
+ int indent = strm.precision() + 2;
+ strm << "{\n";
+ strm << setw(indent+12) << "progIndIE = " << setprecision(indent) << m_progIndIE << '\n';
+ strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_ProgIndIEinfo::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(PIsDescendant(&obj, CISCO_H225_ProgIndIEinfo), PInvalidCast);
+#endif
+ const CISCO_H225_ProgIndIEinfo & other = (const CISCO_H225_ProgIndIEinfo &)obj;
+
+ Comparison result;
+
+ if ((result = m_progIndIE.Compare(other.m_progIndIE)) != EqualTo)
+ return result;
+
+ return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_ProgIndIEinfo::GetDataLength() const
+{
+ PINDEX length = 0;
+ length += m_progIndIE.GetObjectLength();
+ return length;
+}
+
+
+BOOL CISCO_H225_ProgIndIEinfo::Decode(PASN_Stream & strm)
+{
+ if (!PreambleDecode(strm))
+ return FALSE;
+
+ if (!m_progIndIE.Decode(strm))
+ return FALSE;
+
+ return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_ProgIndIEinfo::Encode(PASN_Stream & strm) const
+{
+ PreambleEncode(strm);
+
+ m_progIndIE.Encode(strm);
+
+ UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_ProgIndIEinfo::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(IsClass(CISCO_H225_ProgIndIEinfo::Class()), PInvalidCast);
+#endif
+ return new CISCO_H225_ProgIndIEinfo(*this);
+}
+
+
+//
+// QsigNonStdInfo
+//
+
+CISCO_H225_QsigNonStdInfo::CISCO_H225_QsigNonStdInfo(unsigned tag, PASN_Object::TagClass tagClass)
+ : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
+{
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_QsigNonStdInfo::PrintOn(ostream & strm) const
+{
+ int indent = strm.precision() + 2;
+ strm << "{\n";
+ strm << setw(indent+6) << "iei = " << setprecision(indent) << m_iei << '\n';
+ strm << setw(indent+10) << "rawMesg = " << setprecision(indent) << m_rawMesg << '\n';
+ strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_QsigNonStdInfo::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(PIsDescendant(&obj, CISCO_H225_QsigNonStdInfo), PInvalidCast);
+#endif
+ const CISCO_H225_QsigNonStdInfo & other = (const CISCO_H225_QsigNonStdInfo &)obj;
+
+ Comparison result;
+
+ if ((result = m_iei.Compare(other.m_iei)) != EqualTo)
+ return result;
+ if ((result = m_rawMesg.Compare(other.m_rawMesg)) != EqualTo)
+ return result;
+
+ return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_QsigNonStdInfo::GetDataLength() const
+{
+ PINDEX length = 0;
+ length += m_iei.GetObjectLength();
+ length += m_rawMesg.GetObjectLength();
+ return length;
+}
+
+
+BOOL CISCO_H225_QsigNonStdInfo::Decode(PASN_Stream & strm)
+{
+ if (!PreambleDecode(strm))
+ return FALSE;
+
+ if (!m_iei.Decode(strm))
+ return FALSE;
+ if (!m_rawMesg.Decode(strm))
+ return FALSE;
+
+ return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_QsigNonStdInfo::Encode(PASN_Stream & strm) const
+{
+ PreambleEncode(strm);
+
+ m_iei.Encode(strm);
+ m_rawMesg.Encode(strm);
+
+ UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_QsigNonStdInfo::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(IsClass(CISCO_H225_QsigNonStdInfo::Class()), PInvalidCast);
+#endif
+ return new CISCO_H225_QsigNonStdInfo(*this);
+}
+
+
+//
+// CallMgrParam
+//
+
+CISCO_H225_CallMgrParam::CISCO_H225_CallMgrParam(unsigned tag, PASN_Object::TagClass tagClass)
+ : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
+{
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_CallMgrParam::PrintOn(ostream & strm) const
+{
+ int indent = strm.precision() + 2;
+ strm << "{\n";
+ strm << setw(indent+22) << "interclusterVersion = " << setprecision(indent) << m_interclusterVersion << '\n';
+ strm << setw(indent+15) << "enterpriseID = " << setprecision(indent) << m_enterpriseID << '\n';
+ strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_CallMgrParam::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(PIsDescendant(&obj, CISCO_H225_CallMgrParam), PInvalidCast);
+#endif
+ const CISCO_H225_CallMgrParam & other = (const CISCO_H225_CallMgrParam &)obj;
+
+ Comparison result;
+
+ if ((result = m_interclusterVersion.Compare(other.m_interclusterVersion)) != EqualTo)
+ return result;
+ if ((result = m_enterpriseID.Compare(other.m_enterpriseID)) != EqualTo)
+ return result;
+
+ return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_CallMgrParam::GetDataLength() const
+{
+ PINDEX length = 0;
+ length += m_interclusterVersion.GetObjectLength();
+ length += m_enterpriseID.GetObjectLength();
+ return length;
+}
+
+
+BOOL CISCO_H225_CallMgrParam::Decode(PASN_Stream & strm)
+{
+ if (!PreambleDecode(strm))
+ return FALSE;
+
+ if (!m_interclusterVersion.Decode(strm))
+ return FALSE;
+ if (!m_enterpriseID.Decode(strm))
+ return FALSE;
+
+ return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_CallMgrParam::Encode(PASN_Stream & strm) const
+{
+ PreambleEncode(strm);
+
+ m_interclusterVersion.Encode(strm);
+ m_enterpriseID.Encode(strm);
+
+ UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_CallMgrParam::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(IsClass(CISCO_H225_CallMgrParam::Class()), PInvalidCast);
+#endif
+ return new CISCO_H225_CallMgrParam(*this);
+}
+
+
+//
+// CallPreserveParam
+//
+
+CISCO_H225_CallPreserveParam::CISCO_H225_CallPreserveParam(unsigned tag, PASN_Object::TagClass tagClass)
+ : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
+{
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_CallPreserveParam::PrintOn(ostream & strm) const
+{
+ int indent = strm.precision() + 2;
+ strm << "{\n";
+ strm << setw(indent+17) << "callPreserveIE = " << setprecision(indent) << m_callPreserveIE << '\n';
+ strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_CallPreserveParam::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(PIsDescendant(&obj, CISCO_H225_CallPreserveParam), PInvalidCast);
+#endif
+ const CISCO_H225_CallPreserveParam & other = (const CISCO_H225_CallPreserveParam &)obj;
+
+ Comparison result;
+
+ if ((result = m_callPreserveIE.Compare(other.m_callPreserveIE)) != EqualTo)
+ return result;
+
+ return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_CallPreserveParam::GetDataLength() const
+{
+ PINDEX length = 0;
+ length += m_callPreserveIE.GetObjectLength();
+ return length;
+}
+
+
+BOOL CISCO_H225_CallPreserveParam::Decode(PASN_Stream & strm)
+{
+ if (!PreambleDecode(strm))
+ return FALSE;
+
+ if (!m_callPreserveIE.Decode(strm))
+ return FALSE;
+
+ return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_CallPreserveParam::Encode(PASN_Stream & strm) const
+{
+ PreambleEncode(strm);
+
+ m_callPreserveIE.Encode(strm);
+
+ UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_CallPreserveParam::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(IsClass(CISCO_H225_CallPreserveParam::Class()), PInvalidCast);
+#endif
+ return new CISCO_H225_CallPreserveParam(*this);
+}
+
+
+//
+// CallSignallingParam
+//
+
+CISCO_H225_CallSignallingParam::CISCO_H225_CallSignallingParam(unsigned tag, PASN_Object::TagClass tagClass)
+ : PASN_Sequence(tag, tagClass, 1, TRUE, 0)
+{
+ m_connectedNumber.SetConstraints(PASN_Object::FixedConstraint, 1, 127);
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_CallSignallingParam::PrintOn(ostream & strm) const
+{
+ int indent = strm.precision() + 2;
+ strm << "{\n";
+ if (HasOptionalField(e_connectedNumber))
+ strm << setw(indent+18) << "connectedNumber = " << setprecision(indent) << m_connectedNumber << '\n';
+ strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_CallSignallingParam::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(PIsDescendant(&obj, CISCO_H225_CallSignallingParam), PInvalidCast);
+#endif
+ const CISCO_H225_CallSignallingParam & other = (const CISCO_H225_CallSignallingParam &)obj;
+
+ Comparison result;
+
+ if ((result = m_connectedNumber.Compare(other.m_connectedNumber)) != EqualTo)
+ return result;
+
+ return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_CallSignallingParam::GetDataLength() const
+{
+ PINDEX length = 0;
+ if (HasOptionalField(e_connectedNumber))
+ length += m_connectedNumber.GetObjectLength();
+ return length;
+}
+
+
+BOOL CISCO_H225_CallSignallingParam::Decode(PASN_Stream & strm)
+{
+ if (!PreambleDecode(strm))
+ return FALSE;
+
+ if (HasOptionalField(e_connectedNumber) && !m_connectedNumber.Decode(strm))
+ return FALSE;
+
+ return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_CallSignallingParam::Encode(PASN_Stream & strm) const
+{
+ PreambleEncode(strm);
+
+ if (HasOptionalField(e_connectedNumber))
+ m_connectedNumber.Encode(strm);
+
+ UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_CallSignallingParam::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(IsClass(CISCO_H225_CallSignallingParam::Class()), PInvalidCast);
+#endif
+ return new CISCO_H225_CallSignallingParam(*this);
+}
+
+
+//
+// CommonParam
+//
+
+CISCO_H225_CommonParam::CISCO_H225_CommonParam(unsigned tag, PASN_Object::TagClass tagClass)
+ : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
+{
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_CommonParam::PrintOn(ostream & strm) const
+{
+ int indent = strm.precision() + 2;
+ strm << "{\n";
+ strm << setw(indent+17) << "redirectIEinfo = " << setprecision(indent) << m_redirectIEinfo << '\n';
+ strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_CommonParam::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(PIsDescendant(&obj, CISCO_H225_CommonParam), PInvalidCast);
+#endif
+ const CISCO_H225_CommonParam & other = (const CISCO_H225_CommonParam &)obj;
+
+ Comparison result;
+
+ if ((result = m_redirectIEinfo.Compare(other.m_redirectIEinfo)) != EqualTo)
+ return result;
+
+ return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_CommonParam::GetDataLength() const
+{
+ PINDEX length = 0;
+ length += m_redirectIEinfo.GetObjectLength();
+ return length;
+}
+
+
+BOOL CISCO_H225_CommonParam::Decode(PASN_Stream & strm)
+{
+ if (!PreambleDecode(strm))
+ return FALSE;
+
+ if (!m_redirectIEinfo.Decode(strm))
+ return FALSE;
+
+ return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_CommonParam::Encode(PASN_Stream & strm) const
+{
+ PreambleEncode(strm);
+
+ m_redirectIEinfo.Encode(strm);
+
+ UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_CommonParam::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(IsClass(CISCO_H225_CommonParam::Class()), PInvalidCast);
+#endif
+ return new CISCO_H225_CommonParam(*this);
+}
+
+
+//
+// ProgIndParam
+//
+
+CISCO_H225_ProgIndParam::CISCO_H225_ProgIndParam(unsigned tag, PASN_Object::TagClass tagClass)
+ : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
+{
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_ProgIndParam::PrintOn(ostream & strm) const
+{
+ int indent = strm.precision() + 2;
+ strm << "{\n";
+ strm << setw(indent+16) << "progIndIEinfo = " << setprecision(indent) << m_progIndIEinfo << '\n';
+ strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_ProgIndParam::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(PIsDescendant(&obj, CISCO_H225_ProgIndParam), PInvalidCast);
+#endif
+ const CISCO_H225_ProgIndParam & other = (const CISCO_H225_ProgIndParam &)obj;
+
+ Comparison result;
+
+ if ((result = m_progIndIEinfo.Compare(other.m_progIndIEinfo)) != EqualTo)
+ return result;
+
+ return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_ProgIndParam::GetDataLength() const
+{
+ PINDEX length = 0;
+ length += m_progIndIEinfo.GetObjectLength();
+ return length;
+}
+
+
+BOOL CISCO_H225_ProgIndParam::Decode(PASN_Stream & strm)
+{
+ if (!PreambleDecode(strm))
+ return FALSE;
+
+ if (!m_progIndIEinfo.Decode(strm))
+ return FALSE;
+
+ return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_ProgIndParam::Encode(PASN_Stream & strm) const
+{
+ PreambleEncode(strm);
+
+ m_progIndIEinfo.Encode(strm);
+
+ UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_ProgIndParam::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(IsClass(CISCO_H225_ProgIndParam::Class()), PInvalidCast);
+#endif
+ return new CISCO_H225_ProgIndParam(*this);
+}
+
+
+//
+// ProtoParam
+//
+
+CISCO_H225_ProtoParam::CISCO_H225_ProtoParam(unsigned tag, PASN_Object::TagClass tagClass)
+ : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
+{
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_ProtoParam::PrintOn(ostream & strm) const
+{
+ int indent = strm.precision() + 2;
+ strm << "{\n";
+ strm << setw(indent+17) << "qsigNonStdInfo = " << setprecision(indent) << m_qsigNonStdInfo << '\n';
+ strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_ProtoParam::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(PIsDescendant(&obj, CISCO_H225_ProtoParam), PInvalidCast);
+#endif
+ const CISCO_H225_ProtoParam & other = (const CISCO_H225_ProtoParam &)obj;
+
+ Comparison result;
+
+ if ((result = m_qsigNonStdInfo.Compare(other.m_qsigNonStdInfo)) != EqualTo)
+ return result;
+
+ return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_ProtoParam::GetDataLength() const
+{
+ PINDEX length = 0;
+ length += m_qsigNonStdInfo.GetObjectLength();
+ return length;
+}
+
+
+BOOL CISCO_H225_ProtoParam::Decode(PASN_Stream & strm)
+{
+ if (!PreambleDecode(strm))
+ return FALSE;
+
+ if (!m_qsigNonStdInfo.Decode(strm))
+ return FALSE;
+
+ return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_ProtoParam::Encode(PASN_Stream & strm) const
+{
+ PreambleEncode(strm);
+
+ m_qsigNonStdInfo.Encode(strm);
+
+ UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_ProtoParam::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(IsClass(CISCO_H225_ProtoParam::Class()), PInvalidCast);
+#endif
+ return new CISCO_H225_ProtoParam(*this);
+}
+
+
+//
+// H323_UU_NonStdInfo
+//
+
+CISCO_H225_H323_UU_NonStdInfo::CISCO_H225_H323_UU_NonStdInfo(unsigned tag, PASN_Object::TagClass tagClass)
+ : PASN_Sequence(tag, tagClass, 3, TRUE, 6)
+{
+}
+
+
+#ifndef PASN_NOPRINTON
+void CISCO_H225_H323_UU_NonStdInfo::PrintOn(ostream & strm) const
+{
+ int indent = strm.precision() + 2;
+ strm << "{\n";
+ if (HasOptionalField(e_version))
+ strm << setw(indent+10) << "version = " << setprecision(indent) << m_version << '\n';
+ if (HasOptionalField(e_protoParam))
+ strm << setw(indent+13) << "protoParam = " << setprecision(indent) << m_protoParam << '\n';
+ if (HasOptionalField(e_commonParam))
+ strm << setw(indent+14) << "commonParam = " << setprecision(indent) << m_commonParam << '\n';
+ if (HasOptionalField(e_dummy1))
+ strm << setw(indent+9) << "dummy1 = " << setprecision(indent) << m_dummy1 << '\n';
+ if (HasOptionalField(e_progIndParam))
+ strm << setw(indent+15) << "progIndParam = " << setprecision(indent) << m_progIndParam << '\n';
+ if (HasOptionalField(e_callMgrParam))
+ strm << setw(indent+15) << "callMgrParam = " << setprecision(indent) << m_callMgrParam << '\n';
+ if (HasOptionalField(e_callSignallingParam))
+ strm << setw(indent+22) << "callSignallingParam = " << setprecision(indent) << m_callSignallingParam << '\n';
+ if (HasOptionalField(e_dummy2))
+ strm << setw(indent+9) << "dummy2 = " << setprecision(indent) << m_dummy2 << '\n';
+ if (HasOptionalField(e_callPreserveParam))
+ strm << setw(indent+20) << "callPreserveParam = " << setprecision(indent) << m_callPreserveParam << '\n';
+ strm << setw(indent-1) << setprecision(indent-2) << "}";
+}
+#endif
+
+
+PObject::Comparison CISCO_H225_H323_UU_NonStdInfo::Compare(const PObject & obj) const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(PIsDescendant(&obj, CISCO_H225_H323_UU_NonStdInfo), PInvalidCast);
+#endif
+ const CISCO_H225_H323_UU_NonStdInfo & other = (const CISCO_H225_H323_UU_NonStdInfo &)obj;
+
+ Comparison result;
+
+ if ((result = m_version.Compare(other.m_version)) != EqualTo)
+ return result;
+ if ((result = m_protoParam.Compare(other.m_protoParam)) != EqualTo)
+ return result;
+ if ((result = m_commonParam.Compare(other.m_commonParam)) != EqualTo)
+ return result;
+
+ return PASN_Sequence::Compare(other);
+}
+
+
+PINDEX CISCO_H225_H323_UU_NonStdInfo::GetDataLength() const
+{
+ PINDEX length = 0;
+ if (HasOptionalField(e_version))
+ length += m_version.GetObjectLength();
+ if (HasOptionalField(e_protoParam))
+ length += m_protoParam.GetObjectLength();
+ if (HasOptionalField(e_commonParam))
+ length += m_commonParam.GetObjectLength();
+ return length;
+}
+
+
+BOOL CISCO_H225_H323_UU_NonStdInfo::Decode(PASN_Stream & strm)
+{
+ if (!PreambleDecode(strm))
+ return FALSE;
+
+ if (HasOptionalField(e_version) && !m_version.Decode(strm))
+ return FALSE;
+ if (HasOptionalField(e_protoParam) && !m_protoParam.Decode(strm))
+ return FALSE;
+ if (HasOptionalField(e_commonParam) && !m_commonParam.Decode(strm))
+ return FALSE;
+ if (!KnownExtensionDecode(strm, e_dummy1, m_dummy1))
+ return FALSE;
+ if (!KnownExtensionDecode(strm, e_progIndParam, m_progIndParam))
+ return FALSE;
+ if (!KnownExtensionDecode(strm, e_callMgrParam, m_callMgrParam))
+ return FALSE;
+ if (!KnownExtensionDecode(strm, e_callSignallingParam, m_callSignallingParam))
+ return FALSE;
+ if (!KnownExtensionDecode(strm, e_dummy2, m_dummy2))
+ return FALSE;
+ if (!KnownExtensionDecode(strm, e_callPreserveParam, m_callPreserveParam))
+ return FALSE;
+
+ return UnknownExtensionsDecode(strm);
+}
+
+
+void CISCO_H225_H323_UU_NonStdInfo::Encode(PASN_Stream & strm) const
+{
+ PreambleEncode(strm);
+
+ if (HasOptionalField(e_version))
+ m_version.Encode(strm);
+ if (HasOptionalField(e_protoParam))
+ m_protoParam.Encode(strm);
+ if (HasOptionalField(e_commonParam))
+ m_commonParam.Encode(strm);
+ KnownExtensionEncode(strm, e_dummy1, m_dummy1);
+ KnownExtensionEncode(strm, e_progIndParam, m_progIndParam);
+ KnownExtensionEncode(strm, e_callMgrParam, m_callMgrParam);
+ KnownExtensionEncode(strm, e_callSignallingParam, m_callSignallingParam);
+ KnownExtensionEncode(strm, e_dummy2, m_dummy2);
+ KnownExtensionEncode(strm, e_callPreserveParam, m_callPreserveParam);
+
+ UnknownExtensionsEncode(strm);
+}
+
+
+PObject * CISCO_H225_H323_UU_NonStdInfo::Clone() const
+{
+#ifndef PASN_LEANANDMEAN
+ PAssert(IsClass(CISCO_H225_H323_UU_NonStdInfo::Class()), PInvalidCast);
+#endif
+ return new CISCO_H225_H323_UU_NonStdInfo(*this);
+}
+
+
+#endif // if ! H323_DISABLE_CISCO_H225
+
+
+// End of cisco-h225.cxx
diff --git a/trunk/channels/h323/cisco-h225.h b/trunk/channels/h323/cisco-h225.h
new file mode 100644
index 000000000..7595b4b65
--- /dev/null
+++ b/trunk/channels/h323/cisco-h225.h
@@ -0,0 +1,299 @@
+//
+// cisco-h225.h
+//
+// Code automatically generated by asnparse.
+//
+
+#if ! H323_DISABLE_CISCO_H225
+
+#ifndef __CISCO_H225_H
+#define __CISCO_H225_H
+
+#ifdef P_USE_PRAGMA
+#pragma interface
+#endif
+
+#include <ptclib/asner.h>
+
+//
+// RedirectIEinfo
+//
+
+class CISCO_H225_RedirectIEinfo : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+ PCLASSINFO(CISCO_H225_RedirectIEinfo, PASN_Sequence);
+#endif
+ public:
+ CISCO_H225_RedirectIEinfo(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+ PASN_OctetString m_redirectIE;
+
+ PINDEX GetDataLength() const;
+ BOOL Decode(PASN_Stream & strm);
+ void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+ void PrintOn(ostream & strm) const;
+#endif
+ Comparison Compare(const PObject & obj) const;
+ PObject * Clone() const;
+};
+
+
+//
+// ProgIndIEinfo
+//
+
+class CISCO_H225_ProgIndIEinfo : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+ PCLASSINFO(CISCO_H225_ProgIndIEinfo, PASN_Sequence);
+#endif
+ public:
+ CISCO_H225_ProgIndIEinfo(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+ PASN_OctetString m_progIndIE;
+
+ PINDEX GetDataLength() const;
+ BOOL Decode(PASN_Stream & strm);
+ void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+ void PrintOn(ostream & strm) const;
+#endif
+ Comparison Compare(const PObject & obj) const;
+ PObject * Clone() const;
+};
+
+
+//
+// QsigNonStdInfo
+//
+
+class CISCO_H225_QsigNonStdInfo : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+ PCLASSINFO(CISCO_H225_QsigNonStdInfo, PASN_Sequence);
+#endif
+ public:
+ CISCO_H225_QsigNonStdInfo(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+ PASN_Integer m_iei;
+ PASN_OctetString m_rawMesg;
+
+ PINDEX GetDataLength() const;
+ BOOL Decode(PASN_Stream & strm);
+ void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+ void PrintOn(ostream & strm) const;
+#endif
+ Comparison Compare(const PObject & obj) const;
+ PObject * Clone() const;
+};
+
+
+//
+// CallMgrParam
+//
+
+class CISCO_H225_CallMgrParam : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+ PCLASSINFO(CISCO_H225_CallMgrParam, PASN_Sequence);
+#endif
+ public:
+ CISCO_H225_CallMgrParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+ PASN_Integer m_interclusterVersion;
+ PASN_OctetString m_enterpriseID;
+
+ PINDEX GetDataLength() const;
+ BOOL Decode(PASN_Stream & strm);
+ void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+ void PrintOn(ostream & strm) const;
+#endif
+ Comparison Compare(const PObject & obj) const;
+ PObject * Clone() const;
+};
+
+
+//
+// CallPreserveParam
+//
+
+class CISCO_H225_CallPreserveParam : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+ PCLASSINFO(CISCO_H225_CallPreserveParam, PASN_Sequence);
+#endif
+ public:
+ CISCO_H225_CallPreserveParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+ PASN_Boolean m_callPreserveIE;
+
+ PINDEX GetDataLength() const;
+ BOOL Decode(PASN_Stream & strm);
+ void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+ void PrintOn(ostream & strm) const;
+#endif
+ Comparison Compare(const PObject & obj) const;
+ PObject * Clone() const;
+};
+
+
+//
+// CallSignallingParam
+//
+
+class CISCO_H225_CallSignallingParam : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+ PCLASSINFO(CISCO_H225_CallSignallingParam, PASN_Sequence);
+#endif
+ public:
+ CISCO_H225_CallSignallingParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+ enum OptionalFields {
+ e_connectedNumber
+ };
+
+ PASN_OctetString m_connectedNumber;
+
+ PINDEX GetDataLength() const;
+ BOOL Decode(PASN_Stream & strm);
+ void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+ void PrintOn(ostream & strm) const;
+#endif
+ Comparison Compare(const PObject & obj) const;
+ PObject * Clone() const;
+};
+
+
+//
+// CommonParam
+//
+
+class CISCO_H225_CommonParam : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+ PCLASSINFO(CISCO_H225_CommonParam, PASN_Sequence);
+#endif
+ public:
+ CISCO_H225_CommonParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+ CISCO_H225_RedirectIEinfo m_redirectIEinfo;
+
+ PINDEX GetDataLength() const;
+ BOOL Decode(PASN_Stream & strm);
+ void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+ void PrintOn(ostream & strm) const;
+#endif
+ Comparison Compare(const PObject & obj) const;
+ PObject * Clone() const;
+};
+
+
+//
+// ProgIndParam
+//
+
+class CISCO_H225_ProgIndParam : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+ PCLASSINFO(CISCO_H225_ProgIndParam, PASN_Sequence);
+#endif
+ public:
+ CISCO_H225_ProgIndParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+ CISCO_H225_ProgIndIEinfo m_progIndIEinfo;
+
+ PINDEX GetDataLength() const;
+ BOOL Decode(PASN_Stream & strm);
+ void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+ void PrintOn(ostream & strm) const;
+#endif
+ Comparison Compare(const PObject & obj) const;
+ PObject * Clone() const;
+};
+
+
+//
+// ProtoParam
+//
+
+class CISCO_H225_ProtoParam : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+ PCLASSINFO(CISCO_H225_ProtoParam, PASN_Sequence);
+#endif
+ public:
+ CISCO_H225_ProtoParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+ CISCO_H225_QsigNonStdInfo m_qsigNonStdInfo;
+
+ PINDEX GetDataLength() const;
+ BOOL Decode(PASN_Stream & strm);
+ void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+ void PrintOn(ostream & strm) const;
+#endif
+ Comparison Compare(const PObject & obj) const;
+ PObject * Clone() const;
+};
+
+
+//
+// H323_UU_NonStdInfo
+//
+
+class CISCO_H225_H323_UU_NonStdInfo : public PASN_Sequence
+{
+#ifndef PASN_LEANANDMEAN
+ PCLASSINFO(CISCO_H225_H323_UU_NonStdInfo, PASN_Sequence);
+#endif
+ public:
+ CISCO_H225_H323_UU_NonStdInfo(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
+
+ enum OptionalFields {
+ e_version,
+ e_protoParam,
+ e_commonParam,
+ e_dummy1,
+ e_progIndParam,
+ e_callMgrParam,
+ e_callSignallingParam,
+ e_dummy2,
+ e_callPreserveParam
+ };
+
+ PASN_Integer m_version;
+ CISCO_H225_ProtoParam m_protoParam;
+ CISCO_H225_CommonParam m_commonParam;
+ PASN_OctetString m_dummy1;
+ CISCO_H225_ProgIndParam m_progIndParam;
+ CISCO_H225_CallMgrParam m_callMgrParam;
+ CISCO_H225_CallSignallingParam m_callSignallingParam;
+ PASN_OctetString m_dummy2;
+ CISCO_H225_CallPreserveParam m_callPreserveParam;
+
+ PINDEX GetDataLength() const;
+ BOOL Decode(PASN_Stream & strm);
+ void Encode(PASN_Stream & strm) const;
+#ifndef PASN_NOPRINTON
+ void PrintOn(ostream & strm) const;
+#endif
+ Comparison Compare(const PObject & obj) const;
+ PObject * Clone() const;
+};
+
+
+#endif // __CISCO_H225_H
+
+#endif // if ! H323_DISABLE_CISCO_H225
+
+
+// End of cisco-h225.h
diff --git a/trunk/channels/h323/compat_h323.cxx b/trunk/channels/h323/compat_h323.cxx
new file mode 100644
index 000000000..eec7361b2
--- /dev/null
+++ b/trunk/channels/h323/compat_h323.cxx
@@ -0,0 +1,138 @@
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+/*
+ * ast_h323.cpp
+ *
+ * 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
+ *
+ * This file is part of the chan_h323 driver for Asterisk
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * Version Info: $Id$
+ */
+#include <ptlib.h>
+#include <h323.h>
+#include <transports.h>
+
+#include "ast_h323.h"
+
+#if VERSION(OPENH323_MAJOR,OPENH323_MINOR,OPENH323_BUILD) < VERSION(1,17,3)
+MyH323TransportTCP::MyH323TransportTCP(
+ H323EndPoint & endpoint,
+ PIPSocket::Address binding,
+ BOOL listen)
+ : H323TransportTCP(endpoint, binding, listen)
+{
+}
+
+BOOL MyH323TransportTCP::Connect()
+{
+ if (IsListening())
+ return TRUE;
+
+ PTCPSocket * socket = new PTCPSocket(remotePort);
+ Open(socket);
+
+ channelPointerMutex.StartRead();
+
+ socket->SetReadTimeout(10000/*endpoint.GetSignallingChannelConnectTimeout()*/);
+
+ localPort = endpoint.GetNextTCPPort();
+ WORD firstPort = localPort;
+ for (;;) {
+ PTRACE(4, "H323TCP\tConnecting to "
+ << remoteAddress << ':' << remotePort
+ << " (local port=" << localPort << ')');
+ if (socket->Connect(localAddress, localPort, remoteAddress))
+ break;
+
+ int errnum = socket->GetErrorNumber();
+ if (localPort == 0 || (errnum != EADDRINUSE && errnum != EADDRNOTAVAIL)) {
+ PTRACE(1, "H323TCP\tCould not connect to "
+ << remoteAddress << ':' << remotePort
+ << " (local port=" << localPort << ") - "
+ << socket->GetErrorText() << '(' << errnum << ')');
+ channelPointerMutex.EndRead();
+ return SetErrorValues(socket->GetErrorCode(), errnum);
+ }
+
+ localPort = endpoint.GetNextTCPPort();
+ if (localPort == firstPort) {
+ PTRACE(1, "H323TCP\tCould not bind to any port in range " <<
+ endpoint.GetTCPPortBase() << " to " << endpoint.GetTCPPortMax());
+ channelPointerMutex.EndRead();
+ return SetErrorValues(socket->GetErrorCode(), errnum);
+ }
+ }
+
+ socket->SetReadTimeout(PMaxTimeInterval);
+
+ channelPointerMutex.EndRead();
+
+ return OnOpen();
+}
+#endif
+
+BOOL MyH323TransportUDP::DiscoverGatekeeper(H323Gatekeeper &gk, H323RasPDU &pdu, const H323TransportAddress &address)
+{
+ PThread *thd = PThread::Current();
+
+ /* If we run in OpenH323's thread use it instead of creating new one */
+ if (thd)
+ return H323TransportUDP::DiscoverGatekeeper(gk, pdu, address);
+
+ /* Make copy of arguments to pass them into thread */
+ discoverGatekeeper = &gk;
+ discoverPDU = &pdu;
+ discoverAddress = &address;
+
+ /* Assume discovery thread isn't finished */
+ discoverReady = FALSE;
+
+ /* Create discovery thread */
+ thd = PThread::Create(PCREATE_NOTIFIER(DiscoverMain), 0,
+ PThread::NoAutoDeleteThread,
+ PThread::NormalPriority,
+ "GkDiscovery:%x");
+
+ /* Wait until discovery thread signal us its finished */
+ for(;;) {
+ discoverMutex.Wait();
+ if (discoverReady) /* Thread has been finished */
+ break;
+ discoverMutex.Signal();
+ }
+ discoverMutex.Signal();
+
+ /* Cleanup/delete thread */
+ thd->WaitForTermination();
+ delete thd;
+
+ return discoverResult;
+}
+
+void MyH323TransportUDP::DiscoverMain(PThread &thread, INT arg)
+{
+ PWaitAndSignal m(discoverMutex);
+
+ discoverResult = H323TransportUDP::DiscoverGatekeeper(*discoverGatekeeper, *discoverPDU, *discoverAddress);
+ discoverReady = TRUE;
+}
diff --git a/trunk/channels/h323/compat_h323.h b/trunk/channels/h323/compat_h323.h
new file mode 100644
index 000000000..5437898f4
--- /dev/null
+++ b/trunk/channels/h323/compat_h323.h
@@ -0,0 +1,94 @@
+#ifndef COMPAT_H323_H
+#define COMPAT_H323_H
+
+#if VERSION(OPENH323_MAJOR,OPENH323_MINOR,OPENH323_BUILD) < VERSION(1,17,3)
+/**
+ * Workaround for broken (less than 1.17.3) OpenH323 stack to be able to
+ * make TCP connections from specific address
+ */
+class MyH323TransportTCP : public H323TransportTCP
+{
+ PCLASSINFO(MyH323TransportTCP, H323TransportTCP);
+
+public:
+ MyH323TransportTCP(
+ H323EndPoint & endpoint, ///< H323 End Point object
+ PIPSocket::Address binding = PIPSocket::GetDefaultIpAny(), ///< Local interface to use
+ BOOL listen = FALSE ///< Flag for need to wait for remote to connect
+ );
+ /**Connect to the remote party.
+ */
+ virtual BOOL Connect();
+};
+#else
+#define MyH323TransportTCP H323TransportTCP
+#endif /* <VERSION(1,17,3) */
+
+class MyH323TransportUDP: public H323TransportUDP
+{
+ PCLASSINFO(MyH323TransportUDP, H323TransportUDP);
+
+public:
+ MyH323TransportUDP(H323EndPoint &endpoint,
+ PIPSocket::Address binding = PIPSocket::GetDefaultIpAny(),
+ WORD localPort = 0,
+ WORD remotePort = 0): H323TransportUDP(endpoint, binding, localPort, remotePort)
+ {
+ }
+ virtual BOOL DiscoverGatekeeper(H323Gatekeeper &,
+ H323RasPDU &,
+ const H323TransportAddress &);
+protected:
+ PDECLARE_NOTIFIER(PThread, MyH323TransportUDP, DiscoverMain);
+ H323Gatekeeper *discoverGatekeeper;
+ H323RasPDU *discoverPDU;
+ const H323TransportAddress *discoverAddress;
+ BOOL discoverResult;
+ BOOL discoverReady;
+ PMutex discoverMutex;
+};
+
+template <class _Abstract_T, typename _Key_T = PString>
+class MyPFactory: public PFactory<_Abstract_T, _Key_T>
+{
+public:
+ template <class _Concrete_T> class Worker: public PFactory<_Abstract_T, _Key_T>::WorkerBase
+ {
+ public:
+ Worker(const _Key_T &_key, bool singleton = false)
+ :PFactory<_Abstract_T, _Key_T>::WorkerBase(singleton), key(_key)
+ {
+ PFactory<_Abstract_T, _Key_T>::Register(key, this);
+ }
+ ~Worker()
+ {
+ PFactory<_Abstract_T, _Key_T>::Unregister(key);
+ }
+ protected:
+ virtual _Abstract_T *Create(const _Key_T &) const { return new _Concrete_T; }
+
+ private:
+ PString key;
+ };
+};
+
+#ifdef H323_REGISTER_CAPABILITY
+#undef H323_REGISTER_CAPABILITY
+#endif
+#define H323_REGISTER_CAPABILITY(cls, capName) static MyPFactory<H323Capability>::Worker<cls> cls##Factory(capName, true)
+
+#ifdef OPAL_MEDIA_FORMAT_DECLARE
+#undef OPAL_MEDIA_FORMAT_DECLARE
+#endif
+
+#define OPAL_MEDIA_FORMAT_DECLARE(classname, _fullName, _defaultSessionID, _rtpPayloadType, _needsJitter,_bandwidth, _frameSize, _frameTime, _timeUnits, _timeStamp) \
+class classname : public OpalMediaFormat \
+{ \
+ public: \
+ classname() \
+ : OpalMediaFormat(_fullName, _defaultSessionID, _rtpPayloadType, _needsJitter, _bandwidth, \
+ _frameSize, _frameTime, _timeUnits, _timeStamp){} \
+}; \
+static MyPFactory<OpalMediaFormat>::Worker<classname> classname##Factory(_fullName, true)
+
+#endif /* !defined AST_H323_H */
diff --git a/trunk/channels/h323/noexport.map b/trunk/channels/h323/noexport.map
new file mode 100644
index 000000000..b51f84263
--- /dev/null
+++ b/trunk/channels/h323/noexport.map
@@ -0,0 +1,5 @@
+{
+ global:
+ _Z11PAssertFuncPKc;
+ local: *;
+}; \ No newline at end of file