RFC3265翻译SessionInitiationProtocol(SIP)-Speci。。。闲来⽆事,找篇⽂章翻译⼀下,复习下英⽂,也强迫⾃⼰好好读读协议⽂档。
从短的开始吧,呵呵,也希望⾃⼰能够坚持下去。
1 简介
在终端节点间通信过程中,发送异步通知消息的能⼒被证实在很多类型的SIP服务中是相当有⽤的。其中包括:⾃动会呼功能(基于终端状态事件)、好友列表(基于⽤户存在事件)、消息等待通知(基于邮箱状态变化事件)以及PSTN和Internet互通状态(基于呼叫状态事件)。
在本⽂档中描述的⽅法,提供了⼀个这些通知消息可以遵循的框架。
在这⾥定义的事件通知机制并不是⼀个对所有订阅和通知消息都有效的规则。对于某个单⼀协议,要想满⾜所有订阅和通知消息的需求是⾮常困难的。我们的⽬标只是提供⼀个针对SIP的框架,它对于⼀个特定领域不会过于复杂以⾄于⽆法实现,但能够提供⾜够灵活强⼤的服务。必须注意到,基于这个框架的事件包可能会定义⼀下强制的规则,它们定义的订阅和通知消息都必须遵守这些规则。
本⽂档没有没有定义可以直接使⽤的扩展功能;这些扩展功能必须在其他⽂档定义(这⾥是指“事件消息包”)。在⼀个基于对象的设计系统中,它可以被看作为⼀个抽象基类,可以被其他扩展的功能继承。在
第4章中描述了进⾏这些扩展的⼀些基本原则。
1.1 概述
订阅和通知的基本理念是:在⽹络中的实体可以订阅在⽹络中各种不同资源和呼叫的资源和呼叫状态,并且那些实体当状态发⽣变化时会发送通知消息。
⼀个典型的呼叫流程如下图所⽰:
订阅者 通知者
|-----SUBSCRIBE---->| 请求状态订阅
|<---------200------------| 订阅请求响应
|<------NOTIFY---------| 返回当前状态通知
千年的狐|--------200------------->|
|<------NOTIFY---------| 返回当前状态通知
|--------200------------->|
订阅消息是会过期的,必须由后续的SUBSCRIBE来刷新。
1.2 ⽂档约定
略
2 定义
事件包(Event Package):事件包是指⼀个附加的规范,其中定义了由通知者发送给订阅者的⼀系列状态信息。消息包也定义了基于本⽂描述的框架语法和语义,⽤来描述这些特定的状态信息。
事件模板包(Event Template-Package):事件模板包是⼀种特殊的事件包,它定义了所有事件包可能⽤到的⼀系列状态,包括它⾃⾝。
通知(Notification):通知是值由通知者向订阅者发送某个资源的状态。
通知者(Notifier):通知者是⼀个⽤户代理(Ur Agent),它会产⽣⼀个NOTIFY请求给订阅者,来通知订阅者某个资源的状态。通常通知者可以接收⼀个SUBSCRIBE请求来创建订阅。
状态代理(State Agent):状态代理是⼀个通知者,它根据某个资源的⾏为来产⽣状态信息。为了做
到这点,它可能需要汇总多个资源的这类状态信息。⼀个状态代理通常会拥有它所产⽣通知消息的资源的完整状态。
订阅者(Subscriber):订阅者是⼀个⽤户代理,它接收来⾃通知者的NOTIFY请求,这些NOTIFY请求中包含了订阅者关⼼的某个资源的状态。通常订阅者也会产⽣SUBSRCIBE请求,并将请求发送给通知者来创建订阅。
订阅(Subscribe):订阅是指与⼀个对话相关的⼀系列的应⽤程序状态。这个应⽤程序状态包括⼀个指向对应对话的指针,事件包的名字,以及⼀个可选的ID令牌。事件包会定义附加的订阅状态消息。根据定义,订阅在订阅者和通知者都存在。
登山机订阅转移(Subscribe Migration):订阅转移是指讲某个订阅从⼀个通知者转到另⼀个通知者的⼀些列操作。
3 节点⾏为特性
3.1 SUBSCRIBE⾏为描述
SUBSCRIBE⽅法是向⼀个远端节点请求当前状态和获取状态更新。
3.1.1 订阅持续时间
每个SUBSCRIBE请求都应该包含“Expires”头(在SIP[1]中定义)。这个超时值表明了当前这个订阅的有效时间。为了保证订阅的有效性,使之不超过Expires头中定义的持续时间,订阅者需要定时在同⼀会话中发送⼀个新的SUBSCRIBE请求来刷新订阅。
如果在SUBSCRIBE请求中没有定义Expires头,那么默认值是在事件包中定义。
对于SUBSCRIBE请求的相应消息—200族响应消息中也必须包含Expires头。其中定义的时间可以⽐SUBSCRIBE请求中定义的有效时间短,但绝对不能较之更长。200应答消息中定义的超时时间就是这次订阅的超时时间。
在Contact头中的expires参数和SUBSRCIBE没有关系,很显然,它不等同与SUBSCRIBE请求和响应中的Expires头。
很容易联想到如果⼀个SUBSRCIBE请求中Expires头设为0,那么就表⽰取消该订阅。
除了表明取消订阅外,⼀个Expires头为0的SUBSCRIBE也引发⼀个状态取回操作,详见3.3.6。
通知者也可能想要取消某个订阅。这点⾮常有⽤,⽐⽅说,没有被订阅的资源已经不存在了,那就需要取消它的订阅。关于这点将在3.2.2中做更为详细的讨论。
3.1.2 订阅事件和事件类的描述
事件的描述由三部分信息组成:请求URI(Request URI)、事件类型、消息体(可选)。
Request URI是SUBSCRIBE请求中最重要的字段,它包含了⾜够的路由信息将请求依照每个路由流程送到⽬的端。它也包含了⾜够的信息来标⽰事件订阅的资源。但它不⼀定包含⾜够的信息来确定某个事件(⽐如:sip:可以订阅我现在的状态,也可以是订阅我语⾳信箱的状态)。
订阅者必须在SUBSCRIBE请求中包含⼀个Event头,且只能包含⼀个,来表明订阅的事件或是事件类。Event头也要包含⼀个标记来表明这次订阅的状态类型。这个标记是在IANA注册的,并且和某个事件包对应来描述这个事件或是事件类。Event头也可以包含⼀个Id参数。如果这个Id参数存在的话,它包含⼀个不透明的标记,⽤来标⽰对话中的特定订阅。Id参数仅在单个对话中有效。
如果事件标记对应的事件包定义了SUBSCRIBE请求中的消息体,那么就要遵从这些定义。
事件包也可以⾃⼰为Event头定义参数,那么,它也必须定义这些参数的语义。
3.1.3 其他SUBSCRIBE请求的头变量赋值
由于SUBSCRIBE请求会按照SIP[1]的定义创建⼀个对话,它就可能带有⼀个Accept头。如果存在的话,Accept头定义了在后续NOTIFY 请求中消息体的结构。事件包必须定义在没有Accept头情况下SU
BSCRIBE请求的⾏为。通常这种情况下,SUBCRIBE仅包含⼀个默认的消息体类型。
在本⽂档中没有定义的消息头的赋值参考SIP[1]中的定义。
3.1.4 订阅者SUBSCRIBE⾏为
3.1.
4.1 请求订阅
SUBCRIBE如同在SIP[1]中的定义,是创建⼀个对话的⽅法。
当订阅者想要订阅某个资源的特定状态时,它会创建⼀个SUBSCRIBE消息。如果第⼀个SUBCRIBE是在某个对话之外的(通常是这种情况),它会按照SIP[1]中定义的UAC在对话外创建请求的流程⼀样创建SUBSCRIBE请求。
SUBSCRIBE请求会由⼀个最终的应答来确认。200族的应答消息表明此次订阅被确认,然后⼀个NOTIFY消息会⽴即发送。200应答表明此次订阅已经成功,⽤户有权订阅请求的资源。202应答仅仅表明已经收到订阅请求,但是否订阅成功还未确定。
200族的应答消息中的Expires头表明订阅的实际有效时间。
⾮200族的应答消息,表明没有订阅或是对话被创建,并且也没有后续的NOTIFY会被发送。初应答489以外,所有的⾮200族应答拥有同样的意义,如SIP[1]所述。
在⼀个SUBSCRIBE请求的Event头中可能包含⼀个Id参数,来区分同⼀个会话中的不同订阅。
3.1.
4.2 刷新订阅
在订阅超时前的任何时候,订阅者都可以发送另⼀个SUBSCRIBE请求来刷新订阅超时定时器,这个刷新SUBSCRIBE请求与原先的订阅在同⼀个会话中,并且有相同的Event头和Id参数。通常情况下这个SUBSCRIBE请求和初始SUBSCRIBE处理流程⼀样,但如果是下⾯的情况则有所不同:
如果初始SUBSCRIBE请求在Event头中带有Id参数,那么刷新的SUBSCRIBE请求必须带有同样的Id参数,否则这个SUBSCRIBE会被当做在此对话中⼀个新的订阅。
如果⼀个刷新SUBSCRIBE请求收到⼀个481应答,则表明这个订阅已经结束,订阅者也不会再收到通知消息。此时,订阅者应该认为此订阅已经⽆效。如果订阅者想要重新订阅这个状态,它必须再创建⼀个新的初始SUBSCRIBE请求,包含新的Call-ID和新的唯⼀的From标记。
如果⼀个刷新SUBSCRIBE请求收到⼀个失败应答,但不是481,则表明这次订阅在未超时前仍然有效,这个超时时间可能是在最近⼀次SUBSCRIBE和应答之间协商确定,也可能是在NOTIFY消息中Subscription-State头的expires参数定义。
这种错误可能是由⽹络状况或是通知者问题引起的,以⾄于没有后续NOTIFY消息会被发送。
3.1.
4.3 取消订阅
取消订阅和刷新订阅的处理流程相同,只是Expires头的值为0。取消订阅成功后,将会有⼀个最终的NOTIFY消息。
3.1.
4.4 订阅创建确认
订阅者可以认为它将从所有成功处理订阅和订阅刷新的节点等到NOTIFY消息。在第⼀个NOTIF消息到达之前,订阅者应该认为被订阅资源处于不确定状态。定义事件包的⽂档中必须规定这种不确定状态,以⽅便应⽤程序处理(参见4.4.7)。
由于存在消息乱序和⽹络路径分叉的可能性,订阅者必须有在SUBSCRIBE事务完成前处理NOTIFY消息的能⼒。
3.1.5 代理订阅⾏为
代理需要在SIP[1]定义的功能外⽀持新的⾏为来⽀持SUBSCRIBE。如果代理希望看见某个对话中所有的SUBSCRIBE请求和NOTIFY请求,那么它必须改写初始SUBSCRIBE请求和⽤来建⽴对话的NOTIFY请求的路由信息,也应该改写其他所有SUBSCRIBE和NOTIFY的路由信息。
订阅者和通知者可以使⽤S/MIME来对SUBSCRIBE和NOTIFY进⾏编码。因此,代理不能获取那些在SIP[1]中明确定义代理可读的信息。
3.1.6 通知者SUBSCRIBE⾏为
3.1.6.1 初始SUBSCRIBE事务处理
SUBSCRIBE事务必须在第⼀时间做出应答,它持续的时间不能超过⾃动处理所需的时间,也就是说,通知者不能在等到⽤户响应后再发送SUBSCRIBE请求应答。
通知者需要确定在Event头中定义的事件包是否⽀持。如果不⽀持,通知者需要返回⼀个489-⽆效事件应答,来表明指定的事件不⽀持。
通知者也应根据⾃⼰需要来进⾏必要的鉴权和认证,参见3.1.6.3。
通知者也可以检查Expires头规定的超时值是否过短。仅当超时值⼤于0,⼩于1⼩时,并且⼩于通知者的最⼩配置值时,通知者可以返回⼀个423-时间间隔过⼩应答,并且者应答消息Min-Expires头中指明⽀持的最⼩超时值。Min-Expires头如SIP[1]中定义。
如果通知者能够马上确定它可以⽀持此事件包,鉴权也已经通过,并且没有没有其他问题,那么通知者就会创建订阅和⼀个与之对应的对话,并且返回200应答(除⾮这样做引起鉴权策略混淆,参见5.2)。
如果通知者不能⽴即创建订阅(例如,需要⽤户输⼊密码完成鉴权,或者需要联系另个暂时⽆法联系的节点),或是希望加密鉴权策略,通知者可以返回⼀个202-Accept应答。这个应答说明SUBSCRIBE请求已经被接受,但是由于还未鉴权,所以不能⽣效。
当通知者创建订阅时,它会将事件包名字和Event头Id参数作为订阅信息的⼀部分保存下来。在200族应答消息中的Expires值和REGISTER应答中的是⼀样的:服务端可以缩短时间,但不能延长超时时间。
如果SUBSCRIBE请求中的超时时间过短,那么通知者可以发送⼀个423应答,如前所述。
作为SUBSCRIBE请求的应答,200族应答在订阅有效期间不会产⽣任何有⽤信息,它们的⽬的仅是保证事务传输可靠有效。状态信息将会被包含在后续的NOTIFY消息中发送给订阅者。
SIP[1]中定义的其他应答代码也可以使⽤。
3.1.6.2 订阅创建/刷新确认
对于成功创建和刷新的订阅,通知者必须⽴刻发送⼀个NOTIFY消息给订阅者,其中包含了订阅资源的当前状态。这个NOTIFY消息是在有订阅者创建的对话中发送的。如果订阅发⽣时,资源处于⼀个⾮有效状态的话,通知者可以发送⼀个包含空消息体或是不确定状态的消息体的NOTIFY给订阅者。更多关于⽣成NOTIFY的细节请参考3.2.2。
值得注意的是,任何200族的应答被发送后,都要⽴刻发送⼀个NOTIFY消息,⽽不管是否经过鉴权。
小辫子发型扎法3.1.6.3 SUBSCRIBE请求的认证和鉴权
由于⼀些隐私的原因,通知者可能需要通过某周鉴权策略来确定订阅者是否有权限来订阅某个事件。这种鉴权策略可以是查询某个允许访问的列表,也可以是和⽤户进⾏实时交互来查询。通常,鉴权在认证之前的不是什么常⽤。
SIP的认证机制在SIP[1]中有所讨论。这⾥,即使通知节点是⼀个代理,SUBSCRIBE请求的认证也是从401应答开始,⽽不是407。在创建订阅和发送通知时,通知者通常作为UA的⾓⾊。
当然,作为代理的情况,还是使⽤407应答。刚刚做的解释只是强调通知者是⼀个UAs,必须按照UA认证流程。
如果鉴权失败是由于允许列表中没有记录或是其他⾃动鉴权机制(也就是可以⾃动识别订阅者是否有权限订阅),通知者应该应答403-Forbidden或是603-Decline,除⾮这样会涉及到⼀些隐私信息。参见5.2。
如果通知者需要通过交互的⽅式来确定订阅是否有权限,它需要⽴即返回⼀个202-Accept应答。NOTIFY消息还是要⽴即发送,如前所述。
心怦怦跳
如果订阅鉴权被延误,通知者希望拒绝这次订阅请求,通知者可以发送⼀个包含Subscription-State头的NOTIFY的消息给订阅者来表明这次订阅结束,Subscription-State的值为terminated。
3.1.6.4 刷新订阅
当通知者收到刷新订阅消息时,假定订阅者仍然鉴权有效,通知者就需要更新订阅的超时时间。在初始订阅中服务端可以缩短超时时间,但不能延长。最终确定的超时时间在应答消息的Expires头中描述。
如果订阅者确定的超时时间过短,通知者应该发送⼀个423-Subscription Too Brief应答。
如果在订阅超时前没有收到任何刷新订阅,那么这个订阅将被删除。当删除某个订阅时,通知者需要发送⼀个NOTIFY给订阅者来表明订阅已经被删除,这个NOTIFY的Subscription-State头被置为terminated,并且应该包含⼀个reason=timeout参数。
发送⼀个超时的NOTIFY可以导致对话结束。
3.2 NOTIFY⾏为描述
NOTIFY消息是通知订阅者它订阅的状态发⽣了变化。订阅通常是通过SUBSCRIBE⽅法完成,但是还有其他的⽅法。
如果有任何⾮SUBSCRIBE的⽅法来创建订阅,那么就必须保证相应的NOTIFY能够正常⼯作。这个机制的设计者必须能够区分两种NOTIFY消息,⼀种是发送给明确知道订阅的订阅者,另⼀种是发送⽆知的节点。后⼀种⾏为是⽆效的,肯定会收到481- Subscription does not exist应答(除⾮其他⼀些400族或500族更符合错误情况),参见3.2.4。也就是说订阅必须是对订阅者和通知者都有效的,⽆论是不是使⽤了SUBSCRIBE机制来完成订阅。
⼀条NOTIFY并不还意味者订阅结束,也就是说⼀条SUBSCRIBE请求可能会触发多条NOTIFY请求。
兔年犯太岁的生肖
3.2.1 已报告时间、事件类和当前状态的识别
通知的事件类型识别和前⾯描述的订阅事件类型相似(参见3.1.2)。
和SUBSCRIBE请求⼀样,NOTIFY消息中Event头包含了创建的通知消息的事件包名。在NOTIFY中的事件包名必须和SUBSCRIBE中的事件包名相同。如果SUBSCRIBE消息中有Id参数,那么NOTIFY中也必须带有相同Id参数。
消息包会定义NOTIFY消息体的语义,如果确实定义了,那么就要在NOTIFY中实现这些语义。 NOTIFY的消息主要是⽤来提供⼀些发⽣事件和相关资源状态的⼀些详细信息。
如果有消息体的话,NOTIFY必须要符合的SUBSCRIBE请求中Accept头中规定的格式。消息体中可以包含订阅资源的状态,也可以包含指向此状态的URI(参见4.4.13)
3.2.2 通知者NOTIFY⾏为
当通知者以200族消息响应SUBSCRIBE请求后,必须马上构建并发送⼀个NOTIFY消息给订阅者。当订阅的状态发⽣变化时,也应该根据鉴权、本地策略或是实现难以程度的考虑来⽴即发送⼀个NOTIFY消息。
如果应答超时,那么这个NOTIFY被认为是失败了,或者收到⼀个⾮200族的应答消息,并且这个应答消息没有Retry-After头或其进⼀步要求重试的请求(⽐如401 Authorization Required)。
如果NOTIFY由于超时⽽失败,并且此订阅是由软件层次创建的(如 SUBSCRIBE),那么通知者需要删除这个订阅。
通过这种⾏为,就可以防⽌在订阅者崩溃或是离开⽹络的时候发送不必要的状态变化消息。由于这种传送是要发送多次的,重传算法在
SIP[1]中有定义,持续向⽹络上不存在客户提供服务可能会引起⽹络阻塞。如果客户端重启或是重新加⼊⽹络的话,客户端应该重新发送SUBSCRIBE消息来继续订阅,这样的消息将会重启订阅流程。
如果由于错误导致NOTIFY失败,并且订阅是由软件层次触发的,通知者必须删除对应的订阅。
⼀个表明出错的应答通常表明订阅者或是路由上的某个代理出错。如果是订阅者出错,订阅者就可以在错误被解决的时候通过re-SUBSCRIBE来纠正这个状态。如果是代理出错,那么订阅者定期发送的刷新订阅消息就可以在⽹络问题解决时重新开始这次订阅。
如果通知者收到481应答,那么通知者必须删除这个订阅,即使这个订阅不是由SUBSCRIBE发动的。
如果没有定义上⾯的⾏为,那么订阅者在收到⼀个不可识别的订阅消息时需要先发送⼀个包含错误码的应答,再发送⼀个SUBSCRIBE取消订阅。这样就有可能让订阅者收到⽹络服务攻击,因此,我们选⽤错误码为481的应答来明确的说明订阅必须被全部取消。
NOTIFY必须包含⼀个Subscription-State头,这个消息头的取值包括active, pending和terminated。Active表明订阅已经被接收并且通过鉴权;pending表明订阅请求已经收到,但根据本地策略还不能确定是否被接收;terminate表明此次订阅已经结束。
如果Subscription-Stat头的值是active或是pending,通知者必须在Subscription-Stat头包含⼀个expires参数来表明订阅的有效时间。通知者可以通过这种⽅式来缩短超时时间,但不能延长订阅有效时间。
5月份日历当SUBSCRIBE请求产⽣分叉时,订阅者⽆法收到应答,这种情况下在active和pending订阅中加⼊超时信息就⼗分有⽤。需要注意的是这个expires值是Subscription-Stat头的参数,⽽不是Expires头。
如果Subscription-Stat头的值是terminate,NOTIFY也应该包含⼀个reason参数。通知者也可以包含⼀个retry-after参数。详见3.2.4。
3.2.3 代理NOTIFY⾏为
代理不需要额外的⾏为来⽀持NOTIFY。如果代理希望看到在⼀个对话中所有的SUBSCRIBE和NOTIFY,那么它必须重写初始SUBSCRIBE 消息和创建对话的NOTIFY消息的路由信息。也需要重写所有SUBSCRIBE和NOTIFY的路由信息。
订阅者和通知者可以使⽤S/MIME来对SUBSCRIBE和NOTIFY进⾏编码。因此,代理不能获取那些在SIP[1]中明确定义代理可读的信息。
红海行动演员3.2.4 订阅者NOTIFY⾏为
当收到⼀个NOTIFY请求时,订阅者必须判断它是否和某个未处理的订阅匹配。如果没有,那么订阅者必须返回⼀个481 -Subscription does not exist应答,除⾮有其他400族或500族的应答消息更适合。匹配的SUBSCRIBE和NOTIFY表明⼀个新的对话被创建,参见
3.3.4。如果是在⼀个已经创建的对话中建⽴的SUBSCRIBE和NOTIFY,那么它们属于同⼀对话,并且Event头相同,在7.2.1中描述。
如果由于某些原因,订阅者不⽀持NOTIFY消息中的Event头表⽰的事件包,那么它必须返回⼀个489-Bad Request 应答。
NOTIFY请求应该认证,使⽤SIP定义的认证机制。
NOTIFY请求必须包含Subscription-State头来表明订阅的当前状态。
话梅花生