12. 对话
12 对话
用户代理的一个关键概念是对话.对话表示两个用户代理之间持续一段时间的对等SIP关系.该对话有助于对用户代理之间的消息进行排序,并在两者之间正确路由请求.该对话表示用于解释SIP消息的上下文.第8节讨论了对话外部请求和响应的独立于方法的UA处理.本节讨论如何使用这些请求和响应构建对话,以及如何在对话中发送后续请求和响应.
每个UA上都有一个对话ID,该ID由Call-ID值,本地标记和远程标记组成.对话中涉及的每个UA的对话ID不相同.具体地说,一个UA处的本地标签与对等UA处的远程标签相同.标记是不透明的标记,有助于生成唯一的对话ID.
对话ID还与所有响应以及"收件人"字段中包含标记的任何请求相关联.计算消息对话ID的规则取决于SIP元素是UAC还是UAS.对于UAC,对话ID的Call-ID值设置为消息的Call-ID,远程标记设置为消息的to字段中的标记,本地标记设置为From字段中的标记
消息字段(这些规则适用于请求和响应).正如人们对UAS的期望,对话ID的Call-ID值设置为消息的Call-ID,远程标记设置为消息的From字段中的标记,本地标记设置为消息的to字段中的标记.
对话包含在对话中进一步传输消息所需的某些状态.该状态由对话ID,本地序列号(用于对从UA到其对等方的请求进行排序),远程序列号(用于对从其对等方到UA的请求进行排序),本地URI,远程URI,远程目标,称为"安全"的布尔标志和路由集组成,路由集是URI的有序列表.路由集是向对等方发送请求时需要遍历的服务器列表.对话也可以处于"早期"状态,这在使用临时响应创建对话时发生,然后在2xx最终响应到达时转换为"已ACK"状态.对于其他响应,或者如果该对话上根本没有响应,则早期对话将终止.
12.1 创建对话
对话是通过使用特定方法生成对请求的无故障响应来创建的.在本规范中,只有2xx和101-199带有To标记的响应(请求被INVITE的位置)将建立一个对话.由请求的非最终响应建立的对话处于"早期"状态,称为早期对话.扩展可以定义创建对话的其他方法.第13节给出了INVITE方法特有的更多细节.这里,我们描述了创建不依赖于方法的对话状态的过程.
UAs必须为对话ID组件分配值,如下所述.
12.1.1 UAS行为
当UAS使用建立对话的响应(如2xx to INVITE)响应请求时,UAS必须将所有Record-Route头字段值从请求复制到响应中(包括URI,URI参数和任何Record-Route头字段参数,无论UAS是否知道)并且必须保持这些值的顺序.UAS必须在响应中添加Contact 头字段.Contact header字段包含一个地址,在该地址中,UAS希望在对话中的后续请求中与之联系(如果是INVITE,则包括2xx响应的ACK).通常,此URI的主机部分是主机的IP地址或FQDN.Contact 头字段中提供的URI必须是SIP或SIPS URI.如果启动对话的请求包含
Request-URI或顶部Record-Route头字段值中的SIPS URI(如果有)或Contact 头字段(如果没有Record-Route头字段),响应中的Contact 头字段必须是SIPS URI.URI应该具有全局作用域(也就是说,在该对话之外的消息中可以使用相同的URI).同样,INVITE的Contact header字段中URI的范围也不限于此对话.因此,即使在该对话之外,也可以在发送给UAC的消息中使用它.
然后UAS构建对话的状态.此状态必须在对话期间保持.
如果请求通过TLS到达,并且Request-URI包含SIPS URI,"安全"标志设置为TRUE.
路由集必须设置为来自请求的Record route header字段中的URI列表,按顺序排列并保留所有URI参数.如果请求中不存在Record-Route头字段,则必须将路由集设置为空集.此路由集即使为空,也会覆盖此对话中未来请求的任何预先存在的路由集.远程目标必须从请求的Contact header字段设置为URI.
远程序列号必须设置为请求的CSeq头字段中的序列号值.本地序列号必须为空.对话ID的调用标识符组件必须设置为请求中Call-ID的值.对话ID的本地标记组件必须设置为请求响应中"收件人"字段中的标记(始终包含标记),而对话ID的远程标记组件必须设置为请求中"发件人"字段中的标记.UAS必须准备好接收From字段中没有标记的请求,在这种情况下,标记的值被视为null.
这是为了保持与RFC 2543的向后兼容性,RFC 2543没有强制使用标签.
远程URI必须设置为"发件人"字段中的URI,本地URI必须设置为"收件人"字段中的URI.
12.1.2 UAC行为
当UAC发送可建立对话(如INVITE)的请求时,它必须在请求的Contact 头字段中提供具有全局作用域的SIP或SIPS URI(即,相同的SIP URI可用于此对话之外的消息).如果请求具有Request-URI或具有SIPS URI的最顶端路由头字段值,则Contact 头字段必须包含SIPS URI.
当UAC收到建立对话的响应时,它将构造对话的状态.此状态必须在对话期间保持.
如果请求通过TLS发送,并且Request-URI包含SIPS URI,"安全"标志设置为TRUE.
路由集必须设置为响应中Record-Route头字段中的URI列表,按相反顺序进行,并保留所有URI参数.如果响应中不存在Record-Route头字段,则必须将路由集设置为空集.此路由集即使为空,也会覆盖此对话中未来请求的任何预先存在的路由集.远程目标必须从响应的Contact header字段设置为URI.
必须将本地序列号设置为请求的CSeq头字段中的序列号值.远程序列号必须为空(它是在远程UA在对话中发送请求时建立的).对话ID的调用标识符组件必须设置为请求中Call-ID的值.对话ID的本地标记组件必须设置为请求的"发件人"字段中的标记,而对话ID的远程标记组件必须设置为响应的"收件人"字段中的标记.UAC必须准备好接收到to字段中没有标记的响应,在这种情况下,标记的值被视为null.
这是为了保持与RFC 2543的向后兼容性,RFC 2543不强制使用标签.
远程URI必须设置为"收件人"字段中的URI,本地URI必须设置为"发件人"字段中的URI.
12.2 对话中的请求
一旦两个UAs之间建立了对话,其中任何一个都可以根据需要在对话中启动新的事务.发送请求的UA将担任事务的UAC角色.接收请求的UA将担任UAS角色.请注意,这些角色可能与建立对话的交易期间持有的UAs不同.
对话中的请求可能包含Record-Route和Contact 头字段.但是,这些请求不会导致修改对话的路由集,尽管它们可能会修改远程目标URI.具体来说,不是目标刷新请求的请求不会修改对话的远程目标URI,而作为目标刷新请求的请求会修改对话的远程目标URI.对于已使用
INVITE,唯一定义的目标刷新请求是REINVITE(请参阅第14节).其他扩展可以为以其他方式建立的对话定义不同的目标刷新请求.
请注意,ACK不是目标刷新请求.
目标刷新请求仅更新对话的远程目标URI,而不更新从Record-Route形成的路由集.更新后者将导致RFC 2543兼容系统出现严重的向后兼容性问题.
12.2.1 UAC行为
12.2.1.1 生成请求
对话中的请求是通过使用作为对话一部分存储的状态的许多组件来构造的.
请求的"收件人"字段中的URI必须从对话状态设置为远程URI.请求的To头字段中的标记必须设置为对话ID的远程标记.请求的From URI必须设置为来自对话状态的本地URI.请求的From头字段中的标记必须设置为对话ID的本地标记.如果远程或本地标记的值为null,则必须分别从to或From头字段中忽略标记参数.
在后续请求中使用原始请求中的To和from字段的URI是为了向后兼容RFC 2543,RFC 2543使用URI进行对话标识.在本规范中,只有标签用于对话标识.在本规范的后续版本中,预期在mid对话请求中强制反射原始的往返URI将被弃用.
请求的Call-ID必须设置为对话的Call-ID.对话中的请求必须在每个方向上包含严格单调递增且连续的CSeq序列号(递增1)(当然,ACK和CANCEL除外,其数字等于被ACK或CANCEL的请求).因此,如果本地序列号不是空的,则本地序列号的值必须增加1,并且该值必须放入CSeq头字段中.如果本地序列号为空,则必须使用第8.1.1.5节的指南选择初始值.CSeq头字段值中的方法字段必须与请求的方法匹配.
使用32位的长度,一个客户端可以在一次调用中每秒生成一个请求,持续约136年,然后才需要结束.选择序列号的初始值,以便同一调用中的后续请求不会环绕.非零初始值允许客户端使用基于时间的初始序列号.例如,客户机可以选择32位秒时钟的31个最高有效位作为初始序列号.
UAC使用远程目标和路由集来构建请求的Request-URI和路由头字段.
如果路由集为空,UAC必须将远程目标URI放入Request-URI中.UAC不得向请求中添加路由头字段.
如果路由集不是空的,并且路由集中的第一个URI包含lr参数(参见第19.1.1节),UAC必须将远程目标URI放入Request-URI中,并且必须包括一个按顺序包含路由集值的路由头字段,包括所有参数.
如果路由集不是空的,并且它的第一个URI不包含lr参数,UAC必须将路由集的第一个URI放入Request-URI,去掉Request-URI中不允许的任何参数.UAC必须按顺序添加包含剩余路由集值(包括所有参数)的路由头字段.然后UAC必须将远程目标URI作为最后一个值放入Route header字段中.
例如,如果远程目标是sip:user@remoteua路由集包含:
`<sip:proxy1>`,`<sip:proxy2>`,`<sip:proxy3;lr>`,`<sip:proxy4>`
请求将由以下Request-URI和路由头字段组成:
METHOD sip:proxy1
Route: <sip:proxy2>,<sip:proxy3;lr>,<sip:proxy4>,<sip:user@remoteua>
如果路由集的第一个URI不包含lr参数,则指示的代理不理解本文档中描述的路由机制,并将按照RFC 2543中的规定行事,在转发消息时用它接收的第一个路由头字段值替换Request-URI.将Request-URI放在Route header字段的末尾将保留
通过严格路由器的Request-URI中的信息(当请求到达松散路由器时,它将返回到Request-URI).
UAC应在对话中的任何目标刷新请求中包含Contact 头字段,除非需要更改,否则URI应与对话中以前请求中使用的URI相同.如果"secure"标志为true,则该URI必须是SIPS URI.如第12.2.2节所述,目标刷新请求中的Contact 头字段更新远程目标URI.这允许UA在对话期间地址发生变化时提供新的联系人地址.
但是,不是目标刷新请求的请求不会影响对话的远程目标URI.
请求的其余部分如第8.1.1节所述.
构建请求后,将计算服务器地址并发送请求,对对话外的请求使用相同的过程(第8.1.2节).
第8.1.2节中的程序通常会导致将请求发送到最顶端的路由头字段值或Request-URI(如果不存在路由头字段)指示的地址.根据某些限制,它们允许将请求发送到备用地址(例如路由集中未表示的默认出站代理).
12.2.1.2 处理答复
UAC将从事务层接收对请求的响应.如果客户端事务返回超时,则将其视为408(请求超时)响应.
对于在对话内发送的请求,UAC接收3xx响应的行为与在对话外发送的请求相同.第8.1.3.4节描述了该行为.
但是,请注意,当UAC尝试其他位置时,它仍然使用为对话设置的路由来构建请求的路由头.
当UAC收到对目标刷新请求的2xx响应时,它必须用该响应中Contact 头字段的URI(如果存在)替换对话的远程目标URI.
如果对话内的请求响应为481(呼叫/事务不存在)或408(请求超时),UAC应终止对话.如果没有收到任何请求响应,UAC也应该终止对话(客户端事务将通知TU超时)
对于INVITE启动的对话,终止对话包括发送BYE.
12.2.2 UAS行为
在对话中发送的请求与任何其他请求一样,都是原子请求.如果UAS接受特定请求,则执行与其相关的所有状态更改.如果请求被拒绝,则不会执行任何状态更改.
请注意,某些请求(如INVITE)会影响多个状态.
UAS将从事务层接收请求.如果请求在To头字段中有标记,UAS核心计算与请求对应的对话标识符,并将其与现有对话进行比较.如果存在匹配项,则这是一个mid对话请求.在这种情况下,UAS首先对对话外的请求应用相同的处理规则,如第8.2节所述.
如果请求在To头字段中有一个标记,但对话标识符与任何现有对话不匹配,则UAS可能已崩溃并重新启动,或者可能已收到对不同(可能失败)UAS的请求(UAS可以构造To标记,以便UAS可以识别该标记是针对其正在提供恢复的UAS的). 另一种可能是传入的请求只是被错误路由了.根据To标签,UAS可以接受或拒绝请求.接受可接受标记的请求提供了健壮性,因此对话即使在崩溃时也可以保持.希望支持此功能的UAs必须考虑一些问题,例如选择单调递增的CSeq序列号(即使在重新启动时),重建路由集,以及接受超出范围的RTP时间戳和序列号.
如果UAS希望拒绝请求,因为它不希望重新创建对话,它必须使用481(呼叫/事务不存在)状态代码响应请求,并将其传递给服务器事务.
在对话中可以接收不以任何方式更改对话状态的请求(例如,OPTIONS request).它们的处理方式就像是在对话外部接收到的一样.
如果远程序列号为空,则必须将其设置为请求中CSeq头字段值中的序列号值.如果远程序列号不是空的,但请求的序列号低于远程序列号,则该请求是无序的,必须以500(服务器内部错误)响应拒绝.如果远程序列号不为空,并且请求的序列号大于远程序列号,则请求正常.CSeq序列号可能比远程序列号高出一个以上.这不是错误情况,UAS应准备接收和处理CSeq值高于先前接收请求一个以上的请求.然后,UAS必须将远程序列号设置为请求中CSeq头字段值中的序列号值.
如果代理质疑UAC生成的请求,UAC必须使用凭据重新提交该请求.重新提交的请求将有一个新的CSeq号.UAS将永远看不到第一个请求,因此,它将注意到CSeq编号空间中的间隙.这样的间隙并不代表任何错误情况.
当UAS收到目标刷新请求时,它必须用该请求中Contact 头字段的URI(如果存在)替换对话的远程目标URI.
12.3 终止对话
与该方法无关,如果对话外部的请求生成非2xx最终响应,则通过对该请求的临时响应创建的任何早期对话都将终止.终止ACK对话的机制是特定于方法的.在本规范中,BYE方法终止会话及其关联的对话.详情见第15节.