6.2 SIP 会话

 SipSession 对象代表点到点的 SIP 关系, 无论是作为已经建立的对话, 或者一个对话实际建立之前的阶段. 可以通过调用一个 SipServletMessage 的 getSession 方法获到 SipSession 对象.

6.2.1 和 SIP 对话的关系.

一个 SipSession 既代表一个 RFC3261 中定义的处于其 earyly, confirmed 或者 terminated 状态的实际的 SIP 对话, 也可以代表一个虚假的对话. 虚假对话的概念扩展了对话的定义, 有两种定义的意思: RFC3261 中的一个对话建立之前以及在因为收到一个非 2xx 的最终回应而从 early 状态改变之后. SipSession 接口表现了这个虚假对话的概念, 正因为这样, 一些 SipSession 实例并不相当于一个 SIP 对话.

容器执行基于对话和事务状态约束上的 SIP 协议. 如何它在一个给定的状态上非法地发送一个消息, 容器会抛出一个 IllegalStateException 异常.

SIP 对话状态机.

图 6-1 中的"非定义"状态不是一个真正的状态. 对于 INVITE 结果创建的对话, 对话在收到带有 TO tag 的 1xx 或者 2xx 回应后存在.

SipSession 对象处于下面 4 种状态中的一种: INITIAL, EARLY, CONFIRMED 或者 TERMINATED. 这状态代表了可能和这个 SipSession 关联的 SIP 对话的状态. 在 SipSession 对话中定义的一个新方法允许应用程序可以访问对话的状态. SipSession 的状态不只是依赖于一个基本的 SIP对话的, 也依赖于 servlet 是否扮演了 UAC, UAS 或者代理的角色. 下面给定的是一个 SipSession 对象的状态管理的规则. 注意对于任何接收 SIP 消息引发的状态的改变, 容器都必须在调用处理收入消息的 SipServlet 的 service 方法之前就改变状态.

1. 对话在一个 SipSession 上创建的请求已接收到或发送了之前, SipSession 的状态定义为 INITIAL.
2. 一般来讲, 在任何时候一个非对话创建和接收请求, 都不会影响 SipSession 的状态. 同样的对一个非对话的请求的回应也不会影响会话的状态. 例外的是这个规则不适用于终结对话的请求(如 BYE,CANCEL).
3. 如果 Servlet 扮演 UAC 的角色并且发送了对话创建请求, 那么这个会话的状态就遵循 SIP 对话的状态机制, 除了在 EARLY 或者 INITIAL 状态收到一个非 2xx 的最终回应会使 SIP 会话的状态返回 INITIAL 状态而不是变成 TERMINATED 状态.
4. 如果 Servlet 扮演一个 UAS 并且收到了一个对话创建请求, 那么这个会话的状态直接遵循 SIP 对话状态机制. 不像一个 UAC, 一个非 2xx 最终回应直接使会话进入 TERMINATED 状态.
5. 如果这个 Servlet 扮演一个代理...

6. 因为设置 supervised 标记为 false 只影响于当前请求关联的事务是否会见到这个回应. 这个标记的值对于 SipSession 状态没有影响.

SipSession 接口中定义了可能的 SIP 对话的状态的枚举.
public enum SipSession.State {INITIAL, EARLY, CONFIRMED, TERMINATED }

下面的新方法是 SipSession 接口引进的用于返回当前的 SIP 对话状态:
public SipSession.State getState()

这个方法返回一个 SipSession.State enum 值. 这些值代表了当这个方法调用时这个 SipSession 相关的 SIP 对话的状态.

标准的 SIP 规则在当第二个或后发的回应...


6.2.1.1 取消消息处理
任何时候一个 servlet 扮演一个代理或者 UAS, 收到一个 CANCEL 请求本身不会导致 SIP 会话状态的改变. 不管怎样, 当收到一个 CANCEL请求导致 UAS 回复一个进行中的 INVITE 事务一个非 2xx 响应(487有不同), 这个会话回送给 UAC 一个非 2xx 最终回应的结果, 它的状态通常变为 TERMINATED.

6.2.2 维护 SIP 会话中的对话状态.

UA 在对话中使用 SipSession 的 createRequest 方法创建后续的请求. 这意味着容器必须在应用程序扮演一个 UA 时把 SipSessions 和 SIP 对话状态关联起来. RFC3261 中定义的对话由下面的数据组成: 本地/远程的 URI, 本地/远程的 Tag, 本地/远程的序号, 路由集, 远程对象 URI 以及 secure 标记.

6.2.2.1 当在一个对话中
对于一个应用程序扮演一个 UA, SipSession 必须遵循按照 RFC3261 定义的对话状态. 代理它们自己不能创建新的请求, 所以 SipSession.createRequest 发抛出一个 IllegalStateException 异常. 同样的, 扮演 UA 的应用程序创建的请求不可以被转发. 不管怎么说, getCallId, getLocalParty 以及 getRemoteParty 必须实现. getLocalParty 返回主叫的地址(对话的初始请求的 From 头域), getRemoteParty  返回被叫的地址. 这意味着 Call-ID, From 以及 To 必须关联属于任何应用状态的 proxy SIP 会话.

6.2.2.2 当处于 INITIAL SipSession 状态.
当一个 UAC 或者 UAS 事务从 early 状态到 initial 状态, SipSession 中维护的对话状态更新如下:
. 远程目标重置为远程 URI
. 远程 Tag 被清除
. 远程序号被清除
. 路由集被清除
. secure 标记被设置为 false.

对于这个规则的结果, 同样的 SipSession 创建的请求有下面的特征:
. 它们有同样的 Call-ID
. 它们有同样的 From 头域包话同样的非空的 tag
. 同样的 SipSession 创建的请求的 CSeq 会自动地以1递增.
. 所有 initial 状态的 SipSession 创建的请求有同样的 To 头域并且没有 tag 参数.
. Initial 状态的 SipSession 没有路由集. 远程序号没有定义, secure 标记为 false, 并且远程目标 URI 是 To 头域的值.

6.2.3 SipSession 的创建
SIP 对话和 SIP 会话之间最大的不同就是 SIP 请求可能在对话外存在(例如 OPTIONS 和 REGISTER), 而在 SIP Servlet API 中所有的消息都属于一个 SIP 会话.

SIP 对话是由收到一个可能创建对话的请求的非失败的回应创建的. 基本的 SIP 规范定义了一个这样的方法, 名叫 INVITE. 对话处理因....
这意味着一个单独的请求, 例如一个 INVITE, 可以被多个 UAS 接受, 这将导致创建多个对话. 在这种情况下,UAC SIP Servlet 会看到多个 SipSessions.

SIP 会话和 SIP 对话之间的关系总结如下:

...


何时创建一个 SipSession 的规则是:
. 本地通过 SipFactoryt.createRequest 创建一个初始的请求属于一个新的 SipSession.
. 到达的初始请求属于一个新的 SipSession.
. 对一个初始请求的回应不会创建一个对话, 而是属于"原始"请求的 SipSession.
. 建立一个 SIP 对话的第一个消息(例如, 对一个初始的 INVITE 的 2xx 回应) 和这个"原始"的请求相关所有其他消息属于那个对话.
. 后续的创建一个对话的消息和一个新的从原始的 SipSession 所得到的 SipSessoins 相关,.

当一个正在代理的应用程序收到一个回应关联一个新的 SipSession(也就是说. 因为会有对一个 INVITE 请求有第二个 2xx 回应, 那个回应的 getSession 方法返回一个新的得到的 SipSession. 原始的 SipSession 仍然可以通过原始的请求对象可用--它通过 Proxy 接口的 getOriginalRequest 方法可用.

6.2.3.1 扩展创建对话.
扩展基本的 SIP 规范可能定义附加的方法来建立对话. SIP 事件框架是这样的一个扩展. 在事件框架中, 一个初始 SUBSCRIGE 请求的 2xx 回应建立一个会话. 事实上, 一个匹配的 NOTIFY 请求在对 SUBSCRIBE 的 2xx 回应到达之前也将建立一个对话.

在其他 SIP 扩展介绍一个对话创建写在 RFC 3515 SIP REFER.

一个不明白一个扩展有建立对话能力的 SIP Servlet 容器必须创建一个新的得到的 SipSession 对象对第二个和后续的对话创建了发送一个单独的请求创建多个对话的能力.

6.2.3.2 衍生的 SipSessions
一个衍生的 SipSession 本质上是原始的请求相关的 SipSession 的复制. 在创建一个新的对话的消息传递到这个应用的时候构建的. 新的 SipSession 唯一的不同是被叫的地址的 tag 参数以及路由集. 这些值衍生于 SIP 规范定义的对话建立消息.

新的 SipSessions 相当于第二个或者后续的 2xx 回应(或者有 tag 参数的 1xx 回应) 通过 SipServletResponse 的 getSession 方法可用. 这个请求的原始的 SipSession 仍然通过原始的请求对象可用.

 

6.2.4 SipSession 生命周期

一般来说, SipSession 的生命周期可以由下面的方法控制:
1. 其父 SipApplicationSession 超时或者明确地失效了那么所有协议的子会话也会失效.
2. 应用程序使用 SipSession 的 invalidate() API 使明确的失效.
3. 应用程序标记 SipSession 为失效并且容器随后当这个会话进入 ready-to-invalidate 状态时使它失效了.

任何试图在一个失效的 SipSession 上获取或者存储数据会导致容器抛出一个 IllegalStateException.

当一个 SipSession 终止了, 不管是因为父应用会话超时了还是因为这个会话明确的失效了, 窗口必须从内存中清除所有这个状态的会话. 在这种情况下, 如果收到一个属地这个会话的后续的请求或者回应, 容器将随意地按下面的方法处理这个消息:

1. 通过发送一个 481 错误回应拒绝这个请求
2. 路由这个请求或者回应

很可能在同样的应用路径不同的应用实例有不同的生命周期. 容器处理一个对话的后续的请求和回应...

6.2.4.1 SipSession 失效
在两处情况下一个 SipSession 可以被失效.
1. 明确的失效机制
2. 当就绪时失效机制.

一旦一个 SipSession 对象被应用程序或者容器失效了, 它就不再有用了. 在失效方法中, 容器必须执行 SipSessionListener 接口实现的 sessionDestroyed 回调方法, 如果存在的话.

6.2.4.1.1 明确失效机制.
一个应用程序可以在任何时候使用 invalidate 方法失效一个 SipSession. 在明确失效中, 容器必须从内存中清除所有那个状态的 SipSession. 这些状态可能包括应用状态和容器状态像没有进行的事务.

调用一个已经失效的 SipSessoin 对象的 invalidate 方法会抛出一个 IllegalStateException 异常. 使用 invalidate 方法失效一个 SipSession 会导致父 SipApplicationSession 有更少的会话.

6.2.4.1.2 当就绪时失效机制.

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值