zoukankan      html  css  js  c++  java
  • [LCS]深入了解SipSnoop—事件篇

    write by PanQi@Ultrapower 

    摘要:SipSnoop用于监听Response和Request的SIP消息,是LCS2005自带的一款非常酷的应用程序,虽不及Ethereal强大,但也足以满足一般监听,本文将对其核心方法进行分析。



    l        
    知识点:
           [MSPL]内置变量sipRequestsipRequest变量包含了当前从Live Communications Server到应用程序的SIP请求消息。
           [MSPL]内置变量sipResponsesipResponse变量包含了当前从Live Communications Server到应用程序的SIP响应消息。
           [MSPL] Dispatch方法:Dispatch方法为应用程序的内部的事件处理者(event handler)分配一个事件。如果成功转发到指定的方法则返回真,否则返回否。
          
           [Microsoft.Rtc.Sip]RequestReceivedEventArgsRequestReceivedEventArgs类定义应用程序上关于到达的SIP请求信息。当一个请求成功的被MSPL消息过滤器分配时,一个包含RequestReceivedEventArgs对象签名的事件将被分配到指定的方法。
     
     
    l         深入了解SipSnoop
    1          提出问题:
    1.1         判断消息类型,针对不同消息类型分配不同的事件供给应用程序处理。
    1.2         应用程序截获并处理通过LCS的全部ResponseRequest消息。
    2          分析问题:
    2.1         判断SIP消息类型是通过MSPL的内置变量sipRequestsipResponse来完成。然后用MSPLDispatch方法分配不同的事件给托管代码来进行下一步处理。
    2.2         托管代码应用程序在处理MSPL分配的事件里实例化Response类和Resquest类,通过这两个对象可获取通过LCS的全部请求、响应消息。
    3          解决方案:
    SIP共有六种请求方法,分别是:INVITE(邀请);ACK(确认);OPTIONS(可选项);BYE(再见);CANCEL(取消);REGISTER(注册);SipSnoop的核心事件RequestHandlerResponseHandler中,结合哈希表统计了通过LCSSIP请求数量。下面针对这两个事件进行详细分析。
    3.1         截获并统计Request消息:
    3.1.1   MSPL分配的事件,触发RequestHandler事件处理者,该事件处理者有一个RequestReceivedEventArgs对象签名,通过这个对象签名的Request属性截获当前通过LCSRequest消息。代码如下:
    public void RequestHandler(object sender, RequestReceivedEventArgs e)
    {
        Request request 
    = e.Request;


     
    3.1.2   获取到通过LCSSIP请求消息后进行请求方式的判断,针对不同请求方式进行不同的处理,目的就是统计计数;对Request消息,针对INVITEACK进行了单独处理计数,其它方式采用Other方法计数。
    如果是INVITE的请求方式,说明该会话是首次建立,需要新建一个会话(Session)实例,并将会话的States(状态)属性赋值为Initializing,接下来,锁定哈希表sessionStateTableSyncRoot属性,确保线程安全,然后为哈希表sessionStateTablecallIdHeader.Value赋值。代码如下:

    if (request.StandardMethod == Request.StandardMethodType.Invite)
    {      
     
    ///extract the call-id and create session state
    Header callIdHeader = request.AllHeaders.FindFirst("Call-ID");
     
        
    if (callIdHeader != null)
        
    {
            Session newSession 
    = new Session();
            newSession.State 
    = Session.States.Initializing;
                                              
            
    lock (sessionStateTable.SyncRoot)
            
    {
                sessionStateTable[callIdHeader.Value] 
    = newSession;
            }

        }

    }
     


    如果请求方式为
    ACK,说明是确认请求,在报头中获取Call-ID,依靠得到的Call-ID,在哈希表sessionStateTable中寻找匹配的session,然后进行装箱转换成Session对象,接下来针对Session对象进行判断,如果该对象不为空的话会话状态赋值为Established,说明会话连接已确定,执行Update方法,以原子操作的形式递增指定变量totalSessionsactiveSessions的值并存储结果。代码如下:
     
    else if (request.StandardMethod == Request.StandardMethodType.Ack)
    {
     
                                       
    ///extract the call-id and update session state, ignore errors
                                       Header callIdHeader = request.AllHeaders.FindFirst("Call-ID");
     
                                       
    if (callIdHeader != null)
                                       
    {
                                              Session session 
    = sessionStateTable[callIdHeader.Value] as Session;
                                              
    if (session != null)
                                              
    {
                                                     session.State 
    = Session.States.Established;
                                                     statistics.Update(
    true /* new session */);
                                              }

           }

    }


    Update
    方法中递增指定变量的代码如下:
     

    public void Update(bool sessionEstablished)
                                
    {
                                       
    if (sessionEstablished)
                                       
    {
                                              Interlocked.Increment(
    ref totalSessions);
                                              Interlocked.Increment(
    ref activeSessions);
                                       }

                                       
    else
                                       
    {
                                              Interlocked.Decrement(
    ref activeSessions);
                                       }

    }


    如果在
    Request消息中有INVITEACK之外的请求方式,均采用一种方法计数,实现代码如下:
    statistics.Update(request.StandardMethod);
     
    3.1.3   获取完请求方式后,获取请求消息报头中的发送方和接受方,将其Update到哈希表userTable中,代码如下:
    Header fromHeader = request.AllHeaders.FindFirst("From"); 
    Header toHeader 
    = request.AllHeaders.FindFirst("To"); 
      
    statistics.Update(UriParser.GetUserAtHost(fromHeader.Value)); 
    statistics.Update(UriParser.GetUserAtHost(toHeader.Value)); 
    Update方法:
    public void Update(string user) 

        
    if  (user != null
        

            
    lock (userTable.SyncRoot) 
            

                userTable[user] 
    = user; 
            }
     
        }
     
    }
     

     


    至此,实现
    Request消息的获取及统计功能。
     
    3.2         截获并统计Response消息:
    SipSnoopResponse消息统计中针对请求方式Bye进行HashTableRemove操作,其它请求方式不采用哈希表,只计数;代码实现过程与Request类似,不再赘述。
     
     
     
    write by PanQi@Ultrapower 
    2005-6-9
  • 相关阅读:
    java面向对象
    java 继承
    .net的 http 请求 利用单例减少创建销毁的资源开销 提高利用率
    net core 3.1 swagger文档添加 不用xml配置
    vs code 配置 golang 环境
    .net 使用RabbitMQ demo
    Centos7 上安装配置 RabbitMQ
    C# .net 获取程序运行的路径的几种方法
    c# Windows服务应用程序的创建、安装和卸载
    XCOPY命令 windows 一个文件夹里的文件 快速移到另一个磁盘里
  • 原文地址:https://www.cnblogs.com/MyXQ/p/171319.html
Copyright © 2011-2022 走看看