/*
* 
* 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