/*************************************************************************************************************
分析Gatekeeper Main
*************************************************************************************************************/
void Gatekeeper::Main()
{
/**Get the programme arguments. Programme arguments are a set of strings
provided to the programme in a platform dependent manner.
@return
argument handling class instance.
*/
// PArgList & GetArguments();
PArgList & args = GetArguments(); //
//分析参数 返回PString
args.Parse(GetArgumentsParseString());
//
//如果定义的开发环境是Linux 执行如下代码
#ifdef P_LINUX
// set the core file size
if (args.HasOption("core")) {
struct rlimit rlim;
if (getrlimit(RLIMIT_CORE, &rlim) != 0)
cout << "Could not get current core file size : error = " << errno << endl;
else {
cout << "Current core dump size limits - soft: " << rlim.rlim_cur
<< ", hard: " << rlim.rlim_max << endl;
int uid = geteuid();
seteuid(getuid()); // Switch back to starting uid for next call
const PCaselessString s = args.GetOptionString("core");
rlim_t v = (s == "unlimited" ? RLIM_INFINITY : (rlim_t)s.AsInteger());
rlim.rlim_cur = v;
if (setrlimit(RLIMIT_CORE, &rlim) != 0)
cout << "Could not set current core file size to " << v << " : error = " << errno << endl;
else {
getrlimit(RLIMIT_CORE, &rlim);
cout << "New core dump size limits - soft: " << rlim.rlim_cur
<< ", hard: " << rlim.rlim_max << endl;
}
seteuid(uid);
}
}
#endif
///////////////////结束Linux代码
//如果定义了GK用户,设定用户
#ifdef HAS_SETUSERNAME
if (args.HasOption('u')) {
const PString username = args.GetOptionString('u');
if ( !SetUserAndGroup(username) ) {
cout << "GNU Gatekeeper could not run as user "
<< username
<< endl;
return;
}
}
#endif
//InitLogging设定日志为PTrace::DateAndTime 和 PTrace::TraceLevel
//如果存在参数 -o 则设定日志文件 函数为 SetLogFilename Gk.cxx line 797 注意要使用锁PWaitAndSignal,避免同时操作文件
//InitToolkit调用InstanceOf<Toolkit>(),即使用Toolkit的构造函数
/*********************************
template<class T> T *InstanceOf()
{
if (Singleton<T>::m_Instance == 0) {
PWaitAndSignal lock(Singleton<T>::m_CreationLock);
// We have to check it again after we got the lock
if (Singleton<T>::m_Instance == 0)
Singleton<T>::m_Instance = new T;
}
return Singleton<T>::m_Instance;
}
*********************************/
//Create ToolKit(1)
if(!InitLogging(args) || !InitToolkit(args))
return;
//如果参数存在 -h 选项,则输出选项,并退出GK
if (args.HasOption('h')) {
PrintOpts();
ExitGK();
}
//InitConfig从文件Gatekeeper.ini中读出配置文件信息,如果没有标志 42 则输出错误配置文件报告
//InitHandlers函数 如果定义了Win32环境,执行SetConsoleCtrlHandler,该函数选择WinCtrlHandlerProc作为第一个参数
//也是一个执行函数,用来处理CTRL + C表示用户强行退出
//这里InitConfig(args)调用InstanceOf<Toolkit>()->SetConfig(fp, section),SetConfig()调用ReloadConfig(),ReloadConfig()
//调用 InitTable(),InitTable()再调用 CreateTable(),然后继续InitTable()的剩下的部分,输出network..........等等信息
//继续ReloadConfig(),调用ProxyCriterion.LoadConfig(),输出日志GK/tH.323 Proxy disabled
//继续ReloadConfig(),调用m_GWRewrite.LoadConfig(m_Config),LoadConfig()调用PrintData();输出GK Loaded per GW rewrite data
//继续输出GK No per GW data loaded
if (!InitConfig(args) || !InitHandlers(args))
ExitGK();
//定义日志文件记录周期
EnableLogFileRotation();
//输出欢迎信息 此时 Toolkit已经作为singleton形式创建了
PString welcome("OpenH323 Gatekeeper - The GNU Gatekeeper with ID '" + Toolkit::GKName() + "' started/n" + Toolkit::GKVersion());
cout << welcome << '/n';
PTRACE(1, welcome);
//如果参数存在 -i选项,则设定GKHome地址为后面参数,这里如果设定的地址不存在GK,会输出Shutting down gatekeeper
//否则使用Toolkit中函数GetGKHome得到所有的地址,并输出 Listen on home
if (args.HasOption('i'))
Toolkit::Instance()->SetGKHome(args.GetOptionString('i').Lines());
vector<PIPSocket::Address> GKHome;
PString home(Toolkit::Instance()->GetGKHome(GKHome));
if (GKHome.empty()) {
cerr << "Fatal: Cannot find any interface to run GnuGK!/n";
ExitGK();
}
cout << "Listen on " << home << "/n/n";
// Copyright notice
//输出程序说明
cout <<
"This program is free software; you can redistribute it and/or/n"
"modify it under the terms of the GNU General Public License/n"
"as published by the Free Software Foundation; either version 2/n"
"of the License, or (at your option) any later version./n"
<< endl;
// read capacity from commandline
//设定GK的容量,如果存在参数 -b则从其中读出容量数,否则从全局参数中读出,如果数据 小于 0 ,则输出Disable Bandwidth Management
//否则设定 Available Bandwidth 为 GKcapacity值
int GKcapacity;
if (args.HasOption('b'))
GKcapacity = args.GetOptionString('b').AsInteger();
else
GKcapacity = GkConfig()->GetInteger("TotalBandwidth", -1);
//创建CallTable instance
CallTable::Instance()->SetTotalBandwidth(GKcapacity);
if (GKcapacity < 0)
cout << "/nDisable Bandwidth Management" << endl;
else
cout << "/nAvailable Bandwidth " << GKcapacity << endl;
// read timeToLive from command line
//设置TimeToLive选项
if (args.HasOption('l'))
SoftPBX::TimeToLive = args.GetOptionString('l').AsInteger();
else
SoftPBX::TimeToLive = GkConfig()->GetInteger("TimeToLive", -1);
PTRACE(2, "GK/tTimeToLive for Registrations: " << SoftPBX::TimeToLive);
//由于类RasServer从类Singleton继承而来,所以调用Singleton的Instance方法,创建RasServer的一个实例。
//因为设定路由模式定义在类RasServer中,所以这次定义 RasServer(3)的一个实例
RasServer *RasSrv = RasServer::Instance();
// read signaling method from commandline
//设置路由模式
if (args.HasOption('r'))
//调用RasServer::SetRoutedMode(),然后对HandlerList调用LoadConfig,HandlerList的LoadConfig()调用
//PortRange的LoadConfig,然后输出RTPPortRange: 1024-65535
//HandleList的LoadConfig()调用new ProxyHandler(psprintf("ProxyH(%d)", i)),ProxyHandler从SocketsReader继承过来
//SocketsReader从RegularJob继承过来,RegularJob从Job继承而来,
//ProxyHandler的构造函数执行Execute(),这里Execute()调用基类Job的Execute()方法,从而执行Agent::Instance()->Exec(this)
//创建Agent(4)
RasSrv->SetRoutedMode(true, (args.GetOptionCount('r') > 1 || args.HasOption("h245routed")));
else if (args.HasOption('d'))
RasSrv->SetRoutedMode(false, false);
else
RasSrv->SetRoutedMode();
//如果定义环境为WIN32 设定最大的等待退出时间 好允许 GK有充分的时间完成所有的退出操作
#if defined(_WIN32)
// 1) prevent CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT and CTRL_SHUTDOWN_EVENT
// dialog box from being displayed.
// 2) set process shutdown priority - we want as much time as possible
// for tasks, such as unregistering endpoints during the shut down process.
// 0x3ff is a maximimum permitted for windows app
SetProcessShutdownParameters(0x3ff, SHUTDOWN_NORETRY);
#endif
// let's go
RasSrv->Run();
//HouseKeeping();
// graceful shutdown
cerr << "/nShutting down gatekeeper . . . ";
ShutdownHandler();
cerr << "done/n";
#ifdef _WIN32
// remove control handler/close console
SetConsoleCtrlHandler((PHANDLER_ROUTINE)WinCtrlHandlerProc, FALSE);
FreeConsole();
#endif // _WIN32
}
/*************************************************************************************************************
分析RasServer Run
*************************************************************************************************************/
void RasServer::Run()
{
//初始化一些静态变量
/*
Kit = Toolkit::Instance(); Toolkit *RasMsg::Kit;
StatusPort = GkStatus::Instance(); GkStatus *RasMsg::StatusPort;//这里创建Create instance: GkStatus(5)
EndpointTbl = RegistrationTable::Instance(); RegistrationTable *RasMsg::EndpointTbl;//这里创建Create instance: RegistrationTable(6)
CallTbl = CallTable::Instance(); CallTable *RasMsg::CallTbl;
RasSrv = RasServer::Instance(); RasServer *RasMsg::RasSrv;
*/
RasMsg::Initialize();
RasPDU<H225_GatekeeperRequest>::Creator GRQCreator;
RasPDU<H225_GatekeeperConfirm>::Creator GCFCreator;
RasPDU<H225_GatekeeperReject>::Creator GRJCreator;
RegistrationRequestPDU::Creator RRQCreator;
RasPDU<H225_RegistrationConfirm>::Creator RCFCreator;
RasPDU<H225_RegistrationReject>::Creator RRJCreator;
RasPDU<H225_UnregistrationRequest>::Creator URQCreator;
RasPDU<H225_UnregistrationConfirm>::Creator UCFCreator;
RasPDU<H225_UnregistrationReject>::Creator URJCreator;
AdmissionRequestPDU::Creator ARQCreator;
RasPDU<H225_AdmissionConfirm>::Creator ACFCreator;
RasPDU<H225_AdmissionReject>::Creator ARJCreator;
RasPDU<H225_BandwidthRequest>::Creator BRQCreator;
RasPDU<H225_BandwidthConfirm>::Creator BCFCreator;
RasPDU<H225_BandwidthReject>::Creator BRJCreator;
RasPDU<H225_DisengageRequest>::Creator DRQCreator;
RasPDU<H225_DisengageConfirm>::Creator DCFCreator;
RasPDU<H225_DisengageReject>::Creator DRJCreator;
RasPDU<H225_LocationRequest>::Creator LRQCreator;
RasPDU<H225_LocationConfirm>::Creator LCFCreator;
RasPDU<H225_LocationReject>::Creator LRJCreator;
RasPDU<H225_InfoRequest>::Creator IRQCreator;
RasPDU<H225_InfoRequestResponse>::Creator IRRCreator;
RasPDU<H225_UnknownMessageResponse>::Creator UMRCreator;
RasPDU<H225_RequestInProgress>::Creator RIPCreator;
RasPDU<H225_ResourcesAvailableIndicate>::Creator RAICreator;
RasPDU<H225_ServiceControlIndication>::Creator SCICreator;
RasPDU<H225_ServiceControlResponse>::Creator SCRCreator;
// 创建TCPServer
listeners = new TCPServer;
//创建GkClient
gkClient = new GkClient;
//创建NeighborList
neighbors = new NeighborList;
//创建GkAuthenticatorList
authList = new GkAuthenticatorList;
//创建GkAcctLoggerList
acctList = new GkAcctLoggerList;
//闯将VirtualQueue
vqueue = new VirtualQueue;
//这里调用RasServer的LoadConfig()方法,记录日志GK Home
//并且调用GkInterface *gkif = CreateInterface(addr);
//if (gkif->CreateListeners(this))
// interfaces.push_back(gkif);
//然后CreateListeners(this)调用SetListener(rasPort, m_rasPort, m_rasListener, &GkInterface::CreateRasListener)
//调用SetListener(multicastPort, m_multicastPort, m_multicastListener, &GkInterface::CreateMulticastListener)
//调用SetListener(signalPort, m_signalPort, m_callSignalListener, &GkInterface::CreateCallSignalListener)
//调用SetListener(statusPort, m_statusPort, m_statusListener, &GkInterface::CreateStatusListener)
//调用GKInterface::CreateRasListener()方法
//该方法调用return new RasListener(m_address, m_rasPort);
//然后RasListener调用Listen(addr, 0, pt, PSocket::CanReuseAddress)
//由于RasListener从UDPSocket继承而来,UDPSocket为typedef YaUDPSocket UDPSocket,
//即RasListener调用YaUDPSocket的Listen方法,然后YaUDPSocket的Listen方法调用socket()方法,
//并且调用Bind(addr, pt),Bind()方法如下:
//这是UDP 1719端口
/************************************************************************************
bool YaSocket::Bind(const Address & addr, WORD pt)
{
if (IsOpen()) {
sockaddr_in inaddr;
memset(&inaddr, 0, sizeof(inaddr));
inaddr.sin_family = AF_INET;
inaddr.sin_addr.s_addr = addr;
inaddr.sin_port = htons(pt);
if (ConvertOSError(::bind(os_handle, (struct sockaddr *)&inaddr, sizeof(inaddr)))) {
socklen_t insize = sizeof(inaddr);
if (::getsockname(os_handle, (struct sockaddr *)&inaddr, &insize) == 0) {
port = ntohs(inaddr.sin_port);
return true;
}
}
}
return false;
}
************************************************************************************/
//然后SetListener调用ValidateSocket(listener, oport),然后输出Listening to port
//SetListener(signalPort, m_signalPort, m_callSignalListener, &GkInterface::CreateCallSignalListener)
//调用GkInterface::CreateCallSignalListener方法,该方法调用
//return m_rasSrv->IsGKRouted() ? new CallSignalListener(m_address, m_signalPort) : 0,也就是如果系统选择路由模式
//就new CallSignalListener(m_address, m_signalPort),这里CallSignalListener类从TCPListenSocket继承而来
//所有它的Listen方法是TCP的Listen,监听端口为1721
//调用SetListener(statusPort, m_statusPort, m_statusListener, &GkInterface::CreateStatusListener)
//方法调用GkInterface::CreateStatusListener,该方法调用
//return new StatusListener(m_address, m_statusPort),这里StatusListener也是从TCPListenSocket继承而来
//所以Listen方法是TCP的Listen,监听端口是7000
LoadConfig();
callptr nullcall;
//GKACCT Successfully logged event Line 984 GKAcct.cxx
acctList->LogAcctEvent(GkAcctLogger::AcctOn,nullcall);
if (m_socksize > 0) {
//这里调用RasServer函数HouseKeeping(),HouseKeeping下面分析
CreateJob(this, &RasServer::HouseKeeping, "HouseKeeping");
//这里是重点哦********************************
//因为RegularJob是SocketsReader的基类,而SocketsReader又是RasServer的基类
//所以这里可以调用RegularJob::Run()方法,这里我们来看一下Run方法的实现.
/*
void RegularJob::Run()
{
OnStart();
while (!m_stop)
Exec();
// lock to allow a member function that is calling Stop
// return before OnStop is called and the object is deleted
PWaitAndSignal lock(m_deletionPreventer);
OnStop();
}
*/
//上面的Run()方法调用了基类的纯虚函数Exec(),SocketsReader从RegularJob继承而来,而在SocketsReader类里面实现了Exec()方法
/*
void SocketsReader::Exec()
{
ReadLock cfglock(ConfigReloadMutex);
SocketSelectList slist(GetName());
if (BuildSelectList(slist)) {
if (SelectSockets(slist)) {
int ss = slist.GetSize();
for (int i = 0; i < ss; ++i)
#ifdef LARGE_FDSET
ReadSocket(slist[i]);
#else
ReadSocket(dynamic_cast<IPSocket *>(slist[i]));
#endif
}
CleanUp();
} else {
CleanUp();
ConfigReloadMutex.EndRead();
PTRACE(6, GetName() << " waiting...");
Wait(SOCKETSREADER_IDLE_TIMEOUT);
ConfigReloadMutex.StartRead();
}
}
*/
//上面的ReadSocket(slist[i])及ReadSocket(dynamic_cast<IPSocket *>(slist[i])),
//ReadSocket参考RasSrv.cxx 1254行,然后ReadSocket调用RasListener类的ReadRas()方法
//然后ReadRas()方法调用GatekeeperMessage类的Read()方法,
//然后Read()方法如下:
/*
bool GatekeeperMessage::Read(RasListener *socket)
{
m_socket = socket;
const int buffersize = 4096;
BYTE buffer[buffersize];
if (!socket->Read(buffer, buffersize)) {
PTRACE(1, "RAS/tRead error " << socket->GetErrorCode(PSocket::LastReadError)
<< '/' << socket->GetErrorNumber(PSocket::LastReadError) << ": "
<< socket->GetErrorText(PSocket::LastReadError)
);
return false;
}
socket->GetLastReceiveAddress(m_peerAddr, m_peerPort);
PTRACE(2, "RAS/tRead from " << m_peerAddr << ':' << m_peerPort);
m_rasPDU = PPER_Stream(buffer, socket->GetLastReadCount());
bool result = m_recvRAS.Decode(m_rasPDU);
PTRACE_IF(1, !result, "RAS/tCould not decode message from " << m_peerAddr << ':' << m_peerPort);
return result;
}
*/
RegularJob::Run();
}
acctList->LogAcctEvent(GkAcctLogger::AcctOff,nullcall);
}
//******************************************HouseKeeping******************************************//
void RasServer::HouseKeeping()
{
#if PTRACING
PTime startUp;
#endif
//IsRunning()调用RegularJob类得IsRunning()方法表示程序仍在运行
for (unsigned count = 0; IsRunning(); ++count)
if (!Wait(1000)) {
if( !IsRunning() )
break;
ReadLock lock(ConfigReloadMutex);
if (!(count % 60)) // one minute
//每分钟检测一下EndPoints 函数实现如下
RegistrationTable::Instance()->CheckEndpoints();
//CallTable检查通话连接,下面讨论
CallTable::Instance()->CheckCalls(this);
gkClient->CheckRegistration();
Toolkit::Instance()->GetTimerManager()->CheckTimers();
}
}
//**********************************CheckEndPoints****************************************************//
void RegistrationTable::CheckEndpoints()
{
PTime now;
WriteLock lock(listLock);
iterator Iter = EndpointList.begin(), eIter = EndpointList.end();
while (Iter != eIter) {
iterator i = Iter++;
EndpointRec *ep = *i;
//Gatekeeper 送出一個 InfoRequest (IRQ) 詢問某一端點是否仍存活著。
//如果該端點仍活著的話,應立即回應一個 InfoRequestResponse (IRR)。
//这里如果Isupdated返回false或者SendIRQ()返回false
//
/*
bool EndpointRec::SendIRQ()
{
if (m_pollCount <= 0 || GetRasAddress().GetTag() != H225_TransportAddress::e_ipAddress)
return false;
--m_pollCount;
RasServer *RasSrv = RasServer::Instance();
H225_RasMessage ras_msg;
ras_msg.SetTag(H225_RasMessage::e_infoRequest);
H225_InfoRequest & irq = ras_msg;
irq.m_requestSeqNum.SetValue(RasSrv->GetRequestSeqNum());
irq.m_callReferenceValue.SetValue(0); // ask for each call
PString msg(PString::Printf, "IRQ|%s|%s;/r/n",
(const unsigned char *) AsDotString(GetRasAddress()),
(const unsigned char *) GetEndpointIdentifier().GetValue());
GkStatus::Instance()->SignalStatus(msg, STATUS_TRACE_LEVEL_RAS);
RasSrv->SendRas(ras_msg, GetRasAddress());
return true;
}
*/
if (!ep->IsUpdated(&now) && !ep->SendIRQ()) {
/*
void SoftPBX::DisconnectEndpoint(const endptr &ep)
{
if (!ep) {
PString msg("SoftPBX: no endpoint to disconnect!");
PTRACE(1, "GK/t" + msg);
GkStatus::Instance()->SignalStatus(msg + "/r/n");
return;
}
callptr Call;
// remove all calls of ep
while (Call = CallTable::Instance()->FindCallRec(ep)) {
Call->Disconnect();
CallTable::Instance()->RemoveCall(Call);
}
}
*/
SoftPBX::DisconnectEndpoint(endptr(ep));
/*
EndpointRec *EndpointRec::Expired()
{
//发送unregistration Request
SendURQ(H225_UnregRequestReason::e_ttlExpired);
return this;
}
*/
ep->Expired();
//RemovedList中压入该endpoint
RemovedList.push_back(ep);
//EndpointList移出
EndpointList.erase(i);
//注册数量减少
--regSize;
PTRACE(2, "Endpoint " << ep->GetEndpointIdentifier().GetValue() << " expired.");
}
}
Iter = partition(OuterZoneList.begin(), OuterZoneList.end(),
bind2nd(mem_fun(&EndpointRec::IsUpdated), &now));
#if PTRACING
if (ptrdiff_t s = distance(Iter, OuterZoneList.end()))
PTRACE(2, s << " outerzone endpoint(s) expired.");
#endif
copy(Iter, OuterZoneList.end(), back_inserter(RemovedList));
OuterZoneList.erase(Iter, OuterZoneList.end());
// Cleanup unused EndpointRec in RemovedList
Iter = partition(RemovedList.begin(), RemovedList.end(), mem_fun(&EndpointRec::IsUsed));
DeleteObjects(Iter, RemovedList.end());
RemovedList.erase(Iter, RemovedList.end());
}
//************************************CheckCalls***************************************************//
void CallTable::CheckCalls(
RasServer* rassrv
)
{
std::list<callptr> m_callsToDisconnect;
std::list<callptr> m_callsToUpdate;
time_t now;
{
WriteLock lock(listLock);
iterator Iter = CallList.begin(), eIter = CallList.end();
now = time(0);
while (Iter != eIter) {
if ((*Iter)->IsTimeout(now))
m_callsToDisconnect.push_back(callptr(*Iter));
else if (m_acctUpdateInterval && (*Iter)->IsConnected()) {
if((now - (*Iter)->GetLastAcctUpdateTime()) >= m_acctUpdateInterval)
m_callsToUpdate.push_back(callptr(*Iter));
}
Iter++;
}
//这里使用STL 算法 partition,是因为它是一个非常快速的算法,可以将满足CallRec::IsUsed函数的对象
//排到Iter后面.
Iter = partition(RemovedList.begin(), RemovedList.end(), mem_fun(&CallRec::IsUsed));
DeleteObjects(Iter, RemovedList.end());
RemovedList.erase(Iter, RemovedList.end());
}
//下面的算法移出所有需要Disconnect的Calls
std::list<callptr>::iterator call = m_callsToDisconnect.begin();
while (call != m_callsToDisconnect.end()) {
(*call)->SetDisconnectCause((*call)->IsConnected()
? Q931::ResourceUnavailable : Q931::TemporaryFailure
);
(*call)->SetReleaseSource(CallRec::ReleasedByGatekeeper);
(*call)->Disconnect();
RemoveCall((*call));
call++;
}
//下面的算法Update所有需要被update的Calls
call = m_callsToUpdate.begin();
while (call != m_callsToUpdate.end()) {
if ((*call)->IsConnected())
//更新*call
/*********************************************************************************
bool GkAcctLoggerList::LogAcctEvent(
GkAcctLogger::AcctEvent evt, /// the accounting event to be logged
const callptr& call, /// a call associated with the event (if any)
time_t now /// "now" timestamp for accounting update events
)
{
// if this is an accounting update, check the interval
if (evt & GkAcctLogger::AcctUpdate)
if ((!call) || m_acctUpdateInterval == 0
|| (now - call->GetLastAcctUpdateTime()) < m_acctUpdateInterval)
return true;
else
call->SetLastAcctUpdateTime(now);
bool finalResult = true;
GkAcctLogger::Status status = GkAcctLogger::Ok;
std::list<GkAcctLogger*>::const_iterator iter = m_loggers.begin();
while (iter != m_loggers.end()) {
GkAcctLogger* logger = *iter++;
if ((evt & logger->GetEnabledEvents() & logger->GetSupportedEvents()) == 0)
continue;
status = logger->Log(evt, call);
switch (status)
{
case GkAcctLogger::Ok:
#if PTRACING
if (PTrace::CanTrace(3)) {
ostream& strm = PTrace::Begin(3,__FILE__,__LINE__);
strm << "GKACCT/t" << logger->GetName() << " logged event " << evt;
if (call)
strm << " for call no. " << call->GetCallNumber();
PTrace::End(strm);
}
#endif
break;
default:
#if PTRACING
if (PTrace::CanTrace(3)) {
ostream& strm = PTrace::Begin(3, __FILE__, __LINE__);
strm << "GKACCT/t" << logger->GetName() << " failed to log event "
<< evt;
if (call)
strm << " for call no. " << call->GetCallNumber();
PTrace::End(strm);
}
#endif
// required and sufficient rules always determine
// status of the request
if (logger->GetControlFlag() == GkAcctLogger::Required
|| logger->GetControlFlag() == GkAcctLogger::Sufficient)
finalResult = false;
}
// sufficient and alternative are terminal rules (on log success)
if (status == GkAcctLogger::Ok
&& (logger->GetControlFlag() == GkAcctLogger::Sufficient
|| logger->GetControlFlag() == GkAcctLogger::Alternative))
break;
}
// a last rule determine status of the the request
if (finalResult && status != GkAcctLogger::Ok)
finalResult = false;
#if PTRACING
if (PTrace::CanTrace(2)) {
ostream& strm = PTrace::Begin(2, __FILE__, __LINE__);
strm << "GKACCT/t" << (finalResult ? "Successfully logged event "
: "Failed to log event ") << evt;
if (call)
strm << " for call no. " << call->GetCallNumber();
PTrace::End(strm);
}
#endif
return finalResult;
}
*********************************************************************************/
rassrv->LogAcctEvent(GkAcctLogger::AcctUpdate, *call, now);
call++;
}
}