LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 889|回复: 1

有兴趣一起分析GNUgk 和GnomeMeeting的朋友进来看看

[复制链接]
发表于 2005-6-23 18:28:19 | 显示全部楼层 |阅读模式
最近不是很忙,也赶一把即时通讯的潮流,有兴趣的朋友可以跟帖讨论.现在把主要的问题分析一下. :hungry  ::
1, 首先能够将这个试验的环境搭配起来, 可以去www.gnugk.orgwww.gnomemeeting.org下载相应的软件和源代码下来. 编译或者安装(Linux发行版本的不同而异)
2, 配置GnuGK,使得本地(或者其他方式)的GnomeMeeting(或者ophone)能够登录.(关键是在GnuGK中对帐号的设置和管理)
3,下班了,晚上再说.对网络抓包分析, H323协议感兴趣的朋友可以和我一起研究,谢谢

一点介绍:

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);                                  //接受socket连接
#else
                ReadSocket(dynamic_cast(slist));
#endif
            }
            CleanUp();
        } else {
            CleanUp();
            ReadUnlock unlock(ConfigReloadMutex);                       //防止读取配置的V操作
            PTRACE(3, GetName() << " waiting...");
            Wait();
    }
}
以上只是GNUGK的一个最简单和最主要的执行过程,更多详细情况情参看源代码.
 楼主| 发表于 2005-6-27 22:15:19 | 显示全部楼层
分析进行了几天,看来坛子里人对这个兴趣不大,我和一个同事目前在研究,欢迎有这个方面基础和我们交流,谢谢
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表