/*
*
* versuch project
* Signalling channel Q931/H225
* CallPool object
* $Id: CallThread.cxx,v 1.10 2006/08/24 06:44:48 warlock_kg Exp $
* warlock copyright since 2005 Nov
*
*/
#include "CallThread.h"
#include <ptlib.h>
#include <ptlib/svcproc.h>
#include <q931.h>
#include <h245.h>
#include <sstream>
#include <signal.h>
#include <assert.h>
#include "AddrUtils.h"
#include "global.h"
static const char H225_ProtocolID[] = "0.0.8.2250.0.2";
static CallThread * mCallThread;
static unsigned AcctSessionId = 0;
const char WeekDay[7][4] = {"Sun", "Mon", "Tue", "Web", "Thu", "Fri", "Sat"};
const char Month[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
string GetAcctSessionId() {
stringstream sstr;
AcctSessionId++;
sstr << setw(8) << setbase(10) << setfill('0') << AcctSessionId;
return sstr.str();
}
void EmergencyExit(int sig_num)
{
const CallThread * cthread = mCallThread;
cthread -> ClTbl -> KillAllCalls();
cerr << "Signal has got. sig_num=" << sig_num << endl;
_Exit(1);
}
void * control_thread_function( void *ptr )
{
struct T_control_thread_data * thread_data;
WTRACE(1, "ControlThread\tEntering to control_thread_function. ptr= " << ptr);
thread_data = (struct T_control_thread_data *) ptr;
thread_data -> ch -> Main();
WTRACE(1, "ControlThread\tExiting from control_thread_function");
pthread_exit(0);
}
void * signalling_thread_function( void *ptr )
{
struct T_signalling_thread_data * thread_data;
WTRACE(2, "SignallingThread\tEntering to signalling_thread_function. ptr= " << ptr);
thread_data = (struct T_signalling_thread_data *) ptr;
thread_data -> ch -> Main();
WTRACE(2, "SignallingThread\tExiting from signalling_thread_function");
delete thread_data -> ch;
pthread_exit(0);
}
void LogRotateFunction (pthread_mutex_t * mtx, char logfile[50], char umask[6], unsigned int timespan)
{
struct timeval timeout;
time_t clock;
unsigned int tt, prewait;
while ( true )
{
// prewaitnig
prewait = timespan * 60 / 10;
timeout.tv_usec = 0;
timeout.tv_sec = prewait;
select(0, NULL, NULL, NULL, &timeout);
// reset start
clock = time(NULL);
tt = clock % ( timespan * 60 );
tt = ( timespan * 60 ) - tt ;
// waiting
timeout.tv_usec = 0;
timeout.tv_sec = tt;
select(0, NULL, NULL, NULL, &timeout);
// rotation
pthread_mutex_lock(mtx);
struct tm tmclock;
vector<string> tokens;
string NewName, DateSuffix, Str0;
ostringstream sstr;
clock = time(NULL);
clock = clock - ( timespan * 60 );
localtime_r(&clock, &tmclock);
Tokenize( logfile, tokens, ".");
sstr << tokens[0] << tmclock.tm_year+1900 << setfill('0') << setw(2) << tmclock.tm_mon+1
<< setw(2) << tmclock.tm_mday << "_"
<< setw(2) << tmclock.tm_hour << setw(2) << tmclock.tm_min << "00";
if (tokens.size() == 2 )
sstr << "." << tokens[1] ;
WTRACE(1, "Start log rotation into file : " << sstr.str() );
if ( access(sstr.str().c_str(), F_OK) == 0 )
{
WTRACE(0, "File " << sstr << " already exists. Rotation was canselled" );
pthread_mutex_unlock(mtx);
return;
}
if (rename(logfile, sstr.str().c_str()) == -1 )
{
cerr << endl << "Error in Log Rotating. errno = " << errno << ". text is " << strerror(errno) << endl;
}
// int fh = open(logfile, O_CREAT, S_IRUSR | S_IWUSR );
mode_t permission = strtoll( umask, NULL, 8);
int fh = open(logfile, O_CREAT, permission );
close(fh);
WTRACE(1, "ROTATE LOG FILE at " << time(NULL) );
pthread_mutex_unlock(mtx);
} // while
}
void * LogRotateThreadFunction( void *ptr )
{
struct newlog_thread_data * tdata;
tdata = (struct newlog_thread_data *) ptr;
LogRotateFunction(tdata -> mtx, tdata -> log_file, tdata -> log_file_umask, tdata -> time_span);
free(tdata);
pthread_exit(0);
}
CallThread::CallThread(TGlobal & vEnv)
: env(vEnv)
{
struct timezone tmpTZ;
gettimeofday(&ssStartTime, &tmpTZ);
Running=true;
counters.attempts=0;
counters.calls=0;
counters.wm=0;
if ( !CallSocket.Listen( env.ListenAddr, 1720, true ) ) {
cerr << "Listen failed on call signalling socket : " << env.ListenAddr << endl;
exit (1);
}
WTRACE(2, "CallThread started. Listen started on " << env.ListenAddr);
// Starting ControlThread
pthread_t ControlThreadID;
Control = new ControlThread(this, env.StatusPort);
Control -> control_tdata -> ch = Control;
WTRACE(1, "ControlThread\tStarting Control thread");
if ( pthread_create( &ControlThreadID, NULL, control_thread_function, (void *) Control -> control_tdata ) != 0 )
{
cerr << endl << "Error in Control thread creating. errno = " << errno << ". text is " << strerror(errno) << endl;
return;
}
if ( (pthread_detach(ControlThreadID)) != 0) // there are several reasons
WTRACE(1, "Control pthread_detach error" << ControlThreadID);
WTRACE(1, "Control\tThread started");
ClTbl = new CallTable();
mCallThread = this;
signal(SIGINT, EmergencyExit);
signal(SIGABRT, EmergencyExit);
call_tdata = ( struct T_call_thread_data *) malloc (sizeof (struct T_call_thread_data));
if ( env.AcctType == "both" || env.AcctType == "log" )
{
pthread_t RotThreadID;
rl_tdata = ( struct newlog_thread_data *) malloc (sizeof (struct newlog_thread_data));
rl_tdata -> time_span = env.LogRotateSpan;
rl_tdata -> mtx = & env.global_mtx;
strncpy( rl_tdata -> log_file, env.LogFile.c_str(), 49);
strncpy( rl_tdata -> log_file_umask, env.LogUmask.c_str(), 4);
if (pthread_create( &RotThreadID, NULL, LogRotateThreadFunction, (void *) rl_tdata ) != 0 )
{
cerr << endl << "Error in LogRotate thread creating. errno = " << errno << ". text is " << strerror(errno) << endl;
return;
}
if ( (pthread_detach(RotThreadID)) != 0)
{
WTRACE(1, "LogRotate pthread_detach error " << RotThreadID << ", errno= " << errno << ". Text = " << strerror(errno));
}
} // if LogRotate thread
}
H225_TransportAddress CallThread::GetCallSignallingAddr()
{
WSocket::Address Addr;
unsigned Port;
CallSocket.GetLocalAddress( Addr, Port );
WTRACE(3,"GetCallSignallingAddr() : " << Addr);
return AddrUtils::ConvertToH225TransportAddr( Addr, Port );
}
CallThread::~CallThread()
{
delete [] Control;
delete [] ClTbl;
if ( call_tdata != NULL )
{
free(call_tdata);
}
if ( rl_tdata != NULL )
{
free(rl_tdata);
}
}
void CallThread::Main()
{
ThreadID = pthread_self();
pthread_t sThreadID;
pthread_attr_t attr;
size_t stacksize, init_stack;
pthread_attr_init(&attr);
pthread_attr_getguardsize (&attr, &stacksize);
WTRACE(1, "Default guard size = " << stacksize);
pthread_attr_getstacksize (&attr, &init_stack);
// stacksize = init_stack * 4;
stacksize = init_stack ;
pthread_attr_setstacksize (&attr, stacksize);
WTRACE(1, "Default stack size = " << init_stack << ", New stack size = " << stacksize );
// H323 loop
CallSocket.SetReadTimeout(0);
while ( CallSocket.IsOpen() )
{
WTCPSocket * CallChannel = new WTCPSocket;
if ( CallChannel->Accept( CallSocket ) )
{
CallChannel->SetReadTimeout(60);
counters.attempts++;
WTRACE( 3, "New incoming connection to call signaling port" );
SignallingThread * SigThread = new SignallingThread( this, env, CallChannel );
ClTbl->AddCall(SigThread);
if (ClTbl->CallNumber() > counters.wm) {
counters.wm = ClTbl->CallNumber();
}
SigThread -> signalling_tdata -> ch = SigThread;
if (pthread_create( &sThreadID, &attr, signalling_thread_function, (void *) SigThread -> signalling_tdata ) != 0 )
{
cerr << endl << "Error in Signall thread creating. errno = " << errno << ". text is " << strerror(errno) << endl;
return;
}
if ( (pthread_detach(sThreadID)) != 0) // there are several reasons
WTRACE(1, "Signalling pthread_detach error " << sThreadID << ", errno= " << errno << ". Text = " << strerror(errno));
WTRACE(1, "CallThread\tSigThread started");
}
else
{
WTRACE( 1, "Error in accepting call errno = " << errno << " : " << strerror(errno) );
delete CallChannel;
}
}
pthread_attr_destroy(&attr);
}
void CallThread::Close()
{
Running = false;
CallSocket.Close();
}
void CallThread::WaitForTermination()
{
struct timeval timeout;
while (Running) {
timeout.tv_sec = 10;
timeout.tv_usec = 0;
pthread_yield();
select(0, NULL, NULL, NULL, &timeout);
WTRACE(6, "CallThread::WaitForTermination()");
}
}
static int ReadMsg( WTCPSocket * Socket, Q931 & Mesg )
{
int tpkt;
bool decoded;
// Make sure it is a RFC1006 TPKT
tpkt = Socket->ReadChar();
if ( tpkt != 3 )
{
if ( Socket->GetLastReadCount() == 0 ) {
Socket->Close();
return -4;
}
WTRACE(1,"Invalid call signalling message, not a TKPT :" << tpkt << ", LastReadCount = " << Socket->GetLastReadCount());
return -1;
}
BYTE Header[3];
if ( Socket->ReadBlock( Header, sizeof(Header) ) )
{
int BufferSize = ((Header[1] << 8)|Header[2]) - 4;
PBYTEArray Buffer(BufferSize);
PPER_Stream ReadStream(Buffer);
if ( Socket->ReadBlock( ReadStream.GetPointer(), BufferSize) )
{
if ( Socket->GetLastReadCount() != BufferSize)
WTRACE(1, "Warning!!! Only one part of separate packet was received. Buffersize = " << BufferSize
<< ", LastreadCount = " << Socket->GetLastReadCount());
decoded = Mesg.Decode( ReadStream );
if (decoded)
return 0;
else
return -3;
}
}
WTRACE( 1, "Failed to read" );
Socket->Close();
return -2;
}
void SendMsg( PPER_Stream & Stream, WTCPSocket * Destination )
{
unsigned char tpkt[4];
size_t PacketLength = sizeof(tpkt) + Stream.GetSize();
tpkt[0] = 3;
tpkt[1] = 0;
tpkt[2] = (unsigned char)(PacketLength >> 8);
tpkt[3] = (unsigned char)PacketLength;
Destination->Write( tpkt, sizeof(tpkt) );
Destination->Write( Stream.GetPointer(), Stream.GetSize() );
if ((Destination->GetLastWriteCount() != 0) && (Destination->GetLastWriteCount() != Stream.GetSize())) {
cerr << "Warning!!! Only one part of separate packet was sent. Declared packet :" << PacketLength
<< " Sent :" << Destination->GetLastWriteCount() << endl;
}
}
// Function H225
static void EncodeH225IntoQ931( H225_H323_UserInformation & UUField, Q931 & Mesg )
// Encode the given H225 field into the Q931 message
{
PPER_Stream Strm;
UUField.Encode(Strm);
Strm.CompleteEncoding();
Mesg.SetIE(Q931::UserUserIE, Strm);
}
static bool HasUUField( const Q931 & Mesg, H225_H323_UserInformation & UUField )
{
if ( Mesg.HasIE(Q931::UserUserIE) )
{
PPER_Stream Strm = Mesg.GetIE(Q931::UserUserIE);
if ( UUField.Decode(Strm) )
return true;
}
return false;
}
static void SendMesgToDest( const Q931 & Mesg, WTCPSocket * Destination )
{
PPER_Stream WriteStream;
if( !Mesg.Encode( WriteStream ) )
WTRACE( 1, "Failed to encode message!" );
WSocket::Address PeerAddr;
unsigned PeerPort;
if (Destination != NULL && Destination->IsOpen() ) {
Destination->GetPeerAddress( PeerAddr, PeerPort );
SendMsg( WriteStream, Destination );
}
}
SignallingThread::SignallingThread( CallThread * vParent, TGlobal & vEnv, WTCPSocket * vSocket )
: Parent(vParent), env(vEnv), CallerSocket(vSocket)
{
Stop = false;
vSocket->GetPeerAddress( IncAddr, CallerPort );
CallPool = new TCallPool(env, this);
MyH245Handler = new H245Handler(this);
try
{
mAuth = new TAuth(&env);
if (env.AuthType == "radius" )
mAuth->InitRadius(env.AuthRadHost.c_str(), env.AuthRadPort, env.AuthRadSecret.c_str());
}
catch (...) {
cerr << "Unable to create AAA objects" << endl ;
return;
}
WTRACE(2, "Incomming signal connection from " << IncAddr );
Parent->ClTbl->IncSGWusage(IncAddr);
Parent->ClTbl->IncCIA(IncAddr);
MessLog = new TMessLog();
signalling_tdata = ( struct T_signalling_thread_data *) malloc (sizeof (struct T_signalling_thread_data));
mAcct = new TAcct(& env);
}
SignallingThread::~SignallingThread()
{
delete mAuth;
delete mAcct;
delete CallPool;
Parent -> ClTbl -> DelCall(this);
Parent -> ClTbl -> DecSGWusage(IncAddr);
if (MessLog != NULL)
delete MessLog;
if (signalling_tdata != NULL)
{
WTRACE(2, "Free pointer " << signalling_tdata);
free(signalling_tdata);
}
if ( CallerSocket != NULL )
{
CallerSocket->Close();
delete CallerSocket;
}
if (MyH245Handler != NULL)
delete MyH245Handler;
WTRACE(1,"SignalThread desrtoy");
}
void SignallingThread::Close()
{
// Later on this should be improved to do a proper cleanup of the call
// rather than just dropping it....
CallerSocket->Close();
}
void SignallingThread::Main()
{
ThreadID = pthread_self();
WTRACE(2, "Start Call from " << IncAddr << ":" << CallerPort);
int Selection, tval = 30;
vector<WSocket *> SList;
vector<WSocket *>::iterator it;
while ( !Stop && CallerSocket != NULL && CallerSocket->IsOpen() )
{
SList.clear();
AddrUtils::MapToSocketList(SList, CallPool->OutCalledSocket );
SList.push_back(CallerSocket);
Selection = WSocket::Select(SList, tval);
if ( Selection == -1 )
{
WTRACE(1, "Selection error. errno = " << errno << " : " << strerror(errno));
Stop = true;
continue;
}
if ( Selection == 0 )
{
// timeout
WTRACE(2, "Garbage coolector. OutCalledSocket List size = " << CallPool->OutCalledSocket.size());
if (CallPool->OutCalledSocket.size() == 0) // There aren't any OutCalled Socket
CallerSocket -> Close();
continue;
}
it = SList.begin();
while ( it != SList.end() )
{
if (*it != CallerSocket)
{
WTRACE(2, "Message got from Called");
ReceiveMesg((WTCPSocket *)*it, false);
}
else
{
WTRACE(2, "Message got from Caller");
ReceiveMesg((WTCPSocket *)*it, true);
}
it++;
CheckTimeout();
}
} // while
CallPool->Terminate();
}
void SignallingThread::ReceiveMesg(WTCPSocket * Socket, bool FromCaller )
{
Q931 Mesg;
int res;
unsigned CallRef;
res = ReadMsg( Socket, Mesg );
if ( res == 0 )
{
if (!WTrace::CanTrace(3)) {
WSocket::Address PeerAddr;
unsigned PeerPort;
Socket->GetPeerAddress( PeerAddr, PeerPort );
WTRACE ( 2, "H225\tPDU from " << PeerAddr << ":" << PeerPort );
WTRACE ( 2, Mesg);
}
HandleMesg( Mesg, FromCaller, CallRef );
}
else
{
if ( res == -1) {
if ( FromCaller)
{
CallPool->InternTC[CallRef] = TCallPool::InvalidTPKTCaller;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::InvalidTPKTCaller;
CallPool->IncCDR[CallRef].InternalCause = TCallPool::InvalidTPKTCaller;
}
else
{
CallPool->InternTC[CallRef] = TCallPool::InvalidTPKTCalled;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::InvalidTPKTCalled;
CallPool->IncCDR[CallRef].InternalCause = TCallPool::InvalidTPKTCalled;
}
}
if ( !Parent->IsRunning() )
Close();
}
}
// Handlers of messages
void SignallingThread::HandleMesg( Q931 & Mesg, bool FromCaller, unsigned & CallRef )
{
bool ForwardMesg;
bool HasUU;
bool CloseCall;
H225_H323_UserInformation UUField;
HasUU = HasUUField( Mesg, UUField );
WTRACE_IF(5, (IncAddr == env.DebugSourceHost) ,"Received UUField : " << IncAddr << endl << UUField );
WTRACE(7, "Received Mesg" << Mesg );
switch ( Mesg.GetMessageType() )
{
case Q931::SetupMsg :
WTRACE(2, "H225\tReceived Setup from " << (FromCaller ? "Caller" : "Called"));
MessLog->Add("H225","Setup",FromCaller);
ForwardMesg = HandleSetup( Mesg, FromCaller, HasUU, UUField, CallRef, false );
break;
case Q931::CallProceedingMsg :
WTRACE(2, "H225\tReceived Proceeding from " << (FromCaller ? "Caller" : "Called"));
MessLog->Add("H225","Proceeding",FromCaller);
ForwardMesg = HandleProceeding( Mesg, FromCaller, HasUU, UUField, CallRef );
break;
case Q931::AlertingMsg :
WTRACE(2, "H225\tReceived Alerting from " << (FromCaller ? "Caller" : "Called"));
MessLog->Add("H225","Alerting",FromCaller);
ForwardMesg = HandleAlerting( Mesg, FromCaller, HasUU, UUField, CallRef );
break;
case Q931::ConnectMsg :
WTRACE(2, "H225\tReceived Connect from " << (FromCaller ? "Caller" : "Called"));
MessLog->Add("H225","Connect",FromCaller);
ForwardMesg = HandleConnect( Mesg, FromCaller, HasUU, UUField, CallRef );
break;
case Q931::ReleaseCompleteMsg :
WTRACE(1, "H225\tReceived Release from " << (FromCaller ? "Caller" : "Called"));
MessLog->Add("H225","ReleaseComplete",FromCaller);
ForwardMesg = HandleRelease( Mesg, FromCaller, HasUU, UUField, CallRef, CloseCall );
break;
case Q931::FacilityMsg :
WTRACE(2, "H225\tReceived Facility from " << (FromCaller ? "Caller" : "Called"));
MessLog->Add("H225","Facility",FromCaller);
ForwardMesg = HandleFacility( Mesg, FromCaller, HasUU, UUField, CallRef );
break;
case Q931::ProgressMsg :
WTRACE(2, "H225\tReceived Progress from " << (FromCaller ? "Caller" : "Called"));
MessLog->Add("H225","Progress",FromCaller);
ForwardMesg = HandleProgress( Mesg, FromCaller, HasUU, UUField, CallRef );
break;
case Q931::InformationMsg :
WTRACE(2, "H225\tReceived Information from " << (FromCaller ? "Caller" : "Called"));
MessLog->Add("H225","Information",FromCaller);
ForwardMesg = HandleInformation( Mesg, FromCaller, HasUU, UUField, CallRef );
break;
case Q931::NotifyMsg :
WTRACE(2, "H225\tReceived Notify from " << (FromCaller ? "Caller" : "Called"));
MessLog->Add("H225","Notify",FromCaller);
ForwardMesg = HandleNotify( Mesg, FromCaller, HasUU, UUField, CallRef );
break;
default : // Nothing to do for now...
WTRACE(2, "error\tUnhandled message got " << Mesg << " from " << (FromCaller ? "Caller" : "Called"));
MessLog->Add("H225","UnknownMsg",FromCaller);
HandleUnknown( Mesg, FromCaller, HasUU, UUField, CallRef );
ForwardMesg = true;
break;
}
if ( ForwardMesg )
{
if ( FromCaller )
SendMesgToDest( Mesg, CallPool -> OutCalledSocket[CallRef] );
else
SendMesgToDest( Mesg, CallerSocket );
}
if ( Mesg.GetMessageType() == Q931::ReleaseCompleteMsg )
{
if (CallPool->InternTC[CallRef] == TCallPool::CallInProgress ) {
if ( FromCaller )
{
CallPool->InternTC[CallRef] = TCallPool::CallerNormal;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::CallerNormal;
CallPool->IncCDR[CallRef].InternalCause = TCallPool::CallerNormal;
}
else
{
CallPool->InternTC[CallRef] = TCallPool::CalledNormal;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::CalledNormal;
CallPool->IncCDR[CallRef].InternalCause = TCallPool::CalledNormal;
}
}
WTRACE(2, "ClearCall in ShuttingDownConnection state. CallRef = " << CallRef << " : InternTC=" <<
CallPool->InternTC[CallRef] << " CloseCall= " << CloseCall);
CallPool->StopAcctCall(CallRef);
if ( CloseCall ) {
ClearCall(CallRef);
WTRACE(1, "Call terminates. CloseCall = " << CloseCall << ", ReadyToClose = " << CallPool->ReadyToClose[CallRef] );
}
} // if ReleaseComlete
}
pthread_t SignallingThread::GetThreadName()
{
return ThreadID;
}
static bool HasH245Address( H225_H323_UserInformation & UUField, H225_TransportAddress & Addr )
{
H225_H323_UU_PDU_h323_message_body & Body = UUField.m_h323_uu_pdu.m_h323_message_body;
switch( Body.GetTag() )
{
case H225_H323_UU_PDU_h323_message_body::e_callProceeding :
{
H225_CallProceeding_UUIE & CallProceeding = Body;
if ( CallProceeding.HasOptionalField( H225_CallProceeding_UUIE::e_h245Address ) )
{
Addr = CallProceeding.m_h245Address;
WTRACE(2, "H225\tH245 address has found in CallProceeding message");
return true;
}
}
break;
case H225_H323_UU_PDU_h323_message_body::e_connect :
{
H225_Connect_UUIE & Connect = Body;
if ( Connect.HasOptionalField( H225_Connect_UUIE::e_h245Address ) )
{
Addr = Connect.m_h245Address;
WTRACE(2, "H225\tH245 address has found in Connect message");
return true;
}
}
break;
case H225_H323_UU_PDU_h323_message_body::e_alerting :
{
H225_Alerting_UUIE & Alerting = Body;
if ( Alerting.HasOptionalField( H225_Alerting_UUIE::e_h245Address ) )
{
Addr = Alerting.m_h245Address;
WTRACE(2, "H225\tH245 address has found in Alerting message");
return true;
}
}
break;
case H225_H323_UU_PDU_h323_message_body::e_facility :
{
H225_Facility_UUIE & Facility = Body;
if ( Facility.HasOptionalField( H225_Facility_UUIE::e_h245Address ) )
{
Addr = Facility.m_h245Address;
WTRACE(2, "H225\tH245 address has found in CallProceeding message");
return true;
}
}
break;
case H225_H323_UU_PDU_h323_message_body::e_setup :
{
H225_Setup_UUIE & Setup = Body;
if ( Setup.HasOptionalField( H225_Setup_UUIE::e_h245Address ) )
{
Addr = Setup.m_h245Address;
WTRACE(2, "H225\tH245 address has found in Setup message" );
return true;
}
}
break;
default :
return false;
}
return false;
}
void SignallingThread::HandleH245Setup( Q931 & Mesg, H225_H323_UserInformation & UUField, unsigned CallRef, bool FromCaller )
{
H225_TransportAddress Addr;
WSocket::Address ip_laddr;
if ( HasH245Address( UUField, Addr ) )
{
if (CallPool->Tunneling[CallRef] == true ) {
WTRACE(2, "Blocking H245 Address in call. CallRef = " << CallRef);
RemoveH245Address( Mesg, UUField );
return;
}
WTRACE(1, "H225\tHandling H245 channel procedure. H245 address got from " << (FromCaller ? "Caller" : "Called") << " side" );
if ( CallPool->H245ThreadList[CallRef] == NULL )
{
WTRACE(1, "H225\tCreate the H.245 thread");
CallPool->NewH245Thread(env, CallPool, CallRef, Addr, FromCaller);
}
else
{
WTRACE(1, "H225\tAllocate Second Listener. Request from " << (FromCaller ? "Caller" : "Called") << " side");
CallPool->H245ThreadList[CallRef]->SetTransportAddress(Addr, FromCaller) ;
CallPool->H245ThreadList[CallRef]->AllocateSecondListener(! FromCaller); // Oppozit Listener
}
// Debugging
WSocket::Address ip_addr;
unsigned ip_port;
AddrUtils::ConvertToIPAddress(Addr, ip_addr, ip_port);
WTRACE(2, "Got address " << ip_addr << ":" << ip_port);
// Get Address of Oppozit Listener
if ( !CallPool->H245ThreadList[CallRef]->GetListenerAddress(! FromCaller, Addr) )
WTRACE(0, "H225\tGetting Listener address fail. Rquest from " << (FromCaller ? "Caller": "Called") );
SetH245Address( Mesg, UUField, Addr );
}
}
void SignallingThread::SetH245Address( Q931 & Mesg, H225_H323_UserInformation & UUField, const H225_TransportAddress & Addr )
{
H225_H323_UU_PDU_h323_message_body & Body =
UUField.m_h323_uu_pdu.m_h323_message_body;
switch( Body.GetTag() )
{
case H225_H323_UU_PDU_h323_message_body::e_callProceeding :
{
H225_CallProceeding_UUIE & CallProceeding = Body;
CallProceeding.IncludeOptionalField( H225_CallProceeding_UUIE::e_h245Address );
CallProceeding.m_h245Address = Addr;
}
break;
case H225_H323_UU_PDU_h323_message_body::e_connect :
{
H225_Connect_UUIE & Connect = Body;
Connect.IncludeOptionalField( H225_Connect_UUIE::e_h245Address );
Connect.m_h245Address = Addr;
}
break;
case H225_H323_UU_PDU_h323_message_body::e_alerting :
{
H225_Alerting_UUIE & Alerting = Body;
Alerting.IncludeOptionalField( H225_Alerting_UUIE::e_h245Address );
Alerting.m_h245Address = Addr;
}
break;
case H225_H323_UU_PDU_h323_message_body::e_facility :
{
H225_Facility_UUIE & Facility = Body;
Facility.IncludeOptionalField( H225_Facility_UUIE::e_h245Address );
Facility.m_h245Address = Addr;
}
break;
case H225_H323_UU_PDU_h323_message_body::e_setup :
{
H225_Setup_UUIE & Setup = Body;
Setup.IncludeOptionalField( H225_Setup_UUIE::e_h245Address );
Setup.m_h245Address = Addr;
}
break;
default :
// Do nothing
break;
}
EncodeH225IntoQ931( UUField, Mesg );
WTRACE(2, "SetH245Address " << Addr );
}
void SignallingThread::RemoveH245Address( Q931 & Mesg, H225_H323_UserInformation & UUField )
{
H225_H323_UU_PDU_h323_message_body & Body =
UUField.m_h323_uu_pdu.m_h323_message_body;
switch( Body.GetTag() )
{
case H225_H323_UU_PDU_h323_message_body::e_callProceeding :
{
H225_CallProceeding_UUIE & CallProceeding = Body;
CallProceeding.RemoveOptionalField( H225_CallProceeding_UUIE::e_h245Address );
}
break;
case H225_H323_UU_PDU_h323_message_body::e_connect :
{
H225_Connect_UUIE & Connect = Body;
Connect.RemoveOptionalField( H225_Connect_UUIE::e_h245Address );
}
break;
case H225_H323_UU_PDU_h323_message_body::e_alerting :
{
H225_Alerting_UUIE & Alerting = Body;
Alerting.RemoveOptionalField( H225_Alerting_UUIE::e_h245Address );
}
break;
case H225_H323_UU_PDU_h323_message_body::e_facility :
{
H225_Facility_UUIE & Facility = Body;
Facility.RemoveOptionalField( H225_Facility_UUIE::e_h245Address );
}
break;
case H225_H323_UU_PDU_h323_message_body::e_setup :
{
H225_Setup_UUIE & Setup = Body;
Setup.RemoveOptionalField( H225_Setup_UUIE::e_h245Address );
}
break;
default :
// Do nothing
break;
}
EncodeH225IntoQ931( UUField, Mesg );
WTRACE(1, "RemoveH245Address");
}
bool SignallingThread::HandleProceeding( Q931 & Mesg, bool FromCaller,
bool HasUU, H225_H323_UserInformation & UUField, unsigned & CallRef )
{
CallRef = Mesg.GetCallReference();
WTRACE(3, "H225\tHandle Proceeding message from " << (FromCaller ? "Caller" : "Called"));
if ( HasUU )
{
if ( H225_CallProceeding_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).HasOptionalField( H225_CallProceeding_UUIE::e_fastStart ) )
{
H225_CallProceeding_UUIE & Proceed = UUField.m_h323_uu_pdu.m_h323_message_body;
WTRACE( 3,"FastStart message got in Proceed H225 message");
HandleFastStartAck( Proceed.m_fastStart, FromCaller, CallRef );
CallPool->PFSe[CallRef] = Proceed.m_fastStart;
CallPool->WasPFSe[CallRef] = true;
H225_CallProceeding_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).RemoveOptionalField( H225_CallProceeding_UUIE::e_fastStart );
CallPool->SetfState(CallRef, TCallPool::FastStartAcknowledged);
}
CheckTunneling(HasUU, UUField, CallPool->Tunneling[CallRef]);
HandleH245Setup( Mesg, UUField, CallRef, FromCaller );
HandleTunneledH245( UUField, CallRef, FromCaller );
EncodeH225IntoQ931( UUField, Mesg );
} // if HasUU
CallPool->InternTC[CallRef] = TCallPool::TimeoutAlertingMsg;
CallPool->IncCDR[CallRef].InternalCause = TCallPool::TimeoutAlertingMsg;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::TimeoutAlertingMsg;
CallPool->Timeout[CallRef] = time(NULL);
CallPool->EstablishedConnectionCheck(CallRef);
return false;
}
bool SignallingThread::HandleAlerting( Q931 & Mesg, bool FromCaller,
bool HasUU, H225_H323_UserInformation & UUField, unsigned & CallRef )
{
WTRACE(3, "H225\tHandle Alerting message from " << (FromCaller ? "Caller" : "Called"));
CallRef = Mesg.GetCallReference();
if ( env.Gateways->gwList[CallPool->DestGW[CallRef]]->DeferMsg == "Alerting" && CallPool->HasDefferedAlert[CallRef] == false )
{
WTRACE(1, "Ignore proxing Alerting message for " << CallPool->DestGW[CallRef]);
CallPool->HasDefferedAlert[CallRef] = true;
CallPool->AlertMsg[CallRef] = Mesg;
return false;
}
CallPool->HasDefferedAlert[CallRef] = false;
if ( HasUU )
{
// FastStart proceed
WTRACE (3, "Old Alerting message " << Mesg );
if ( H225_Alerting_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).HasOptionalField( H225_Alerting_UUIE::e_fastStart ) )
{
H225_Alerting_UUIE & Alerting = UUField.m_h323_uu_pdu.m_h323_message_body;
WTRACE( 3,"FastStart message got in Alerting H225 message");
if ( CallPool->WasPFSe[CallRef] )
HandleFastStartAck( Alerting.m_fastStart, FromCaller, CallRef, CallPool->PFSe[CallRef] );
else
HandleFastStartAck( Alerting.m_fastStart, FromCaller, CallRef );
CallPool->SetfState(CallRef, TCallPool::FastStartAcknowledged);
}
else
{
if ( CallPool->WasPFSe[CallRef] ) {
// insert Deffered FastStart elements
H225_Alerting_UUIE & Alerting = UUField.m_h323_uu_pdu.m_h323_message_body;
WTRACE (4, "Old Alerting UUe " << Alerting );
WTRACE( 4,"Inserting deferred Faststart elements from Proceed into Alerting message");
Alerting.IncludeOptionalField( H225_Alerting_UUIE::e_fastStart );
Alerting.m_fastStart = CallPool->PFSe[CallRef];
WTRACE (4, "New Alerting UUe " << Alerting );
CallPool->WasPFSe[CallRef] = false;
}
}
CheckTunneling(HasUU, UUField, CallPool->Tunneling[CallRef]);
HandleH245Setup( Mesg, UUField, CallRef, FromCaller );
HandleTunneledH245( UUField, CallRef, FromCaller );
// Multiply Call stub for several issues
if (H225_Alerting_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).HasOptionalField( H225_Alerting_UUIE::e_multipleCalls )) {
multipleCallsS = H225_Alerting_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).m_multipleCalls;
if (multipleCallsS)
{
WTRACE(1, "H225\tMulti call stub in Alerting message. CallRef = " << CallRef );
H225_Alerting_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).m_multipleCalls = false;
}
} // Multiply Call stub
EncodeH225IntoQ931( UUField, Mesg );
WTRACE (5, "New Alerting message " << Mesg );
} // if HasUU
CallPool->InternTC[CallRef] = TCallPool::TimeoutConnectMsg;
CallPool->IncCDR[CallRef].InternalCause = TCallPool::TimeoutConnectMsg;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::TimeoutConnectMsg;
CallPool->Timeout[CallRef] = time(NULL);
CallPool->EstablishedConnectionCheck(CallRef);
return true;
}
bool SignallingThread::HandleConnect( Q931 & Mesg, bool FromCaller,
bool HasUU, H225_H323_UserInformation & UUField , unsigned & CallRef )
{
WTRACE(3, "H225\tHandle Connect message from " << (FromCaller ? "Caller" : "Called"));
CallRef = Mesg.GetCallReference();
CallPool->IncCDR[CallRef].ConnectTime = TAcct::GetLocalTime();
if ( HasUU )
{
if ( H225_Connect_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).HasOptionalField( H225_Connect_UUIE::e_fastStart ) )
{
H225_Connect_UUIE & Connect = UUField.m_h323_uu_pdu.m_h323_message_body;
WTRACE( 3,"FastStart message got in Connect H225 message");
if ( CallPool->WasPFSe[CallRef] )
HandleFastStartAck( Connect.m_fastStart, FromCaller, CallRef, CallPool->PFSe[CallRef] );
else
HandleFastStartAck( Connect.m_fastStart, FromCaller, CallRef );
CallPool->SetfState( CallRef, TCallPool::FastStartAcknowledged);
}
else {
if ( CallPool->WasPFSe[CallRef] ) {
H225_Connect_UUIE & Connect = UUField.m_h323_uu_pdu.m_h323_message_body;
WTRACE (2, "Old Connect UUe " << Connect );
WTRACE( 3,"Inserting deferred Faststart elements from Proceed into Connect message");
Connect.IncludeOptionalField( H225_Connect_UUIE::e_fastStart );
Connect.m_fastStart = CallPool->PFSe[CallRef];
WTRACE (2, "New Connect UUe " << Connect );
CallPool->WasPFSe[CallRef] = false;
}
}
CheckTunneling(HasUU, UUField, CallPool->Tunneling[CallRef]);
HandleH245Setup( Mesg, UUField, CallRef, FromCaller );
HandleTunneledH245( UUField, CallRef, FromCaller );
// Multiply Call stub for several issues
if (H225_Connect_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).HasOptionalField( H225_Connect_UUIE::e_multipleCalls )) {
multipleCallsS = H225_Connect_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).m_multipleCalls;
if (multipleCallsS)
{
WTRACE(1, "H225\tMulti call stub in Connect message. CallRef = " << CallRef );
H225_Connect_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).m_multipleCalls = false;
}
} // Multiply Call stub
EncodeH225IntoQ931( UUField, Mesg );
}
// Set flag that we are up to CONNECT stage
CallPool->cStatesList[CallRef] = TCallPool::HasExecutedSignalConnect;
CallPool->InternTC[CallRef] = TCallPool::CallInProgress;
CallPool->IncCDR[CallRef].InternalCause = TCallPool::CallInProgress;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::CallInProgress;
WTRACE(3, "CallRef=" << CallRef << ": CallPool->cStatesList[CallRef]=" << CallPool->cStatesList[CallRef] <<
":CallPool->InternTC[CallRef]="<<CallPool->InternTC[CallRef]);
CallPool->Timeout[CallRef] = time(NULL);
CallPool->EstablishedConnectionCheck(CallRef);
CallPool->OutCDR[CallRef].ConnectTime = TAcct::GetLocalTime();
// if has deffered Alerting message
if (CallPool->HasDefferedAlert[CallRef] == true )
{
WTRACE(1, "Sending deffered message to CallerSocket " );
bool AlHasUU;
H225_H323_UserInformation AlUUField;
AlHasUU = HasUUField( CallPool->AlertMsg[CallRef], AlUUField );
HandleAlerting(CallPool->AlertMsg[CallRef], false, AlHasUU, AlUUField, CallRef);
SendMesgToDest( CallPool->AlertMsg[CallRef], CallerSocket );
CallPool->HasDefferedAlert[CallRef] = false;
}
return true;
}
bool SignallingThread::HandleRelease( Q931 & Mesg, bool FromCaller,
bool HasUU, H225_H323_UserInformation & UUField, unsigned & CallRef, bool & CloseCall )
{
bool b1;
WTRACE(1, "H225\tHandle Release message from" << (FromCaller ? "Caller" : "Called"));
CallRef = Mesg.GetCallReference();
CloseCall = false;
WTRACE(1, "CallPool->ReadyToClose[CallRef] = " << CallPool->ReadyToClose[CallRef] << ", CloseCall = " << CloseCall);
if ( HasUU ) {
HandleTunneledH245( UUField, CallRef, FromCaller );
CallPool->cStatesList[CallRef] = TCallPool::ShuttingDownConnection;
CallPool->EstablishedConnectionCheck(CallRef);
}
CallPool->IncCDR[CallRef].DisconnectTime = TAcct::GetLocalTime();
CallPool->OutCDR[CallRef].DisconnectTime = TAcct::GetLocalTime();
CallPool->HasDefferedAlert[CallRef] = false;
CallPool->WasPFSe[CallRef] = false;
WTRACE_IF(5, (IncAddr == env.DebugSourceHost) ,"Release Message dot : " << Mesg << endl << "Cause : " << Mesg.GetCause() );
if (FromCaller) {
CallPool->IncTC[CallRef] = Mesg.GetCause();
CallPool->IncCDR[CallRef].DisconnectCause = CallPool->IncTC[CallRef];
}
else {
CallPool->OutTC[CallRef] = Mesg.GetCause();
CallPool->IncCDR[CallRef].DisconnectCause = CallPool->OutTC[CallRef];
// if ( ! IsMultyCon ) {
// Dynamic routing only for H323 v <= 2
if ( ( ! env.IsBlockingCause( CallPool->OutTC[CallRef] ) ) && ( CallPool->IncCDR[CallRef].ConnectTime.size() == 0 ) ) {
if (mAuth->Routes.size() > 1 ) {
// StopAcct for failed call
CallPool->IncCDR[CallRef].InternalCause = TCallPool::CalledNormal;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::CalledNormal;
mAcct->StopAcct(CallPool->IncCDR[CallRef], CallPool->OutCDR[CallRef], TAcct::Both);
mAuth->Routes.erase(mAuth->Routes.begin());
CallPool->OutCDR[CallRef].RouteRetries++;
if ( b1 = ReHandleSetup(CallRef, CallPool->OutTC[CallRef]) )
if (b1) {
// New SetupMessage was sended through new way
CallPool->cStatesList[CallRef] = TCallPool::NoConnectionActive;
CloseCall = false;
CallPool->ReadyToClose[CallRef] = false;
CallPool->IncTC.erase(CallRef);
CallPool->OutTC.erase(CallRef);
return false;
}
else
// Close calls - resend ReleaseComlete - Rehandle can't procced new way
CallPool->ReadyToClose[CallRef] = true ;
if ( CallPool->OutCalledSocket[CallRef] != NULL )
CallPool->OutCalledSocket[CallRef]->Close();
} // if we have another way to route the call
} // if Termination cause isn't blocking
// } // if H323 has correct version
}
if (CallPool->StopTime[CallRef] == 0) {
CallPool->StopTime[CallRef] = time(NULL);
WTRACE(2, "Fixing of the moment of StopTime " << PTime(CallPool->StopTime[CallRef]) << ": CallRef=" << CallRef );
}
// StopAcct
CallPool->IncCDR[CallRef].StopTime = time(NULL);
CallPool->OutCDR[CallRef].StopTime = time(NULL);
CallPool->IncCDR[CallRef].IncOctets = CallPool->IncBytes[CallRef];
CallPool->IncCDR[CallRef].OutOctets = CallPool->OutBytes[CallRef];
CallPool->OutCDR[CallRef].IncOctets = CallPool->OutBytes[CallRef];
CallPool->OutCDR[CallRef].OutOctets = CallPool->IncBytes[CallRef];
if ((CallPool->InternTC[CallRef] != TCallPool::AuthReject) && (CallPool->InternTC[CallRef] != TCallPool::CallLoop) ) {
if (FromCaller)
{
CallPool->InternTC[CallRef] = TCallPool::CallerNormal;
CallPool->IncCDR[CallRef].InternalCause = TCallPool::CallerNormal;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::CallerNormal;
}
else
{
CallPool->InternTC[CallRef] = TCallPool::CalledNormal;
CallPool->IncCDR[CallRef].InternalCause = TCallPool::CalledNormal;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::CalledNormal;
}
}
CallPool->IncCDR[CallRef].Tunneling = (CallPool->IncCDR[CallRef].Tunneling ? 1 : 0 );
CallPool->OutCDR[CallRef].Tunneling = (CallPool->IncCDR[CallRef].Tunneling ? 1 : 0 );
CallPool->IncCDR[CallRef].FastStart = (CallPool->fStatesList[CallRef] != TCallPool::NoFastStart ? 1 : 0 );
CallPool->OutCDR[CallRef].FastStart = (CallPool->fStatesList[CallRef] != TCallPool::NoFastStart ? 1 : 0 );
if (mAuth->Routes.size() != 0) {
if ( ! CallPool->ReadyToClose[CallRef] ) // check for double stop leg
{
WTRACE(1, "StopAcct for " << CallPool->IncCDR[CallRef].CallID );
mAcct->StopAcct(CallPool->IncCDR[CallRef], CallPool->OutCDR[CallRef], TAcct::Both);
mAuth->Routes.erase(mAuth->Routes.begin());
}
}
CallPool->Timeout[CallRef] = time(NULL);
if (CallPool->ReadyToClose[CallRef] )
CloseCall = true;
CallPool->ReadyToClose[CallRef] = true;
return true;
}
bool SignallingThread::HandleFacility( Q931 & Mesg, bool FromCaller,
bool HasUU, H225_H323_UserInformation & UUField, unsigned & CallRef )
{
CallRef = Mesg.GetCallReference();
if ( HasUU )
{
WTRACE(5, "Facility message has UU : " << UUField );
CheckTunneling(HasUU, UUField, CallPool->Tunneling[CallRef]);
HandleH245Setup( Mesg, UUField, CallRef, FromCaller );
HandleTunneledH245( UUField, CallRef, FromCaller );
CallPool->EstablishedConnectionCheck(CallRef);
if (UUField.m_h323_uu_pdu.m_h323_message_body.GetDataLength() > 0 )
{
// FastStart proceeding
if ( H225_Facility_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).HasOptionalField( H225_Facility_UUIE::e_fastStart ) )
{
WTRACE(1, "FastStart UU got in Facility message from " << (FromCaller ? "Caller" : "Called" ) );
WTRACE(1, "Body: " << H225_Facility_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body) );
// H225_Facility_UUIE & Facility = UUField.m_h323_uu_pdu.m_h323_message_body;
// HandleFastStartAck( Facility.m_fastStart, FromCaller, CallRef );
// CallPool->SetfState(CallRef, TCallPool::FastStartAcknowledged);
} // FastStart
// Multiply Call stub for several issues
if (H225_Facility_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).HasOptionalField( H225_Facility_UUIE::e_multipleCalls )) {
multipleCallsS = H225_Facility_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).m_multipleCalls;
if (multipleCallsS)
{
WTRACE(1, "H225\tMulti call stub in Facility message. CallRef = " << CallRef );
H225_Facility_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).m_multipleCalls = false;
}
} // Multiply Call stub
}
EncodeH225IntoQ931( UUField, Mesg );
}
return true;
}
bool SignallingThread::HandleProgress ( Q931 & Mesg, bool FromCaller,
bool HasUU, H225_H323_UserInformation & UUField, unsigned & CallRef )
{
CallRef = Mesg.GetCallReference();
if ( HasUU )
{
WTRACE(2, "Progress message has UU : " << UUField );
if (UUField.m_h323_uu_pdu.m_h323_message_body.GetDataLength() > 0 )
{
// FastStart proceeding
if ( H225_Progress_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).HasOptionalField( H225_Progress_UUIE::e_fastStart ) )
{
WTRACE(1, "FastStart UU got in Progress message from " << (FromCaller ? "Caller" : "Called" ) );
H225_Progress_UUIE & Progress = UUField.m_h323_uu_pdu.m_h323_message_body;
WTRACE( 1,"FastStart message got in facility H225 message");
if ( FromCaller )
HandleFastStart( Progress.m_fastStart, FromCaller, CallRef );
else
HandleFastStartAck( Progress.m_fastStart, FromCaller, CallRef );
} // FastStart
CallPool->SetfState(CallRef, TCallPool::FastStartAcknowledged);
// Multiply Call stub for several issues
if (H225_Progress_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).HasOptionalField( H225_Progress_UUIE::e_multipleCalls )) {
multipleCallsS = H225_Progress_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).m_multipleCalls;
if (multipleCallsS)
{
WTRACE(1, "H225\tMulti call stub in Progress");
H225_Progress_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).m_multipleCalls = false;
}
} // Multiply Call stub
}
EncodeH225IntoQ931( UUField, Mesg );
}
return true;
}
void SignallingThread::HandleUnknown ( Q931 & Mesg, bool FromCaller,
bool HasUU, H225_H323_UserInformation & UUField, unsigned & CallRef )
{
CallRef = Mesg.GetCallReference();
if ( HasUU )
{
WTRACE(1, "Unknown message has UU : " << UUField );
WTRACE(1, "Message body " << Mesg );
}
return ;
}
bool SignallingThread::HandleInformation ( Q931 & Mesg, bool FromCaller,
bool HasUU, H225_H323_UserInformation & UUField, unsigned & CallRef )
{
CallRef = Mesg.GetCallReference();
if ( HasUU )
{
WTRACE(1, "Information message has UU : " << UUField );
WTRACE(1, "Message body " << Mesg );
}
return true;
}
bool SignallingThread::HandleNotify ( Q931 & Mesg, bool FromCaller,
bool HasUU, H225_H323_UserInformation & UUField, unsigned & CallRef )
{
CallRef = Mesg.GetCallReference();
if ( HasUU )
{
WTRACE(2, "Notify message has UU : " << UUField );
}
return true;
}
void SignallingThread::TranslateSetup( H225_Setup_UUIE & Setup, const H225_TransportAddress & SourceCallSigAddr,
const H225_TransportAddress & DestCallSigAddr,
const string & OutCalledNumber, const string & OutCallingNumber )
// Translate a setup UserUser information element
{
if ( Setup.HasOptionalField( H225_Setup_UUIE::e_sourceCallSignalAddress ) )
{
Setup.m_sourceCallSignalAddress = SourceCallSigAddr;
}
if ( Setup.HasOptionalField( H225_Setup_UUIE::e_destCallSignalAddress ) )
{
Setup.m_destCallSignalAddress = DestCallSigAddr;
}
int i;
PString str;
WTRACE(1, "New: CalledNumber " << OutCalledNumber << " , CallingNumber " << OutCallingNumber );
for (i = 0; i < Setup.m_destinationAddress.GetSize(); i++) {
if ( Setup.m_destinationAddress[i].GetTag() == H225_AliasAddress::e_dialedDigits ) {
str = OutCalledNumber.c_str();
//Setup.m_destinationAddress[i].SetTag(H225_AliasAddress::e_dialedDigits);
(PASN_IA5String &) Setup.m_destinationAddress[i] = str;
}
}
/*
* Non-stable block/ Cisco 38xx trow code in coredump
if ( OutCallingNumber != "" )
{
for (i = 0; i < Setup.m_sourceAddress.GetSize(); i++) {
if ( Setup.m_sourceAddress[i].GetTag() == H225_AliasAddress::e_h323_ID ) {
str = OutCallingNumber.c_str();
(PASN_IA5String &) Setup.m_sourceAddress[i] = str;
}
}
} // if
*/
}
bool SignallingThread::ConnectToRemote( WSocket::Address & IpAddr, unsigned CallRef )
// Connect the socket to the desired destination
{
bool Connected;
CallPool->OutCalledSocket[CallRef] = new WTCPSocket();
if (env.OutAddr != INADDR_ANY ) {
CallPool->OutLocalAddr[CallRef] = env.OutAddr;
CallPool->OutCalledSocket[CallRef]->Bind(env.OutAddr);
}
Connected = CallPool->OutCalledSocket[CallRef]->Connect( IpAddr, static_cast<WORD>(1720) );
if ( Connected )
{
CallPool->OutCalledSocket[CallRef]->GetLocalAddress( CallPool->OutLocalAddr[CallRef] );
WTRACE(1,"Connected from " << CallPool->OutLocalAddr[CallRef] << ":" << CallPool->OutCalledSocket[CallRef]->GetLocalPort()
<< " to " << IpAddr);
return true;
}
else
{
CallPool->OutCalledSocket[CallRef] -> Close();
delete CallPool->OutCalledSocket[CallRef];
CallPool->OutCalledSocket.erase(CallRef);
WTRACE( 1, "Error\tFailed to connect to call signalling channel at " << IpAddr );
return false;
}
}
void SignallingThread::GetDestinationAdress( H225_H323_UserInformation UUField, string & DestDialedDigits)
{
int i;
PString str;
H225_Setup_UUIE & Setup = UUField.m_h323_uu_pdu.m_h323_message_body;
if ( Setup.HasOptionalField( H225_Setup_UUIE::e_destinationAddress ) ) {
for (i = 0; i < Setup.m_destinationAddress.GetSize(); i++) {
if (Setup.m_destinationAddress[i].GetTag() == H225_AliasAddress::e_dialedDigits ) {
str = (PASN_IA5String &)Setup.m_destinationAddress[i];
DestDialedDigits = AddrUtils::PerlTranslate("/#//", (const char *) str );
WTRACE(2, "H225\tGot dialedDigits in destinationAddress : " << str);
}
}
}
return ;
}
bool SignallingThread::ReHandleSetup(unsigned & CallRef, const int TermCode)
{
Q931 Mesg;
bool HasUU, res;
H225_H323_UserInformation UUField;
CallPool->WasPFSe[CallRef]=false;
Mesg = CallPool->SetupMsg[CallRef];
WTRACE(1, "ReHandleSetup. CallRef=" << CallRef << ". TermCode=" << TermCode << " Routes.size= " << mAuth->Routes.size());
if (CallPool -> MediaThreadList[CallRef] != NULL)
CallPool -> MediaThreadList[CallRef] -> PrintOn();
HasUU = HasUUField( Mesg, UUField );
res = HandleSetup(Mesg, true, HasUU, UUField, CallRef, true);
SendMesgToDest( Mesg, CallPool->OutCalledSocket[CallRef] );
return res;
}
bool SignallingThread::HandleSetup( Q931 & Mesg, bool FromCaller,
bool HasUU, H225_H323_UserInformation & UUField, unsigned & CallRef, bool Reuse )
{
WTRACE(3, "Q931\tHandle Setup message");
string sAddr, CalledTl;
unsigned plan, type;
PString RawCalledNumber, PCallingNumber;
string CallingNumber, TechPrefix, OutCalledNumber, OutCallingNumber, DestDialedDigits;
int MinDigitsRestriction, GWusage;
bool RemoteConnected;
bool IsLocalZoneCall = false;
GetDestinationAdress(UUField, DestDialedDigits);
if ( !Mesg.GetCalledPartyNumber(RawCalledNumber, &plan, &type) )
RawCalledNumber = DestDialedDigits.c_str();
Mesg.GetCallingPartyNumber(PCallingNumber, &plan, &type);
if (RawCalledNumber.GetLength() > 30) {
WTRACE(1, "RawCalledNumber is too long : " << RawCalledNumber );
RawCalledNumber.SetSize(30);
}
if (PCallingNumber.GetLength() > 30) {
WTRACE(1, "CallingNumber is too long : " << CallingNumber );
PCallingNumber.SetSize(30);
}
CallingNumber = (const char *) PCallingNumber;
if (! Reuse ) // New call
{
CallRef = Mesg.GetCallReference();
CallPool->OutCDR[CallRef].RouteRetries = 1;
CallPool->IncCDR[CallRef].RouteRetries = 1;
CallPool->IncCDR[CallRef].SetupTime = TAcct::GetLocalTime();
CallPool->SetupMsg[CallRef] = Mesg;
CallPool->StartTime[CallRef] = time(NULL);
CallPool->ReadyToClose[CallRef] = false;
if (CallPool->StartTime.size() > 1 )
IsMultyCon = true;
else
IsMultyCon = false;
// Get CallIdent / IncProductId
if ( HasUU )
{
H225_Setup_UUIE & Setup = UUField.m_h323_uu_pdu.m_h323_message_body;
if (Setup.HasOptionalField( H225_Setup_UUIE::e_callIdentifier )) {
CallPool->CallIdent[CallRef] = Setup.m_callIdentifier;
}
IncProductId = "";
IncVersionId = "";
if ( Setup.HasOptionalField( H225_Setup_UUIE::e_sourceAddress ) )
{
IncProductId = Setup.m_sourceInfo.m_vendor.m_productId.AsString();
IncVersionId = Setup.m_sourceInfo.m_vendor.m_versionId.AsString();
}
CallPool->IncCDR[CallRef].ConferenceID = (const char *)AddrUtils::AsString(Setup.m_conferenceID);
CallPool->OutCDR[CallRef].ConferenceID = (const char *)AddrUtils::AsString(Setup.m_conferenceID);
}
else {
CallPool->InternTC[CallRef] = TCallPool::InvalidSetupMsg;
CallPool->IncCDR[CallRef].InternalCause = TCallPool::InvalidSetupMsg;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::InvalidSetupMsg;
return false;
}
CallerSocket->GetLocalAddress( IncLocalAddr );
WTRACE(3,"The connection proceed from interface: " << IncLocalAddr );
AddrUtils::IncomingTranslate(RawCalledNumber, env.IncTlCalled);
WTRACE(4, "New RawCalledNumber:" << RawCalledNumber << " Pattern size:" << env.IncTlCalled.size());
// StartAcct for incoming leg
CallPool->IncCDR[CallRef].AcctSessionID = GetAcctSessionId();
CallPool->IncCDR[CallRef].CallingStationId = CallingNumber;
CallPool->IncCDR[CallRef].CalledStationId = (const char *) RawCalledNumber;
CallPool->IncCDR[CallRef].CallID = (const char *)AddrUtils::AsString(CallPool->CallIdent[CallRef].m_guid);
CallPool->IncCDR[CallRef].gwID = env.ID;
CallPool->IncCDR[CallRef].RemoteAddr = IncAddr.AsString();
CallPool->IncCDR[CallRef].LocalAddr = IncLocalAddr.AsString();
mAcct->StartAcct(CallPool->IncCDR[CallRef], false);
if (! mAuth->FirstAuthorize(IncAddr, CallingNumber, (const char *) RawCalledNumber, CallPool->IncCDR[CallRef].ConferenceID ) )
{
WTRACE(1, "Authentication fails. IncAddr = " << IncAddr << " , CallingNumber = " << CallingNumber
<< " , CallRef = " << CallRef << " , CalledNumber = " << RawCalledNumber);
CallPool->InternTC[CallRef] = TCallPool::AuthReject;
CallPool->IncCDR[CallRef].InternalCause = TCallPool::AuthReject;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::AuthReject;
SendReleaseComplete( Mesg, CallerSocket, Q931::NoRouteToNetwork );
CallPool->IncCDR[CallRef].SetupTime = TAcct::GetLocalTime();
mAcct->StopAcct(CallPool->IncCDR[CallRef], CallPool->OutCDR[CallRef], TAcct::Origin);
return false;
} // Auth fails
if (mAuth->KillList.size() > 0 )
{
WTRACE(1, "List for shutdown call is exist");
ShutdownCalls(mAuth->KillList);
}
// CallLoop control for frequent calls on several interfaces
if (! Parent->ClTbl->isUniqCallIdent(CallPool->CallIdent[CallRef]) ) {
WTRACE(1, "Call loop. IncAddr = " << IncAddr << " , CallingNumber = " << CallingNumber <<
" CallIdent = " << AddrUtils::AsString(CallPool->CallIdent[CallRef].m_guid));
CallPool->InternTC[CallRef] = TCallPool::CallLoop;
CallPool->IncCDR[CallRef].InternalCause = TCallPool::CallLoop;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::CallLoop;
SendReleaseComplete( Mesg, CallerSocket, Q931::NoCircuitChannelAvailable );
return false;
} // Call loop
} //// if New call (!Reuse)
OutCalledNumber = mAuth->Replies[mAuth->Routes[0]]->CalledNumber;
CallPool->MediaProxing[CallRef] = mAuth->Replies[mAuth->Routes[0]]->MediaProxy;
WTRACE(1, "Media\tMediaProxing mode " << (CallPool->MediaProxing[CallRef] ? "on" : "off" ) );
if ( OutCalledNumber == "" )
OutCalledNumber = RawCalledNumber;
OutCallingNumber = mAuth->Replies[mAuth->Routes[0]]->CallingNumber;
if ( OutCallingNumber == "" )
OutCallingNumber = PCallingNumber;
CallPool->OutCDR[CallRef].CallingStationId = OutCallingNumber;
CallPool->OutCDR[CallRef].CalledStationId = OutCalledNumber;
WTRACE(1,"OutCalledNumber : " << OutCalledNumber << " OutCallingNumber : " << OutCallingNumber);
if ( Reuse )
{
CallPool->Attempts[CallRef]++;
}
else
{
WSocket::Address SoIP;
CallerSocket->GetPeerAddress(SoIP);
CallPool->CalledNumber[CallRef] = RawCalledNumber;
}
CallPool->OutCDR[CallRef].AcctSessionID = GetAcctSessionId();
CallPool->OutCDR[CallRef].CallID = (const char *)AddrUtils::AsString(CallPool->CallIdent[CallRef].m_guid);
CallPool->OutCDR[CallRef].gwID = env.ID;
CallPool->IncCDR[CallRef].SetupTime = TAcct::GetLocalTime();
mAcct->StartAcct(CallPool->OutCDR[CallRef], true);
RemoteConnected = false;
WTRACE(2, "RouteTable size is " << mAuth->Routes.size());
while ( ! RemoteConnected) {
CallPool->OutCDR[CallRef].IncOctets = 0;
CallPool->OutCDR[CallRef].OutOctets = 0;
CallPool->OutCDR[CallRef].StartTime = 0;
CallPool->OutCDR[CallRef].StopTime = 0;
if ( mAuth->Routes.size() == 0 ) {
WTRACE(2, "NoCircuitChannelAvailable for" << CallPool->CalledNumber[CallRef]);
SendReleaseComplete( Mesg, CallerSocket, Q931::NoCircuitChannelAvailable );
CallPool->InternTC[CallRef] = TCallPool::NoRouteToDest;
CallPool->IncCDR[CallRef].InternalCause = TCallPool::NoRouteToDest;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::NoRouteToDest;
CallPool->Attempts[CallRef]++;
CallPool->OutCDR[CallRef].DisconnectCause = Q931::NoCircuitChannelAvailable;
CallPool->IncCDR[CallRef].DisconnectCause = Q931::NoCircuitChannelAvailable;
CallPool->IncCDR[CallRef].Tunneling = (CallPool->IncCDR[CallRef].Tunneling ? 1 : 0 );
CallPool->OutCDR[CallRef].Tunneling = (CallPool->IncCDR[CallRef].Tunneling ? 1 : 0 );
CallPool->IncCDR[CallRef].FastStart = (CallPool->fStatesList[CallRef] != TCallPool::NoFastStart ? 1 : 0 );
CallPool->OutCDR[CallRef].FastStart = (CallPool->fStatesList[CallRef] != TCallPool::NoFastStart ? 1 : 0 );
return false;
}
if (IsLocalZoneCall) {
WTRACE(1, "Local zone call");
// sAddr is already defined
CalledTl = "";
OutDialPeer = 0;
MinDigitsRestriction = CallPool->CalledNumber[CallRef].size()-1;
}
else
{
CalledTl = "";
CallPool->DestGW[CallRef] = mAuth->Routes[0] ;
if (env.Gateways->gwList[CallPool->DestGW[CallRef]] == NULL )
sAddr = "";
else
sAddr = env.Gateways->gwList[CallPool->DestGW[CallRef]]->Address;
if ( sAddr.empty() )
{
WTRACE(1, "Unrecognized Gateway " << mAuth->Routes[0]);
CallPool->OutCDR[CallRef].DisconnectCause = Q931::NoCircuitChannelAvailable;
CallPool->IncCDR[CallRef].DisconnectCause = Q931::NoCircuitChannelAvailable;
CallPool->IncCDR[CallRef].Tunneling = (CallPool->IncCDR[CallRef].Tunneling ? 1 : 0 );
CallPool->OutCDR[CallRef].Tunneling = (CallPool->IncCDR[CallRef].Tunneling ? 1 : 0 );
CallPool->IncCDR[CallRef].FastStart = (CallPool->fStatesList[CallRef] != TCallPool::NoFastStart ? 1 : 0 );
CallPool->OutCDR[CallRef].FastStart = (CallPool->fStatesList[CallRef] != TCallPool::NoFastStart ? 1 : 0 );
if (mAuth->Routes.size() != 0) {
mAcct->StopAcct(CallPool->IncCDR[CallRef], CallPool->OutCDR[CallRef], TAcct::Origin);
mAuth->Routes.erase(mAuth->Routes.begin());
CallPool->OutCDR[CallRef].RouteRetries++;
}
continue;
}
MinDigitsRestriction = 1;
CallPool->OutCDR[CallRef].CallingBill = mAuth->Replies[mAuth->Routes[0]]->BCallingNumber;
CallPool->OutCDR[CallRef].CalledBill = mAuth->Replies[mAuth->Routes[0]]->BCalledNumber;
CallPool->IncCDR[CallRef].CallingBill = mAuth->Replies[mAuth->Routes[0]]->BCallingNumber;
CallPool->IncCDR[CallRef].CalledBill = mAuth->Replies[mAuth->Routes[0]]->BCalledNumber;
}
if (MinDigitsRestriction == -1) {
MinDigitsRestriction = env.MinDigitsDefault;
}
if ((! IsLocalZoneCall) && CallPool->CalledNumber[CallRef].length() < (unsigned) MinDigitsRestriction) {
WTRACE( 1, "Target gateway has restricted Minmal digits in Called number :" << sAddr << " : " << OutCalledNumber);
CallPool->InternTC[CallRef] = TCallPool::RestrictedCalledN;
CallPool->IncCDR[CallRef].InternalCause = TCallPool::RestrictedCalledN;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::RestrictedCalledN;
CallPool->Attempts[CallRef]++;
CallPool->OutCDR[CallRef].DisconnectCause = Q931::NoCircuitChannelAvailable;
CallPool->IncCDR[CallRef].DisconnectCause = Q931::NoCircuitChannelAvailable;
CallPool->IncCDR[CallRef].Tunneling = (CallPool->IncCDR[CallRef].Tunneling ? 1 : 0 );
CallPool->OutCDR[CallRef].Tunneling = (CallPool->IncCDR[CallRef].Tunneling ? 1 : 0 );
CallPool->IncCDR[CallRef].FastStart = (CallPool->fStatesList[CallRef] != TCallPool::NoFastStart ? 1 : 0 );
CallPool->OutCDR[CallRef].FastStart = (CallPool->fStatesList[CallRef] != TCallPool::NoFastStart ? 1 : 0 );
if (mAuth->Routes.size() != 0) {
mAcct->StopAcct(CallPool->IncCDR[CallRef], CallPool->OutCDR[CallRef], TAcct::Origin);
mAuth->Routes.erase(mAuth->Routes.begin());
CallPool->OutCDR[CallRef].RouteRetries++;
}
continue;
} // minimal called digits restriction
CallPool->OutAddr[CallRef] = sAddr.c_str();
GWusage = Parent->ClTbl->GetUsage(CallPool->OutAddr[CallRef]);
WTRACE(1, "GWUsage = " << GWusage << " for Addr = " << CallPool->OutAddr[CallRef] << ". Capcity = "
<< env.Gateways->gwList[mAuth->Routes[0]]->Capacity);
if ( (env.Gateways->gwList[mAuth->Routes[0]]->Capacity != 0) && (GWusage >= env.Gateways->gwList[mAuth->Routes[0]]->Capacity) )
{
WTRACE( 1, "Target gateway has restricted capacity :" << CallPool->OutAddr[CallRef] );
CallPool->InternTC[CallRef] = TCallPool::DestUnreach;
CallPool->IncCDR[CallRef].InternalCause = TCallPool::DestUnreach;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::DestUnreach;
CallPool->OutCDR[CallRef].DisconnectCause = Q931::NoCircuitChannelAvailable;
CallPool->IncCDR[CallRef].DisconnectCause = Q931::NoCircuitChannelAvailable;
CallPool->IncCDR[CallRef].Tunneling = (CallPool->IncCDR[CallRef].Tunneling ? 1 : 0 );
CallPool->OutCDR[CallRef].Tunneling = (CallPool->IncCDR[CallRef].Tunneling ? 1 : 0 );
CallPool->IncCDR[CallRef].FastStart = (CallPool->fStatesList[CallRef] != TCallPool::NoFastStart ? 1 : 0 );
CallPool->OutCDR[CallRef].FastStart = (CallPool->fStatesList[CallRef] != TCallPool::NoFastStart ? 1 : 0 );
if (mAuth->Routes.size() != 0) {
mAcct->StopAcct(CallPool->IncCDR[CallRef], CallPool->OutCDR[CallRef], TAcct::Origin);
mAuth->Routes.erase(mAuth->Routes.begin());
CallPool->OutCDR[CallRef].RouteRetries++;
}
continue;
} // Capacity restriction
Parent->ClTbl->IncDGWusage(CallPool->OutAddr[CallRef]);
Parent->ClTbl->IncCOA(CallPool->OutAddr[CallRef]);
WTRACE (2, "Try to connect to " << CallPool->OutAddr[CallRef] << " CalledNumber is " << CallPool->CalledNumber[CallRef]
<< "::" << plan << ":" << type );
if ( Reuse && CallPool->OutCalledSocket[CallRef] != NULL) {
if (CallPool->OutCalledSocket[CallRef]->IsOpen() )
CallPool->OutCalledSocket[CallRef]->Close(); // for reassign
delete CallPool->OutCalledSocket[CallRef]; // in ConnectToRemote function
}
if ( ! ConnectToRemote( CallPool->OutAddr[CallRef], CallRef ) ) {
WTRACE( 1, "Failed to connect to calling signalling channel of remote endpoint :" << CallPool->OutAddr[CallRef] );
CallPool->InternTC[CallRef] = TCallPool::DestUnreach;
CallPool->IncCDR[CallRef].InternalCause = TCallPool::DestUnreach;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::DestUnreach;
CallPool->OutCDR[CallRef].LocalAddr = CallPool->OutLocalAddr[CallRef].AsString();
CallPool->OutCDR[CallRef].RemoteAddr = "0.0.0.0";
CallPool->OutCDR[CallRef].DisconnectCause = Q931::DestinationOutOfOrder;
CallPool->IncCDR[CallRef].DisconnectCause = Q931::DestinationOutOfOrder;
CallPool->IncCDR[CallRef].Tunneling = (CallPool->IncCDR[CallRef].Tunneling ? 1 : 0 );
CallPool->OutCDR[CallRef].Tunneling = (CallPool->IncCDR[CallRef].Tunneling ? 1 : 0 );
CallPool->IncCDR[CallRef].FastStart = (CallPool->fStatesList[CallRef] != TCallPool::NoFastStart ? 1 : 0 );
CallPool->OutCDR[CallRef].FastStart = (CallPool->fStatesList[CallRef] != TCallPool::NoFastStart ? 1 : 0 );
if (mAuth->Routes.size() != 0)
{
mAcct->StopAcct(CallPool->IncCDR[CallRef], CallPool->OutCDR[CallRef], TAcct::Origin );
mAuth->Routes.erase(mAuth->Routes.begin());
CallPool->OutCDR[CallRef].RouteRetries++;
}
}
else {
RemoteConnected = true;
WTRACE (2, "RemoteConnect = true; Routes.size = " << mAuth->Routes.size() );
}
CallPool->OutCDR[CallRef].LocalAddr = CallPool->OutLocalAddr[CallRef].AsString();
} // Loop in
WTRACE(4, "Connected to remote " << CallPool->OutAddr[CallRef] << " CalledNumber is " << CallPool->CalledNumber[CallRef] );
CallPool->OutCDR[CallRef].SetupTime = TAcct::GetLocalTime();
CallPool->OutCDR[CallRef].RemoteAddr = CallPool->OutAddr[CallRef].AsString();
if ( HasUU )
{
CheckTunneling(HasUU, UUField, CallPool->Tunneling[CallRef]);
WTRACE(4, "Handle UU in setup message");
HandleH245Setup( Mesg, UUField, CallRef, FromCaller );
// Multiply Call stub for several issues
if (H225_Setup_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).HasOptionalField( H225_Setup_UUIE::e_multipleCalls ))
{
multipleCallsS = H225_Setup_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).m_multipleCalls;
if (multipleCallsS)
{
WTRACE(1, "H225\tMulti call stub in Setup message. CallRef = " << CallRef);
H225_Setup_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).m_multipleCalls = false;
}
} // Multiply Call stub
} // if HasUU
if ( ! Reuse ) // New Call
{
SendProceeding( Mesg, UUField, CallPool->Tunneling[CallRef], multipleCallsS );
}
if ( HasUU )
{
// FastStart proceed
if ( H225_Setup_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).HasOptionalField( H225_Setup_UUIE::e_fastStart ) )
{
H225_Setup_UUIE & Setup = UUField.m_h323_uu_pdu.m_h323_message_body;
WTRACE( 3,"fastStart message got");
HandleFastStart( Setup.m_fastStart, FromCaller, CallRef );
CallPool->SetfState(CallRef, TCallPool::FastStartResponse);
}
// Handle any tunneled H.245
HandleTunneledH245( UUField, CallRef, FromCaller );
if ( H225_Setup_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).HasOptionalField( H225_Setup_UUIE::e_parallelH245Control ) )
{
WTRACE(3, "H225\tHandle H245Parallel Control in Setup message");
for( int i = 0; i < H225_Setup_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).m_parallelH245Control.GetSize(); ++i )
{
PPER_Stream Strm = H225_Setup_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).m_parallelH245Control[i].GetValue();
H245_MultimediaSystemControlMessage H245Mesg;
H245Mesg.Decode( Strm );
MyH245Handler->HandleMesg( H245Mesg, CallRef, FromCaller );
PPER_Stream strm_m;
H245Mesg.Encode( strm_m );
H225_Setup_UUIE(UUField.m_h323_uu_pdu.m_h323_message_body).m_parallelH245Control[i].SetValue( strm_m );
} // for
} // if H245 Parallel control
// Translate setup message so that it references our call signalling address
WSocket::Address SourceAddr, DestAddr;
unsigned SourcePort, DestPort;
CallPool->OutCalledSocket[CallRef]->GetLocalAddress( SourceAddr, SourcePort );
CallPool->OutCalledSocket[CallRef]->GetPeerAddress( DestAddr, DestPort );
TranslateSetup( UUField.m_h323_uu_pdu.m_h323_message_body,
AddrUtils::ConvertToH225TransportAddr( SourceAddr, SourcePort ),
AddrUtils::ConvertToH225TransportAddr( DestAddr, DestPort),
OutCalledNumber, OutCallingNumber );
EncodeH225IntoQ931( UUField, Mesg );
Mesg.SetCalledPartyNumber(OutCalledNumber.c_str(), plan, type);
Mesg.SetCallingPartyNumber(OutCallingNumber.c_str(), plan, type);
WTRACE(2,"Q931\tOutCalledNumber = " << OutCalledNumber << " OutCallingNumber = " << OutCallingNumber);
}
else
{
WTRACE( 1, "Failed to decode Q931 User-User information" );
CallPool->InternTC[CallRef] = TCallPool::InvalidSetupMsg;
CallPool->IncCDR[CallRef].InternalCause = TCallPool::InvalidSetupMsg;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::InvalidSetupMsg;
} // if else HasUU
CallPool->InternTC[CallRef] = TCallPool::TimeoutProceeding;
CallPool->IncCDR[CallRef].InternalCause = TCallPool::TimeoutProceeding;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::TimeoutProceeding;
CallPool->Timeout[CallRef] = time(NULL);
return true;
}
void SignallingThread::SendProceeding( const Q931 & SetupMesg, H225_H323_UserInformation & UUFieldPar , bool Tunneling, bool multipleCallsS )
{
Q931 Proceeding;
Proceeding.BuildCallProceeding( SetupMesg.GetCallReference() );
WTRACE(2, "Q931\tGenerate CallProceed for send it to Caller");
H225_H323_UserInformation UUField;
const H225_Setup_UUIE & Setup = H225_Setup_UUIE(UUFieldPar.m_h323_uu_pdu.m_h323_message_body);
H225_H323_UU_PDU_h323_message_body & Body = UUField.m_h323_uu_pdu.m_h323_message_body;
Body.SetTag( H225_H323_UU_PDU_h323_message_body::e_callProceeding );
H225_CallProceeding_UUIE & CallProceeding = Body;
CallProceeding.m_protocolIdentifier.SetValue( H225_ProtocolID );
CallProceeding.m_destinationInfo = Setup.m_sourceInfo;
if ( Setup.HasOptionalField( H225_Setup_UUIE::e_callIdentifier ) )
{
CallProceeding.IncludeOptionalField( H225_CallProceeding_UUIE::e_callIdentifier );
CallProceeding.m_callIdentifier = Setup.m_callIdentifier;
}
if ( Tunneling )
{
UUField.m_h323_uu_pdu.IncludeOptionalField( H225_H323_UU_PDU::e_h245Tunneling );
UUField.m_h323_uu_pdu.m_h245Tunneling = Tunneling;
}
// if (multipleCallsS )
if ( true )
{
CallProceeding.m_multipleCalls = false;
}
EncodeH225IntoQ931( UUField, Proceeding );
WTRACE(2, "Q931\tSending CallProceed back to Caller");
SendMesgToDest( Proceeding, CallerSocket );
}
void SignallingThread::SendReleaseComplete( const Q931 & Mesg, WTCPSocket * Destination, Q931::CauseValues cause )
{
WTRACE(1, "Send ReleaseComplete");
Q931 Complete;
unsigned CallRef;
CallRef = Mesg.GetCallReference();
CallPool->ReadyToClose[CallRef] = true;
// Complete.BuildReleaseComplete( CallRef, Mesg.IsFromDestination() );
if (Destination == CallerSocket)
Complete.BuildReleaseComplete( CallRef, true );
else
Complete.BuildReleaseComplete( CallRef, false);
H225_H323_UserInformation UUField;
H225_H323_UU_PDU_h323_message_body & Body = UUField.m_h323_uu_pdu.m_h323_message_body;
Body.SetTag( H225_H323_UU_PDU_h323_message_body::e_releaseComplete );
H225_ReleaseComplete_UUIE & ReleaseComplete = Body;
// Set CallIdentifier
ReleaseComplete.IncludeOptionalField( H225_ReleaseComplete_UUIE::e_callIdentifier );
ReleaseComplete.m_callIdentifier = CallPool->CallIdent[CallRef];
// Set EndSessionCommand As in OhPhone
H245_MultimediaSystemControlMessage h245msg;
h245msg.SetTag(H245_MultimediaSystemControlMessage::e_command);
H245_CommandMessage & h245cmd = h245msg;
h245cmd.SetTag(H245_CommandMessage::e_endSessionCommand);
H245_EndSessionCommand & endcmd = h245cmd;
endcmd.SetTag(H245_EndSessionCommand::e_disconnect);
PPER_Stream wtstrm;
h245msg.Encode(wtstrm);
wtstrm.CompleteEncoding();
UUField.m_h323_uu_pdu.IncludeOptionalField( H225_H323_UU_PDU::e_h245Control );
UUField.m_h323_uu_pdu.m_h245Control.SetSize(1);
UUField.m_h323_uu_pdu.m_h245Control[0] = wtstrm;
// set CauseIE
Complete.SetCause( cause );
// Encode and send
EncodeH225IntoQ931( UUField, Complete );
WTRACE(5, Complete );
WTRACE(5, UUField );
SendMesgToDest( Complete, Destination );
}
void SignallingThread::HandleTunneledH245( H225_H323_UserInformation & UUField, unsigned CallRef, bool FromCaller )
// Handle tunneled H.245 messages in the given message (if any)
{
if (CallPool->MediaProxing[CallRef] == false)
{
return;
}
H225_H323_UU_PDU & UU_PDU = UUField.m_h323_uu_pdu;
if ( UU_PDU.HasOptionalField( H225_H323_UU_PDU::e_h245Control ) )
{
WTRACE(3, "H225\tHandleTunneledH245 from " << (FromCaller ? "Caller" : "Called"));
for( int i=0; i < UU_PDU.m_h245Control.GetSize(); ++i )
{
PPER_Stream Strm = UU_PDU.m_h245Control[i].GetValue();
H245_MultimediaSystemControlMessage H245Mesg;
H245Mesg.Decode( Strm );
MyH245Handler->HandleMesg( H245Mesg, CallRef, FromCaller );
// We should re-encode it here if we change it....
PPER_Stream strm_m;
H245Mesg.Encode( strm_m );
UU_PDU.m_h245Control[i].SetValue( strm_m );
} // for every H245 control
} // if there is any H245 control
}
void SignallingThread::HandleFastStart(H225_ArrayOf_PASN_OctetString & fastStart, bool FromCaller, unsigned CallRef)
{
if (CallPool->MediaProxing[CallRef] == false)
{
return;
}
for(int i = 0; i < fastStart.GetSize(); ++i) {
PPER_Stream strm = fastStart[i].GetValue();
H245_OpenLogicalChannel OpenLChannel;
OpenLChannel.Decode(strm);
WTRACE(3, "FastStart from " << (FromCaller ? "Caller" : "Called") << " index : " << i);
WTRACE_IF(5, (IncAddr == env.DebugSourceHost), "fastStart = " << OpenLChannel);
MyH245Handler->HandleOpenLogicalChannel(OpenLChannel, CallRef, FromCaller);
PPER_Stream strm_m;
OpenLChannel.Encode(strm_m);
WTRACE(5, "fastStart Changed = "<< OpenLChannel);
fastStart[i].SetValue( strm_m );
}
CallPool->SetfState(CallRef, TCallPool::FastStartResponse);
}
void SignallingThread::HandleFastStartAck(H225_ArrayOf_PASN_OctetString & fastStart, bool FromCaller, unsigned CallRef)
{
if (CallPool->MediaProxing[CallRef] == false)
{
return;
}
WTRACE ( 3, "HandleFastStartAck procced . Size is " << fastStart.GetSize() );
for(int i = 0; i < fastStart.GetSize(); ++i) {
PPER_Stream strm = fastStart[i].GetValue();
H245_OpenLogicalChannel OpenLChannel;
OpenLChannel.Decode(strm);
WTRACE(3, "FastStartAck from " << (FromCaller ? "Caller" : "Called") << " index : " << i);
WTRACE_IF(4, (IncAddr == env.DebugSourceHost), "fastStartAck = " << OpenLChannel);
MyH245Handler->HandleOpenLogicalChannel(OpenLChannel, CallRef, FromCaller);
PPER_Stream strm_m;
OpenLChannel.Encode(strm_m);
WTRACE(4, "fastStartAck Changed = "<< OpenLChannel);
fastStart[i].SetValue( strm_m );
}
CallPool->SetfState(CallRef, TCallPool::FastStartAcknowledged);
}
void SignallingThread::HandleFastStartAck(H225_ArrayOf_PASN_OctetString & fastStart, bool FromCaller, unsigned CallRef, H225_ArrayOf_PASN_OctetString DefferedFS)
{
if (CallPool->MediaProxing[CallRef] == false)
{
return;
}
int i;
PPER_Stream strm1, strm2;
WTRACE ( 3, "HandleFastStartAck with Defferd element procced . Size is " << fastStart.GetSize() );
for( i = 0; i < fastStart.GetSize(); ++i) {
PPER_Stream strm = fastStart[i].GetValue();
H245_OpenLogicalChannel OpenLChannel;
OpenLChannel.Decode(strm);
WTRACE(3, "FastStartAck from " << (FromCaller ? "Caller" : "Called") << " index : " << i);
WTRACE_IF(4, (IncAddr == env.DebugSourceHost), "fastStartAck = " << OpenLChannel);
MyH245Handler->HandleOpenLogicalChannel(OpenLChannel, CallRef, FromCaller);
PPER_Stream strm_m;
OpenLChannel.Encode(strm_m);
WTRACE(3, "fastStartAck Changed = "<< OpenLChannel);
fastStart[i].SetValue( strm_m );
}
/*
for( i = 0; i < DefferedFS.GetSize(); ++i) {
WTRACE ( 3, "Adding defferd FastStart element" );
fastStart.Append(&DefferedFS[i]);
}
j = 0;
if (! fastStart.SetSize(fastStart.GetSize() + DefferedFS.GetSize()))
Parent->env.Notify("Fail in new size assertion for Faststart" , "Call Ref =" + CallRef);
WTRACE ( 3, "FastStart size is " << fastStart.GetSize() );
for ( i = fastStart.GetSize(); i < fastStart.GetSize() + DefferedFS.GetSize(); ++i) {
WTRACE ( 3, "Adding defferd FastStart element. j=" << j << ", i=" << i);
fastStart[i].SetValue(DefferedFS[j].GetValue());
j++;
}
*/
CallPool->SetfState(CallRef, TCallPool::FastStartAcknowledged);
}
void SignallingThread::GetCallSignallingAddr( WSocket::Address & CallerAddr, WSocket::Address & CalledAddr, unsigned CallRef )
{
CallerSocket->GetPeerAddress(CallerAddr);
CallPool->OutCalledSocket[CallRef]->GetPeerAddress(CalledAddr);
}
void SignallingThread::GetCallSignallingAddr( in_addr & CallerAddr, in_addr & CalledAddr, unsigned CallRef )
{
WSocket::Address s1, s2;
CallerSocket->GetPeerAddress(s1);
CallPool->OutCalledSocket[CallRef]->GetPeerAddress(s2);
CallerAddr = s1;
CalledAddr = s2;
}
void SignallingThread::ClearCall(unsigned CallRef)
{
CallPool->ClearCall(CallRef);
if (CallPool->StartTime.empty() && CallPool->BillRecID.empty()) {
Close();
}
}
void SignallingThread::CheckTimeout()
{
map<unsigned, unsigned> st;
map<unsigned, unsigned>::iterator it;
st = CallPool->StartTime;
for (it = st.begin(); it != st.end(); it++)
{
if ( ! CallPool->CheckTimeout(it->first)) {
CallPool->StopAcctCall(it->first);
ClearCall(it->first);
}
}
}
bool SignallingThread::FE_IsAlready(const H225_ArrayOf_PASN_OctetString & FS1, const H225_ArrayOf_PASN_OctetString & FS2,
PPER_Stream & strm1, PPER_Stream & strm2)
{
int i, j;
for( i = 0; i < FS1.GetSize(); ++i) {
for( j = 0; j < FS2.GetSize(); ++j) {
if (FS1[i].GetValue() != FS2[j].GetValue() ) {
strm1 = FS1[i].GetValue();
strm2 = FS2[j].GetValue();
return false;
}
}
}
return true;
}
void SignallingThread::CheckTunneling(bool HasUU, H225_H323_UserInformation & UUField, bool & Tunnel)
{
if ( !HasUU )
return;
if ((UUField.m_h323_uu_pdu.HasOptionalField(H225_H323_UU_PDU::e_h245Tunneling) && UUField.m_h323_uu_pdu.m_h245Tunneling.GetValue()))
{
Tunnel = true;
WTRACE(3, "Tunneling is on");
}
else
{
Tunnel = false;
WTRACE(3, "Tunneling is off");
}
}
void SignallingThread::ShutdownCall(unsigned CallRef)
{
WTRACE(1, "Force shutting down call. CallRef = " << CallRef);
SendReleaseComplete( CallPool->SetupMsg[CallRef], CallerSocket, Q931::NormalCallClearing);
SendReleaseComplete( CallPool->SetupMsg[CallRef], CallPool->OutCalledSocket[CallRef], Q931::NormalCallClearing);
CallPool->ReadyToClose[CallRef] = true ;
if (CallPool->StopTime[CallRef] == 0)
{
CallPool->StopTime[CallRef] = time(NULL);
WTRACE(2, "Fixing of the moment of StopTime " << PTime(CallPool->StopTime[CallRef]) << ": CallRef=" << CallRef );
}
// StopAcct
CallPool->IncCDR[CallRef].StopTime = time(NULL);
CallPool->OutCDR[CallRef].StopTime = time(NULL);
CallPool->IncCDR[CallRef].IncOctets = CallPool->IncBytes[CallRef];
CallPool->IncCDR[CallRef].OutOctets = CallPool->OutBytes[CallRef];
CallPool->OutCDR[CallRef].IncOctets = CallPool->OutBytes[CallRef];
CallPool->OutCDR[CallRef].OutOctets = CallPool->IncBytes[CallRef];
CallPool->IncCDR[CallRef].InternalCause = TCallPool::ForceTermination;
CallPool->OutCDR[CallRef].InternalCause = TCallPool::ForceTermination;
CallPool->IncCDR[CallRef].Tunneling = (CallPool->IncCDR[CallRef].Tunneling ? 1 : 0 );
CallPool->OutCDR[CallRef].Tunneling = (CallPool->IncCDR[CallRef].Tunneling ? 1 : 0 );
CallPool->IncCDR[CallRef].FastStart = (CallPool->fStatesList[CallRef] != TCallPool::NoFastStart ? 1 : 0 );
CallPool->OutCDR[CallRef].FastStart = (CallPool->fStatesList[CallRef] != TCallPool::NoFastStart ? 1 : 0 );
if (mAuth->Routes.size() != 0) {
WTRACE(1, "StopAcct for " << CallPool->IncCDR[CallRef].CallID );
mAcct->StopAcct(CallPool->IncCDR[CallRef], CallPool->OutCDR[CallRef], TAcct::Both);
mAuth->Routes.clear();
}
}
void SignallingThread::ShutdownCalls(vector<string> & List)
{
unsigned int i;
SignallingThread * S = NULL;
unsigned CallRef;
for ( i = 0; i < List.size(); i++)
{
if (Parent->ClTbl->FindCall(List[i], S, CallRef) )
{
if ( S != NULL )
S->ShutdownCall(CallRef);
}
else
{
WTRACE(1, "Wrong CallId " << List[i] );
}
}
}
//////////////////////////////////
//
// TCallPool
//
//////////////////////////////////
TCallPool::TCallPool(const TGlobal & vEnv, SignallingThread * ParenSigThread)
: env(vEnv)
{
Parent = ParenSigThread;
}
TCallPool::~TCallPool()
{
Terminate();
}
bool TCallPool::NewMediaThread(unsigned CallRef)
{
bool created = false;
if (! MediaThreadList[CallRef] ) {
WTRACE(3, "Creating new MediaThread for call " << CallRef);
MediaThreadList[CallRef] = new MediaThread(env, Parent, CallRef);
created = true;
}
return created;
}
void TCallPool::StartMediaThread(unsigned CallRef)
{
MediaThreadList[CallRef]->Start();
WTRACE(1, "Starting media thread. CallRef " << CallRef);
}
void TCallPool::StopMediaThread(unsigned CallRef)
{
MediaThreadList[CallRef]->Stop();
}
void TCallPool::Terminate()
{
int status;
WTRACE(1,"CallPool terminate");
// Correct clering every existed call
map<unsigned, unsigned>::iterator it0;
vector<unsigned int> CallList;
unsigned int i;
for (it0 = BillRecID.begin(); it0 != BillRecID.end(); it0++ )
{
CallList.push_back(it0->first);
}
for (i=0; i < CallList.size(); i++ ) {
StopAcctCall(CallList[i]);
ClearCall(CallList[i]);
}
map<unsigned, MediaThread*>::iterator it;
for (it = MediaThreadList.begin(); it != MediaThreadList.end(); it++ )
{
WTRACE(1, "Stop command for threads in CallPool");
if (it->second != NULL) {
it->second->Stop();
delete it->second;
}
}
map<unsigned, H245Thread*>::iterator it2;
for (it2 = H245ThreadList.begin(); it2 != H245ThreadList.end(); it2++)
{
WTRACE(2, "Terminate every H245 thread in CallPool. CallRef=" << it2->first);
if (it2->second != NULL) {
it2 -> second -> SetStop();
if (pthread_join(H245ThreadID[it2->first], (void **)&status) != 0 )
{
WTRACE(0, "Error\terrno from pthread_join H245Thread = " << errno << ". Text = " << strerror(errno));
}
H245ThreadList[it2->first]->Close();
delete it2->second;
}
}
WTRACE(1,"Closing CalledSockets");
map<unsigned, WTCPSocket *>::iterator SockIt;
for (SockIt = OutCalledSocket.begin(); SockIt != OutCalledSocket.end(); SockIt++)
{
WTRACE(1, "Close every Socket. Callref = " << SockIt->first );
if (SockIt->second != NULL)
{
// if (! SockIt->second->IsOpen() )
SockIt->second->Close();
delete SockIt->second;
}
}
OutCalledSocket.clear();
MediaThreadList.clear();
H245ThreadList.clear();
CallList.clear();
}
bool TCallPool::BindRTPSockets(unsigned CallRef, WORD srcPort, WORD dstPort,
WSocket::Address & inAddr, WSocket::Address & outAddr )
{
UDPProxyLChannel* rtpch;
rtpch = MediaThreadList[CallRef]->getRTP_LCCh();
if ( rtpch == NULL )
{
WTRACE(1, "Error in resolve of rtpch for CallRef = " << CallRef);
return false;
}
if ( ! rtpch -> bindSockets(srcPort, dstPort, inAddr, outAddr) )
{
WTRACE(1,"Error" << endl << "Error in binding RTP channel. CallRef " << CallRef <<
", inAddr " << inAddr << " , outAddr " << outAddr);
return false;
}
WTRACE(3,"Binding RTP channel. CallRef " << CallRef << ", inAddr " << inAddr << " , outAddr " << outAddr);
return true;
}
bool TCallPool::BindRTCPSockets(unsigned CallRef, WORD srcPort, WORD dstPort,
WSocket::Address & inAddr, WSocket::Address & outAddr )
{
RTCPProxyChannel* rtcpch;
rtcpch = MediaThreadList[CallRef]->getRTCP_LCCh();
if ( rtcpch == NULL )
{
WTRACE(1, "Error in resolve of rtcpch for CallRef = " << CallRef);
return false;
}
if ( ! rtcpch -> bindSockets(srcPort, dstPort, inAddr, outAddr) )
{
WTRACE(1, "Error" << endl << "Error in binding RTCP channel. CallRef " << CallRef <<
", inAddr " << inAddr << " , outAddr " << outAddr);
return false;
}
WTRACE(3,"Binding RTCP channel. CallRef " << CallRef << ", inAddr " << inAddr << " , outAddr " << outAddr);
return true;
}
void TCallPool::SetControlChannel(unsigned CallRef, H245_TransportAddress & vAddr, bool FromCaller)
{
MediaThreadList[CallRef]->SetControlChannel(vAddr, FromCaller);
WTRACE(3,"SetControlChannel " << vAddr << " Ref " << CallRef);
}
void TCallPool::SetMediaChannel(unsigned CallRef, H245_TransportAddress & vAddr, bool FromCaller)
{
MediaThreadList[CallRef]->SetMediaChannel(vAddr, FromCaller);
WTRACE(3,"SetMediaChannel " << vAddr << " Ref " << CallRef);
}
void TCallPool::MediaThreadPrintOn(unsigned CallRef)
{
MediaThreadList[CallRef]->PrintOn();
}
bool TCallPool::IsMediaRunning(unsigned CallRef)
{
return MediaThreadList[CallRef]->IsRunning;
}
void TCallPool::SetMediaRunning(unsigned CallRef, bool val)
{
MediaThreadList[CallRef]->IsRunning = val;
}
void TCallPool::SetMediaChannelOpened(unsigned CallRef, bool FromCaller)
{
if (FromCaller)
MediaThreadList[CallRef]->InMediaChannelOpened = true;
else
MediaThreadList[CallRef]->OutMediaChannelOpened = true;
}
bool TCallPool::IsMediaChannelsOpened(unsigned CallRef)
{
if ( MediaThreadList[CallRef] == NULL)
return false;
return (MediaThreadList[CallRef]->InMediaChannelOpened && MediaThreadList[CallRef]->OutMediaChannelOpened);
}
void TCallPool::SetfState(unsigned CallRef, FastStartStates State)
{
fStatesList[CallRef] = State;
}
TCallPool::FastStartStates TCallPool::GetfState(unsigned CallRef)
{
if (fStatesList[CallRef] == 0 )
return NoFastStart;
return fStatesList[CallRef];
}
void TCallPool::EstablishedConnectionCheck(unsigned CallRef)
{
ConnectionStates connectionState = cStatesList[CallRef];
FastStartStates fastStartState = fStatesList[CallRef];
if ((connectionState == EstablishedConnection) || (connectionState == MediaRunning) || (connectionState == ShuttingDownConnection ) )
return;
WTRACE(6, "H323\tEstablishedConnectionCheck . connectionState = " << connectionState);
if (connectionState != HasExecutedSignalConnect) {
WTRACE(6, "H323\tEstablishedConnectionCheck : connectionState != HasExecutedSignalConnect" );
return;
}
bool h245_available;
if( fastStartState == NoFastStart)
h245_available = IsDetermined(CallRef) && HasCapabilities(CallRef) && IsMediaChannelsOpened(CallRef); // No needs
else
h245_available = IsDetermined(CallRef) && HasFullCapabilities(CallRef); //
if ( !Tunneling[CallRef] && (fastStartState == NoFastStart) )
h245_available = IsMediaChannelsOpened(CallRef);
WTRACE(5, endl << "IsDetermined " << IsDetermined(CallRef) << endl <<
"HasCapabilities" << HasCapabilities(CallRef) << endl <<
"IsChannelsOpened" << IsMediaChannelsOpened(CallRef) << endl <<
"Tunneling " << Tunneling[CallRef] << endl <<
"fastStartState" << fastStartState);
if (fastStartState != FastStartAcknowledged) {
if (!h245_available && MediaProxing[CallRef] == true ) {
WTRACE(2, "H323\tEstablishedConnectionCheck : !h245_available : FastStart is " << fastStartState);
return;
}
}
cStatesList[CallRef] = EstablishedConnection;
Parent->Parent->counters.calls++;
WSocket::Address CallerAddr, CalledAddr;
Parent->GetCallSignallingAddr( CallerAddr, CalledAddr, CallRef );
WTRACE( 1, "H323\tConnection between " << CallerAddr << " and "<<CalledAddr<< " esteblished. CallRef = "
<< CallRef << endl << endl);
Parent->mAcct->StartAcctTransit(IncCDR[CallRef], OutCDR[CallRef]);
Parent->Parent->ClTbl->IncCOC(CalledAddr);
Parent->Parent->ClTbl->IncCIC(CallerAddr);
StartTime[CallRef] = time(NULL);
IncCDR[CallRef].StartTime = time(NULL);
OutCDR[CallRef].StartTime = time(NULL);
}
bool TCallPool::IsDetermined(unsigned CallRef)
{
if (Determined[CallRef] == 0)
return false;
return ( Determined[CallRef] ) ;
}
void TCallPool::DeterminedSet(unsigned CallRef, bool val)
{
Determined[CallRef] = val;
}
bool TCallPool::HasCapabilities(unsigned CallRef)
{
return( OutCapability[CallRef] || InCapability[CallRef]);
}
void TCallPool::NewH245Thread(TGlobal & AkaEnviron, TCallPool * vCallPool, unsigned CallRef, const H225_TransportAddress & CalledAddress, bool FromCaller)
{
if (! H245ThreadList[CallRef] ) {
WTRACE(1, "Creating new H245Thread for call " << CallRef);
if ( ! StartH245Thread(H245ThreadID[CallRef], AkaEnviron, vCallPool, CallRef, CalledAddress, FromCaller) )
{
assert(false);
}
}
}
bool TCallPool::CheckTimeout(unsigned CallRef)
{
eTCause CallState = InternTC[CallRef];
int now = time (NULL);
WTRACE(3, "CheckTimout. State is : " << CallState);
if ( (CallState == TimeoutProceeding) && (now - Timeout[CallRef] > 30) ) {
WTRACE(1, "CheckTimout brakes call. State is TimeoutProceeding : Now = " << now << ": Timeout=" << Timeout[CallRef] << ": CallRef=" << CallRef );
return false;
}
if ( (CallState == TimeoutAlertingMsg) && (now - Timeout[CallRef] > 30) ) {
WTRACE(1, "CheckTimout brakes call. State is TimeoutAlerting : Now = " << now << ": Timeout=" << Timeout[CallRef] << ": CallRef=" << CallRef );
return false;
}
if ( (CallState == TimeoutConnectMsg) && (now - Timeout[CallRef] > 120) ) {
WTRACE(1, "CheckTimout brakes call. State is TimeoutConnectMsg : Now = " << now << ": Timeout=" << Timeout[CallRef] << ": CallRef=" << CallRef );
return false;
}
if ( (CallState == TimeoutRlsCaller) && (now - Timeout[CallRef] > 30) ) {
WTRACE(1, "CheckTimout brakes call. State is TimeoutRlsCaller : Now = " << now << ": Timeout=" << Timeout[CallRef] << ": CallRef=" << CallRef );
return false;
}
if ( (CallState == TimeoutRlsCalled) && (now - Timeout[CallRef] > 30) ) {
WTRACE(1, "CheckTimout brakes call. State is TimeoutRlsCalled : Now = " << now << ": Timeout=" << Timeout[CallRef] << ": CallRef=" << CallRef );
return false;
}
if ( (CallState == CallInProgress) && ((LastIncByte[CallRef] != 0 && now - LastIncByte[CallRef] > 180) ||
(LastOutByte[CallRef] != 0 && now - LastOutByte[CallRef] > 180))) {
WTRACE(1, "CheckTimout brakes call. State is TimeoutMedia : Now = " << now << ": LastIncByte=" << LastIncByte[CallRef] <<
": LastOutByte=" << LastOutByte[CallRef] << ": CallRef=" << CallRef );
InternTC[CallRef] = TimeoutMedia;
IncCDR[CallRef].InternalCause = TCallPool::TimeoutMedia;
OutCDR[CallRef].InternalCause = TCallPool::TimeoutMedia;
return false;
}
if (now - StartTime[CallRef] > 10800) {
InternTC[CallRef] = HungCall;
IncCDR[CallRef].InternalCause = TCallPool::HungCall;
OutCDR[CallRef].InternalCause = TCallPool::HungCall;
return false;
}
return true;
}
void TCallPool::StopAcctCall(unsigned CallRef)
{
}
void TCallPool::ClearCall(unsigned CallRef)
{
int status;
WTRACE(1, "ClearCall. CallRef=" << CallRef);
if ( MediaThreadList[CallRef] != NULL )
{
MediaThreadList[CallRef]->Stop();
delete MediaThreadList[CallRef];
MediaThreadList.erase(CallRef);
}
WTRACE(2, "Checkin for h245 erase");
if ( H245ThreadList[CallRef] != NULL )
{
WTRACE(2, "Terminate H245 thread. CallRef=" << CallRef);
H245ThreadList[CallRef] -> SetStop();
if (pthread_join(H245ThreadID[CallRef], (void **)&status) != 0 )
{
WTRACE(0, "Error\terrno from pthread_join H245Thread = " << errno << ". Text = " << strerror(errno));
}
H245ThreadList[CallRef]->Close();
delete H245ThreadList[CallRef];
H245ThreadList.erase(CallRef);
H245ThreadID.erase(CallRef);
}
if ( OutCalledSocket[CallRef] != NULL )
{
OutCalledSocket[CallRef] -> Close();
delete OutCalledSocket[CallRef];
OutCalledSocket.erase(CallRef);
}
OutCapability.erase(CallRef);
InCapability.erase(CallRef);
Tunneling.erase(CallRef);
BillRecID.erase(CallRef);
StartTime.erase(CallRef);
StopTime.erase(CallRef);
RTCPcount.erase(CallRef);
IncBytes.erase(CallRef);
OutBytes.erase(CallRef);
IncTC.erase(CallRef);
OutTC.erase(CallRef);
InternTC.erase(CallRef);
Timeout.erase(CallRef);
LastIncByte.erase(CallRef);
LastOutByte.erase(CallRef);
cStatesList.erase(CallRef);
fStatesList.erase(CallRef);
CalledNumber.erase(CallRef);
CallIdent.erase(CallRef);
Attempts.erase(CallRef);
Determined.erase(CallRef);
}
syntax highlighted by Code2HTML, v. 0.9.1