GNUGK是建立在Openh323和PWlib基础上的开源项目,支持OpenSSL,MySQL,OpenLDAP和FreeRADIUS,并且可以穿越防火墙和NAT.实际上GateKeeper已经成为H.323网络的核心部分,整个网络都由它掌控,而GNUGK几乎又是GateKeeper的业界标准,所以研究Openh323的同时了解GNUGK的原理和实现也是很有必要的。 GNUGK是由Jan Willamowius说领导开发,不同于Openh323的开发小组,它采用标准的c++编写,可实现跨平台编译,不过和Openh323不同的是GNUGK大量采用了C++的STL技术,比如模板和向量等等...,所以建议在看GNUGK前好好学习PWlib,Openh323和STL,这样才能为以后的学习打下坚实的基础。 废话不多讲,我们上路吧。 此处我用的是从CVS上Update的最新的GNUGK和Pandora的PWlib和Openh323.和每个基于PWlib的程序一样,首先从PProcess派生出一个GateKeeper类,程序就从GateKeeper::Main()开始。 void Gatekeeper::Main() { PArgList & args = GetArguments(); //获得命令行参数 args.Parse(GetArgumentsParseString()); //解析各个参数
#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
if(!InitLogging(args) || !InitToolkit(args)) //InitLogging对日志和跟踪(Trace)进行初始化 return; //InitToolkit
if (args.HasOption('h')) { //如果包含命令行参数'h' PrintOpts(); //显示帮助信息 ExitGK(); //停止Log和Trace,删除Toolkit并退出 }
if (!InitConfig(args) || !InitHandlers(args))//InitConfig读取INI配置文件 ExitGK(); //InitHandlers设置Ctrl+C停止热键
EnableLogFileRotation(); //开始记录日志 PString welcome("OpenH323 Gatekeeper - The GNU Gatekeeper with ID '" + Toolkit::GKName() + "' started\n" + Toolkit::GKVersion()); cout << welcome << '\n'; PTRACE(1, welcome);
if (args.HasOption('i')) //使用自定义的IP地址 Toolkit::Instance()->SetGKHome(args.GetOptionString('i').Lines());
std::vector GKHome; //遍历本机所有IP地址 PString home(Toolkit::Instance()->GetGKHome(GKHome));//home为本机的所有IP地址 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 int GKcapacity; //GK的带宽总容量 if (args.HasOption('b')) GKcapacity = args.GetOptionString('b').AsInteger(); else GKcapacity = GkConfig()->GetInteger("TotalBandwidth", -1); CallTable::Instance()->SetTotalBandwidth(GKcapacity); //限制带宽 if (GKcapacity < 0) cout << "\nDisable Bandwidth Management" << endl; else cout << "\nAvailable Bandwidth " << GKcapacity << endl;
// read timeToLive from command line 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 *RasSrv = RasServer::Instance(); //RasServer是核心,定义GK各种操作
// read signaling method from commandline if (args.HasOption('r')) //设置路由模式 RasSrv->SetRoutedMode(true, (args.GetOptionCount('r') > 1 || args.HasOption("h245routed"))); else if (args.HasOption('d')) RasSrv->SetRoutedMode(false, false); else RasSrv->SetRoutedMode();
#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 }
void RasServer::Run() { RasMsg::Initialize(); //Ras消息类的初始化 //RasPDU是一个模板类 RasPDU::Creator GRQCreator; //网守搜寻请求 RasPDU::Creator GCFCreator; //网守搜寻证实 RasPDU::Creator GRJCreator; //网守搜寻拒绝 RegistrationRequestPDU::Creator RRQCreator; //端点登记请求 RasPDU::Creator RCFCreator; //端点登记证实 RasPDU::Creator RRJCreator; //端点登记拒绝 RasPDU::Creator URQCreator; //登记注销请求 RasPDU::Creator UCFCreator; //登记注销证实 RasPDU::Creator URJCreator; //登记注销拒绝 AdmissionRequestPDU::Creator ARQCreator; //呼叫接受请求 RasPDU::Creator ACFCreator; //呼叫接受证实 RasPDU::Creator ARJCreator; //呼叫接受拒绝 RasPDU::Creator BRQCreator; //带宽管理请求 RasPDU::Creator BCFCreator; //带宽管理证实 RasPDU::Creator BRJCreator; //带宽管理拒绝 RasPDU::Creator DRQCreator; //呼叫退出请求 RasPDU::Creator DCFCreator; //呼叫退出证实 RasPDU::Creator DRJCreator; //呼叫退出拒绝 RasPDU::Creator LRQCreator; //端点定位请求 RasPDU::Creator LCFCreator; //端点定位证实 RasPDU::Creator LRJCreator; //端点定位拒绝 RasPDU::Creator IRQCreator; //状态查询请求 RasPDU::Creator IRRCreator; //状态查询证实 RasPDU::Creator UMRCreator; //未知消息 RasPDU::Creator RIPCreator; //延长对方等待时间 RasPDU::Creator RAICreator; //网关资源指示 RasPDU::Creator SCICreator; //服务控制标识 RasPDU::Creator SCRCreator; //服务控制反应
listeners = new TCPServer; //执行处理所有TCP连接请求 gkClient = new GkClient(this); //处理GK注册请求 neighbors = new NeighborList; //相邻网守列表 authList = new GkAuthenticatorList; //认证用户列表 acctList = new GkAcctLoggerList; //帐户日志列表 vqueue = new VirtualQueue; //用别名呼叫队列
LoadConfig();
callptr nullcall; acctList->LogAcctEvent(GkAcctLogger::AcctOn,nullcall);//开始记录每个帐号的事件 if (m_socksize > 0) { //m_socksize是socket的数量 CreateJob(this, &RasServer::HouseKeeping, "HouseKeeping");//检查注册和通话是否超时 RegularJob::Run(); //循环执行SocketsReader::Exec() } acctList->LogAcctEvent(GkAcctLogger::AcctOff,nullcall); } void SocketsReader::Exec() { ReadLock cfglock(ConfigReloadMutex); //防止读取配置的P操作 SocketSelectList slist;
if (BuildSelectList(slist)) { //建立select列表 if (SelectSockets(slist)) { int ss = slist.GetSize(); for (int i = 0; i < ss; ++i) #ifdef LARGE_FDSET //最大socket数目,作者重新定义了fd_set数据结构 ReadSocket(slist[i]); //接受socket连接 #else ReadSocket(dynamic_cast(slist[i])); #endif } CleanUp(); } else { CleanUp(); ReadUnlock unlock(ConfigReloadMutex); //防止读取配置的V操作 PTRACE(3, GetName() << " waiting..."); Wait(); } } 以上只是GNUGK的一个最简单和最主要的执行过程,更多详细情况情参看源代码. 
|