504 lines
13 KiB
C++
504 lines
13 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// PBX4Linux //
|
|
// //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright: Andreas Eversberg //
|
|
// //
|
|
// h323_ep class //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
/*
|
|
NOTE:
|
|
|
|
The code was inspired by the isdn2h323 gateway my marco bode.
|
|
Thanx to marco budde for lerarning to program h323 and c++ from your code.
|
|
His homepage is www.telos.de, there you'll find the isdn2h323 gateway.
|
|
|
|
Also thanx to others who write documents and applications for OpenH323.
|
|
|
|
Andreas Eversberg
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include "main.h"
|
|
|
|
//#include <gsmcodec.h>
|
|
//#include <g7231codec.h>
|
|
//#include <g729codec.h>
|
|
//#include "g726codec.h"
|
|
//#include <speexcodec.h>
|
|
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
//
|
|
// constructor
|
|
//
|
|
H323_ep::H323_ep(void)
|
|
{
|
|
terminalType = e_GatewayOnly;
|
|
|
|
PDEBUG(DEBUG_H323, "H323 endpoint constuctor\n");
|
|
}
|
|
|
|
//
|
|
// destructor
|
|
//
|
|
H323_ep::~H323_ep()
|
|
{
|
|
// clear all calls to remote endpoints
|
|
ClearAllCalls();
|
|
|
|
PDEBUG(DEBUG_H323, "H323 endpoint destuctor\n");
|
|
}
|
|
|
|
|
|
//
|
|
// create connection
|
|
//
|
|
H323Connection *H323_ep::CreateConnection(unsigned callReference)
|
|
{
|
|
PDEBUG(DEBUG_H323, "H323 endpoint create connection\n");
|
|
|
|
return new H323_con(*this, callReference);
|
|
}
|
|
|
|
|
|
//
|
|
// on establishment of conneciton
|
|
//
|
|
void H323_ep::OnConnectionEstablished(H323Connection &connection, const PString &token)
|
|
{
|
|
const unsigned char *token_string = token;
|
|
|
|
PDEBUG(DEBUG_H323, "H323 endpoint connection established to: %s\n", token_string);
|
|
|
|
H323EndPoint::OnConnectionEstablished(connection, token);
|
|
}
|
|
|
|
//
|
|
// on remote alerting
|
|
//
|
|
BOOL H323_ep::OnAlerting(H323Connection &connection, const H323SignalPDU &alertingPDU, const PString &user)
|
|
{
|
|
class H323Port *port;
|
|
const unsigned char *token_string = connection.GetCallToken();
|
|
const unsigned char *user_string = user;
|
|
struct message *message;
|
|
|
|
PDEBUG(DEBUG_H323, "H323 endpoint alerting at: %s\n", user_string);
|
|
|
|
mutex_h323.Wait();
|
|
|
|
if (!(port=(class H323Port *)find_port_with_token((char *)token_string)))
|
|
{
|
|
PERROR("cannot find port with token '%s'\n", token_string);
|
|
mutex_h323.Signal();
|
|
return FALSE;
|
|
}
|
|
if (port->p_state==PORT_STATE_OUT_SETUP
|
|
|| port->p_state==PORT_STATE_OUT_OVERLAP
|
|
|| port->p_state==PORT_STATE_OUT_PROCEEDING)
|
|
{
|
|
port->new_state(PORT_STATE_OUT_ALERTING);
|
|
message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
|
|
message_put(message);
|
|
}
|
|
|
|
mutex_h323.Signal();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// on clearing of connection
|
|
//
|
|
void H323_ep::OnConnectionCleared(H323Connection &connection, const PString &token)
|
|
{
|
|
int cause;
|
|
class H323Port *port;
|
|
const unsigned char *token_string = token;
|
|
struct message *message;
|
|
|
|
PDEBUG(DEBUG_H323, "H323 endpoint connection cleared.\n");
|
|
|
|
mutex_h323.Wait();
|
|
|
|
if (!(port=(class H323Port *)find_port_with_token((char *)token_string)))
|
|
{
|
|
PERROR("cannot find port with token '%s'\n", token_string);
|
|
mutex_h323.Signal();
|
|
return;
|
|
}
|
|
|
|
switch(connection.GetCallEndReason())
|
|
{
|
|
case H323Connection::EndedByRemoteUser:
|
|
case H323Connection::EndedByCallerAbort:
|
|
case H323Connection::EndedByGatekeeper:
|
|
case H323Connection::EndedByCallForwarded:
|
|
cause = 16; // normal call clearing
|
|
break;
|
|
|
|
case H323Connection::EndedByRefusal:
|
|
case H323Connection::EndedBySecurityDenial:
|
|
cause = 21; // call rejected
|
|
break;
|
|
|
|
case H323Connection::EndedByNoAnswer:
|
|
cause = 19; // no answer from user
|
|
break;
|
|
|
|
case H323Connection::EndedByTransportFail:
|
|
cause = 47; // resource unavaiable, unspecified
|
|
break;
|
|
|
|
case H323Connection::EndedByNoBandwidth:
|
|
cause = 49; // quality of service not available
|
|
break;
|
|
|
|
case H323Connection::EndedByNoUser:
|
|
cause = 1; // unallocated number
|
|
break;
|
|
|
|
case H323Connection::EndedByCapabilityExchange:
|
|
cause = 65; // bearer capability not implemented
|
|
break;
|
|
|
|
case H323Connection::EndedByRemoteBusy:
|
|
cause = 17; // user busy
|
|
break;
|
|
|
|
case H323Connection::EndedByRemoteCongestion:
|
|
cause = 42; // switching equipment congestion
|
|
break;
|
|
|
|
case H323Connection::EndedByUnreachable:
|
|
cause = 2; // no route ...
|
|
break;
|
|
|
|
case H323Connection::EndedByNoEndPoint:
|
|
case H323Connection::EndedByConnectFail:
|
|
cause = 18; // no user responding
|
|
break;
|
|
|
|
case H323Connection::EndedByHostOffline:
|
|
cause = 27; // destination out of order
|
|
break;
|
|
|
|
case H323Connection::EndedByTemporaryFailure:
|
|
cause = 41; // temporary failure
|
|
break;
|
|
|
|
default:
|
|
cause = 31; // normal, unspecified
|
|
break;
|
|
|
|
}
|
|
|
|
// delete channels
|
|
if (port->p_h323_channel_in)
|
|
delete port->p_h323_channel_in;
|
|
port->p_h323_channel_in = NULL;
|
|
if (port->p_h323_channel_out)
|
|
delete port->p_h323_channel_out;
|
|
port->p_h323_channel_out = NULL;
|
|
|
|
/* release endpoint */
|
|
message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
|
|
message->param.disconnectinfo.cause = cause;
|
|
message->param.disconnectinfo.location = LOCATION_BEYOND;
|
|
message_put(message);
|
|
|
|
/* delete port */
|
|
delete port;
|
|
|
|
mutex_h323.Signal();
|
|
}
|
|
|
|
|
|
//
|
|
// open audio channel
|
|
//
|
|
BOOL H323_ep::OpenAudioChannel(H323Connection &connection, BOOL isEncoding, unsigned bufferSize, H323AudioCodec &codec)
|
|
{
|
|
H323_chan *channel;
|
|
class H323Port *port;
|
|
const unsigned char *token_string = connection.GetCallToken();
|
|
|
|
PDEBUG(DEBUG_H323, "H323 endpoint audio channel open (isEndcoding=%d).\n", isEncoding);
|
|
|
|
// disable the silence detection
|
|
codec.SetSilenceDetectionMode (H323AudioCodec::NoSilenceDetection);
|
|
|
|
// create channels
|
|
if (isEncoding)
|
|
{
|
|
channel = new H323_chan(connection.GetCallToken(), TRUE);
|
|
} else
|
|
{
|
|
channel = new H323_chan(connection.GetCallToken(), FALSE);
|
|
}
|
|
if (!channel)
|
|
{
|
|
PERROR("channel for token '%s' not set", token_string);
|
|
return FALSE;
|
|
}
|
|
|
|
// return the channel object
|
|
mutex_h323.Wait();
|
|
if (!(port=(class H323Port *)find_port_with_token((char *)token_string)))
|
|
{
|
|
PERROR("cannot find port with token '%s'\n", token_string);
|
|
mutex_h323.Signal();
|
|
return FALSE;
|
|
}
|
|
|
|
// set channels
|
|
if (isEncoding)
|
|
{
|
|
port->p_h323_channel_out = channel;
|
|
} else
|
|
{
|
|
port->p_h323_channel_in = channel;
|
|
}
|
|
|
|
mutex_h323.Signal();
|
|
return codec.AttachChannel(channel, FALSE);
|
|
}
|
|
|
|
|
|
//
|
|
// open video channel
|
|
//
|
|
BOOL H323_ep::OpenVideoChannel(H323Connection &connection, BOOL isEncoding, H323VideoCodec &codec)
|
|
{
|
|
PDEBUG(DEBUG_H323, "H323 endpoint video channel open (isEndcoding=%d).\n", isEncoding);
|
|
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// initialize H323 endpoint
|
|
//
|
|
BOOL H323_ep::Init(void)
|
|
{
|
|
H323ListenerTCP *listener;
|
|
int pri;
|
|
|
|
PDEBUG(DEBUG_H323, "H323 endpoint initialize\n");
|
|
|
|
// add keypad capability
|
|
H323_UserInputCapability::AddAllCapabilities(capabilities, 0, P_MAX_INDEX);
|
|
|
|
/* will add codec in order of priority 1 = highest, 0 = don't use */
|
|
pri = 1;
|
|
while (pri < 256)
|
|
{
|
|
#warning codecs are temporarily disabled due to api change
|
|
#if 0
|
|
if (options.h323_gsm_pri == pri)
|
|
{
|
|
H323_GSM0610Capability * gsm_cap;
|
|
MicrosoftGSMAudioCapability * msgsm_cap;
|
|
|
|
SetCapability(0, 0, gsm_cap = new H323_GSM0610Capability);
|
|
gsm_cap->SetTxFramesInPacket(options.h323_gsm_opt);
|
|
SetCapability(0, 0, msgsm_cap = new MicrosoftGSMAudioCapability);
|
|
msgsm_cap->SetTxFramesInPacket(options.h323_gsm_opt);
|
|
}
|
|
if (options.h323_g726_pri == pri)
|
|
{
|
|
if (options.h323_g726_opt > 4)
|
|
SetCapability(0, 0, new H323_G726_Capability(*this, H323_G726_Capability::e_40k));
|
|
if (options.h323_g726_opt > 3)
|
|
SetCapability(0, 0, new H323_G726_Capability(*this, H323_G726_Capability::e_32k));
|
|
if (options.h323_g726_opt > 2)
|
|
SetCapability(0, 0, new H323_G726_Capability(*this, H323_G726_Capability::e_24k));
|
|
SetCapability(0, 0, new H323_G726_Capability(*this, H323_G726_Capability::e_16k));
|
|
}
|
|
if (options.h323_g7231_pri == pri)
|
|
{
|
|
#if 0
|
|
SetCapability(0, 0, new H323_G7231Capability(FALSE));
|
|
#endif
|
|
}
|
|
if (options.h323_g729a_pri == pri)
|
|
{
|
|
#if 0
|
|
SetCapability(0, 0, new H323_G729Capability());
|
|
#endif
|
|
}
|
|
if (options.h323_lpc10_pri == pri)
|
|
{
|
|
SetCapability(0, 0, new H323_LPC10Capability(*this));
|
|
}
|
|
if (options.h323_speex_pri == pri)
|
|
{
|
|
if (options.h323_speex_opt > 5)
|
|
SetCapability(0, 0, new SpeexNarrow6AudioCapability());
|
|
if (options.h323_speex_opt > 4)
|
|
SetCapability(0, 0, new SpeexNarrow5AudioCapability());
|
|
if (options.h323_speex_opt > 3)
|
|
SetCapability(0, 0, new SpeexNarrow4AudioCapability());
|
|
if (options.h323_speex_opt > 2)
|
|
SetCapability(0, 0, new SpeexNarrow3AudioCapability());
|
|
SetCapability(0, 0, new SpeexNarrow2AudioCapability());
|
|
}
|
|
if (options.h323_xspeex_pri == pri)
|
|
{
|
|
if (options.h323_xspeex_opt > 5)
|
|
SetCapability(0, 0, new XiphSpeexNarrow6AudioCapability());
|
|
if (options.h323_xspeex_opt > 4)
|
|
SetCapability(0, 0, new XiphSpeexNarrow5AudioCapability());
|
|
if (options.h323_xspeex_opt > 3)
|
|
SetCapability(0, 0, new XiphSpeexNarrow4AudioCapability());
|
|
if (options.h323_xspeex_opt > 2)
|
|
SetCapability(0, 0, new XiphSpeexNarrow3AudioCapability());
|
|
SetCapability(0, 0, new XiphSpeexNarrow2AudioCapability());
|
|
}
|
|
#endif
|
|
if (options.h323_law_pri == pri)
|
|
{
|
|
H323_G711Capability * g711uCap;
|
|
H323_G711Capability * g711aCap;
|
|
SetCapability(0, 0, g711uCap = new H323_G711Capability (H323_G711Capability::ALaw/*, H323_G711Capability::At64k*/));
|
|
#warning H323_law frame size is disabled due to bug in OpenH323
|
|
// g711uCap->SetTxFramesInPacket(options.h323_law_opt);
|
|
SetCapability(0, 0, g711aCap = new H323_G711Capability (H323_G711Capability::muLaw/*, H323_G711Capability::At64k*/));
|
|
// g711aCap->SetTxFramesInPacket(options.h323_law_opt);
|
|
}
|
|
pri++;
|
|
}
|
|
|
|
// h323 user is the hostname or given by h323_name
|
|
if (options.h323_name[0] == '\0')
|
|
{
|
|
if (getenv("HOSTNAME") == NULL)
|
|
{
|
|
cout << "OpenH323: Environment variable HOSTNAME not set. Please specify 'h323_name' in options.conf" << endl;
|
|
return FALSE;
|
|
}
|
|
}
|
|
SetLocalUserName((options.h323_name[0])?options.h323_name:getenv("HOSTNAME"));
|
|
|
|
// create listener
|
|
if (options.h323_icall)
|
|
{
|
|
PIPSocket::Address interfaceAddress(INADDR_ANY);
|
|
listener = new H323ListenerTCP(*this, interfaceAddress, options.h323_port);
|
|
if (!StartListener(listener))
|
|
{
|
|
cout << "OpenH323: Could not open H323 port " << listener->GetListenerPort() << endl;
|
|
return FALSE;
|
|
}
|
|
cout << "OpenH323: Waiting for incoming H323 connections on port " << listener->GetListenerPort() << endl;
|
|
}
|
|
|
|
// register with gatekeeper
|
|
if (options.h323_gatekeeper)
|
|
{
|
|
if (options.h323_gatekeeper_host[0] == '\0')
|
|
{
|
|
if (DiscoverGatekeeper(new H323TransportUDP(*this)))
|
|
{
|
|
cout << "OpenH323: Registering with gatekeeper " << gatekeeper->GetIdentifier() << " (automatically)" << endl;
|
|
} else
|
|
{
|
|
cout << "OpenH323: Gatekeeper not found." << endl;
|
|
sleep(2);
|
|
}
|
|
} else
|
|
{
|
|
if (SetGatekeeper(options.h323_gatekeeper_host) == TRUE)
|
|
{
|
|
cout << "OpenH323: Registering with gatekeeper " << gatekeeper->GetIdentifier() << " (automatically)" << endl;
|
|
} else
|
|
{
|
|
cout << "OpenH323: Gatekeeper at " << gatekeeper->GetIdentifier() << " not found." << endl;
|
|
sleep(2);
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// make an outgoing h323 call
|
|
//
|
|
|
|
BOOL H323_ep::Call(char *token_string, char *caller, char *host)
|
|
{
|
|
PString address;
|
|
PString token = "";
|
|
BOOL failed = FALSE;
|
|
class H323Port *port;
|
|
struct message *message;
|
|
char *newtoken_string;
|
|
|
|
PDEBUG(DEBUG_H323, "H323 endpoint call to host '%s'\n", host);
|
|
|
|
address = host;
|
|
|
|
if (!MakeCall(address, token))
|
|
{
|
|
PDEBUG(DEBUG_H323, "H323 endpoint call to host '%s'\n", host);
|
|
failed = TRUE;
|
|
}
|
|
|
|
// set new token
|
|
mutex_h323.Wait();
|
|
if (!(port=(class H323Port *)find_port_with_token((char *)token_string)))
|
|
{
|
|
PERROR("cannot find port with token '%s'\n", token_string);
|
|
mutex_h323.Signal();
|
|
return FALSE;
|
|
}
|
|
if (failed == TRUE)
|
|
{
|
|
PDEBUG(DEBUG_H323, "call of port '%s' failed.\n", token_string);
|
|
message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
|
|
message->param.disconnectinfo.cause = 31;
|
|
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
|
|
message_put(message);
|
|
} else
|
|
{
|
|
PDEBUG(DEBUG_H323, "changing port name from '%s' to token '%s'\n", token_string, token.GetPointer());
|
|
newtoken_string = token.GetPointer();
|
|
SCPY(port->p_name, newtoken_string);
|
|
}
|
|
mutex_h323.Signal();
|
|
PDEBUG(DEBUG_H323, "H323 endpoint call to host '%s'\n", host);
|
|
|
|
if (failed == TRUE)
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
void H323_ep::SetEndpointTypeInfo(H225_EndpointType &info) const
|
|
{
|
|
// H225_VoiceCaps voicecaps;
|
|
PDEBUG(DEBUG_H323, "H323 endpoint set endpoint type info *TBD*\n");
|
|
|
|
H323EndPoint::SetEndpointTypeInfo(info);
|
|
|
|
// protocols.SetTag(H225_SupportedProtocols::e_voice);
|
|
// (H225_VoiceCaps&)protocols = voicecaps;
|
|
// a_protocols.SetSize(1);
|
|
// a_protocols[0] = protocols;
|
|
|
|
// gateway.IncludeOptionalField(H225_GatewayInfo::e_protocol);
|
|
// gateway.m_protocol = a_protocols;
|
|
// info.m_gateway = gateway;
|
|
}
|