rfc5245中文翻译(持续更新中)

 

目录

 

1 介绍

2 ICE整体视图

2.1 收集candidate

2.2 连通性检查

2.3 Candidate排序

2.4 Frozen candidate

2.5 检查机制的安全考虑

2.6 ICE判定

2.7 Lite实现

3 术语

4 发送初始OFFER

4.1 Full实现的要求

4.1.1 收集candidate

4.1.2 设置candidate优先级

4.1.3 剔除冗余candidate

4.1.4 选择默认candidate

4.2 Lite实现的要求

4.3 SDP编码

5 接收初始OFFER

5.1 验证ICE是否支持

5.2 角色判定

5.3 收集candidate

5.4 设置candidate优先级

5.5 选择默认candidate

5.6 SDP编码

5.7 构造check list

5.7.1 构造candidate pair

5.7.2 计算pair的优先级和排序

5.7.3 修剪这些pair

5.7.4 计算状态

5.8 调度检测

6 接收初始ANSWER

6.1 验证ICE是否支持

6.2 角色判定

6.3 构造check list

6.4 启动Ordinary检测

7 执行连通性检测

7.1 STUN客户端流程

7.1.1 创建Relayed candidate的Permission

7.1.2 发送请求

7.1.3 处理响应

7.2 STUN 服务器端流程

7.2.1 Full实现的额外流程

7.2.2 Lite实现的额外流程

8 ICE定论

9 后续的OFFER/ANSWER请求

10 保活

11 媒体处理

12 使用SDP

13 与ANAT的关系

14 可扩展性考虑

15 语法

16 设置Ta和RTO

17 样例

18 安全考虑

19 STUN扩展

20 可操作性考虑

21 IANA考虑

22 IAB考虑

23 致谢

24 参考

附A Lite和Full实现

附B 设计动机


1 介绍

Rfc3264规范定义了一个用于建立多媒体会话的SDP两步交换机制,这个OFFER/ANSER机制被SIP这类协议所使用。

OFFER/ANSER机制在NAT网络的穿透方面比较困难,因为该机制的目的是建立一条媒体报文的流,倾向于在消息中携带IP地址和端口号,而这种做法NAT穿透是有问题的。这类协议寻求创建一条端到端的媒体流,没有应用层级的媒体中继,目的是减少媒体传输过程中的时延、丢包以及应用部署的成本。但是带来的问题就是在NAT网络的难以有效工作。对于此类问题的完整讨论超出了本文档的范围。

已经有一些解决方案用于解决这类协议在NAT网络的操作场景。例如Application Layer Gateways(ALGs),Middlebox Control Protocol(rfc3303)等。不幸的是,这些技术都是有利有弊的,就单个技术而言在一种网络拓扑下可能是最优选择,但是在其他网络拓扑下可能就是很差的选择,这就要求管理员和开发者需要对应用到的网络拓扑状态做出假设,这会导致实现方案变得复杂而脆弱。而我们需要的是机制单一的、在所有的情况下都能很好工作的解决方案。

本规范将ICE定义为一种NAT穿透技术,用于使用OFFER/ANSWER建立起的基于UDP的媒体流(尽管ICE也可以扩展用于其他传输协议,例如TCP)。ICE是OFFER/ANSWER的一种扩展,基本的原理是在SDP的OFFER和ANSWER中指定多个IP地址和端口,然后根据这些信息进行端到端的连通性检查。包含在SDP中的这些IP地址和端口号,以及连通性检查是通过修正后的STUN协议来实施的。STUN协议新的全称是Session Traversal Utilities for NAT,这个命名反应了它的新角色,就是作为其他NAT网络穿透技术(例如ICE)的工具而不是单独的NAT穿透解决方案。ICE还使用了TURN规范,这是STUN协议的扩展。ICE机制对于一个媒体流会交换多个IP地址和端口对,它同样支持多IP和双栈的主机。

2 ICE整体视图

在典型的ICE部署场景下,存在两个相互通信的endpoint(在rfc3264协议中就是agent)。他们能够通过其他信令协议(例如SIP)间接通信,通过这个信令协议进行OFFER/ANSWER协商。注意ICE并不用于SIP协议的穿透,我们假设已经存在其他相应机制 (rfc5626)。在ICE流程开始之前,这些agents对于他们所处的网络拓扑一无所知。具体来说,他们有可能存在于一个(甚至多个)NAT网关后面,也有可能不存在。而ICE流程就是让这些agent去获取关于网络拓扑的足够信息,从而找到一条或者多条他们能够互通的网络路径。

图1展示了ICE部署的典型环境。这两个endpoint被称作L和R(就是左和右,用于帮助我们可视化这个呼叫流程)。L和R分别处于各自的NAT网关后面,尽管他们对此并不知悉。NAT的类型和相关属性同样也是未知的。AGENT L和R具备OFFER/ANSWER协商的能力,可以建立他们之间的会话。典型的协议是SIP。

除了这些agent,一个SIP服务器和NAT网关,ICE还涉及网络中的STUN或者TURN服务器。每个agent都有他们自己的STUN或者TURN服务器,当然也可能是同一个。

rfc5245中文翻译(持续更新中)

ICE的基本思想是这样的:每个agent都有一组可选的candidate(IP地址、端口号以及特定传输协议,本规范中是UDP),可以用于同其他的agent进行媒体通信。这些candidates包括:

  • 同网络接口直接对应的地址

  • NAT映射的对应公网地址(server reflexive地址)

  • TURN服务器分配的地址(relayed地址)

L的任何一个candidate都有可能同R的任何一个candidate通信。实际场景下,有些L和R之间的candidate组合可能无法工作。比如,L和R都处于各自的NAT网关后面,那么本地的网络地址之间就无法直接通信(这不就是ICE存在的原因吗)。而ICE的目的就是去发现到底哪些candidate组合可以工作,方法就是逐一尝试(经过仔细排序)所有可能的组合直到找到一条或者多条可用的candidate对。

2.1 收集candidate

为了启动ICE流程,agent必须识别出所有的candidate。一个candidate是一个传输地址----一个特定协议(这里特指UDP)下的IP地址和端口的组合。本文定义了三种类型的candidate:有些是从本机的物理或者逻辑网卡得到的,其他的是通过STUN或者TURN服务器获取到的。从本地接口获取到的candidate是很自然的情况,这种candidate被称为HOST CANDIDATE。本地接口可能是以太网或者WiFi,也有可能是通过某种隧道机制获取到的,比如v*n或者是移动IP(MIP)。上述所有情况下,这些网络接口对于agent来说就是本地接口,这些接口上的端口号是可以自由分配的。

如果一个agent是多归属的(multihomed),那么每个IP地址都能产生一个candidate。对端agent通过一个或者多个这样的IP都能访问这个agent,这取决于对端agent(PEER)所在IP网络的位置。考虑如下情况:一个agent有一个本地IP地址连接上私有的10网段网络(I1),第二个连接上公共网络(I2)。从I1得到的candidate可以直接被处于同一私有10网段网络的对端访问,同时从I1得到的candidate可以被处于公共网络的其他对端所访问。发送OFFER的agent与其猜测哪一个IP地址优先被访问,不如直接将所有的candidate都放在OFFER里面。

下一步,这个agent使用STUN或者TURN来获取其他的candidate。这些candidate通常来自两个方面:NAT网关在公网侧的翻译地址(server reflexive candidate)和TURN服务器的公网转发地址(relayed candidate)。当TURN服务器启用时,两种地址都是从TURN服务器上获取到的。如果只有STUN服务器启用,那么只有server reflexive candidate可以从服务器获取到。这些candidate同host candidate的关系如图2所示。图中两种类型的candidate都是通过TURN发现的。图中标记X:x意思是IP地址X和UDP端口x。

rfc5245中文翻译(持续更新中)

当agent从地址端口对X:x(host candiate)向TURN服务器发送Allocate请求时,NAT网关(假设只有一层)将会创建一个地址对绑定的外部地址对X1':x1'(server relexive candidate),用于映射到host candidate X:x。从这个host candiate外发的报文,NAT将会将本端地址修改为server relexive candidate。反之收到的外部发往server relexive candidate的报文,NAT会将目的地址修改为host candidate。我们将这个host candidate称之为对应server relexive candidate的BASE。

  • 注意:base指的是从一个candidate发送报文时实际的发送地址。从某种意义上说,host candidate同样有base,只不过和host candidate一样而已。

如果在agent同TURN服务器之前存在多层NAT,那么这个TURN请求会导致每层NAT都会创建一个绑定,但是只有最外层的server reflexive candidate(最接近TURN服务器的那一层NAT网关)才会被agent发现。如果agent没有处于NAT后面,那么这个server  reflexive candidate同host candidate是一样的,将会被剔除掉。

然后这个Allocate请求到达TURN服务器,这个TURN服务器将会从服务器地址Y中分配一个端口y,将这个relayed candidate Y:y通过响应消息发送给agent。TURN服务器同时还会将server  reflexive candidate拷贝都响应消息中发送agent。这个TURN服务器作为一个报文中继,转发agent L和R之间的流量。为了能够发送而给L,R需要发送报文到TURN服务器的Y:y,TURN服务器转发给X1':x1',NAT网关再通过地址映射转发给X:x这样报文就到达了L。

如果只启用STUN,agent将会发送binding请求给STUN服务器。STUN服务器将会通过bingding响应消息告知agent它对应的server relexive candidate。

2.2 连通性检查

一旦L收到到他所有的candidate,它将他们按照优先级从高到低进行排序后通过信令通道发给R,这些candidate通过OFFER SDP消息中的属性来携带。当R收到这个OFFER,也执行同样的candidate收集过程,并且将收集的结果通过ANSWER发送给L。这样每个agent都具有了完整的candidate列表,包括本侧的candidate和对端的candidate。然后将本端candidate同对端candidate对应起来,形成candidate pair。为了查明哪些pair能有效工作,每个agent都实施了 一系列的检查。每个检查就是基于一个pair的一次STUN 请求/响应事务,通过从pair的本端candidate发送STUN请求到对端candidate。

连通性检查的基本原则很简单:

1. 按优先级对candidate pair进行排序

2. 按照优先级顺序对每个candidate pair发起检查

3. 对对单agent发起的检查进行确认

 

对于两方agent都对同一个candidate pair进行检查的情况,结果就是一个4次握手的过程。

rfc5245中文翻译(持续更新中)

需要注意的是STUN请求发送和接收的端口同媒体报文(RTP/RTCP)使用的端口是一样的。因此agent需要根据报文的内容进行解复用STUN报文和RTP/RTCP报文,而不是基于端口号。幸运的是,这种解复用很简单,特别是对于RTP和RTCP来说。

由于STUN的bingding请求用于连通性检查,因此STUN bingding响应中会携带agent的在同对端通信时NAT映射地址,这个地址有可能同之前流程学习到的地址都不相同,体现为一个新的candidate,称之为peer reflexive candidate,这个candidate同样会被用于后续联通性测试,测试流程与其他candidate一样。

作为一种优化措施,一旦R收到L的检查消息,R会基于相同的candidate pair进行一次连通性检查调度。这个措施可以加速寻找到合适candidate的过程,被称之为triggered check。

通过这个握手,L和R就都知道了他们可以在这个pair上进行双向的端到端消息发送(和接收)。

2.3 Candidate排序

由于上述的检查流程基于所有的candidate pair,因此如果有一个pair可以正常运作的话,那么无论是什么检查顺序最终都能找到它。candidate按照一定规则排序是为了更快(更好)的产生最终的检测结果。candidate排序后的列表叫做check list。排序算法在4.1.2节描述,基于下述两条原则:

1. 每个agent将自身的candidate设置一个数字优先级,并将这个优先级信息随candidate发给对端

2. 本地和对端优先级联合作为pair的优先级,因此对于同一个candidate pair,两端的agent具有相同的优先级

当L和R存在于NAT之后时,第二条对于他们之间的ICE流程的正常工作尤为重要。常见的情况是NAT在内部的agent向外部的一个host发送报文之前,不转发该host向内部的agent发送的报文。因此,ICE的在每个方向的检查都不会成功直到两端都通过各自的NAT执行了check之后才行。

agent遍历check list,逐条周期性的发送STUN请求。这个流程称为ordinary checks。

一般情况下,优先级算法被设计让相似类型的candidate具有相似的优先级,以使得更直接的路由优先于非直接的路由。尽管如此,在这些原则的指导下,agent还是有一些手段调整自身的算法。

2.4 Frozen candidate

前面的描述主要关注于agent期望建立只有一个component(媒体流的一部分,要求一个独立的传输地址;一条媒体流可能要求多个component,每个都是独立工作的)的媒体会话。典型的情况下(例如RTP和RTCP),agent实际需要的是多条流。

每个component的网络属性常常是非常相似的。(特别是对于RTP和RTCP要求通过同一个IP地址发送和接收)因此一个媒体component获取到的信息对于另一个在决定最好的candidate选择方面是很有用的。ICE通过一个“frozen candidates”的机制来实现这个机制。

每个candidate都关联一个称为foundation的属性。两个相似的candidate具有相同的foundation----相同的candidate类型,源于相同的host candidate,使用相同的协议。否则他们的foundation就不同。一个candidate pair同样具有foundation,就是简单的将两个candidate的foundation做一个拼接。初始情况下,一个唯一的foundation只有一个candidate pair用于测试,其他的被标记为frozen。当某个candidate pair连通性检测成功,那么带有相同foundation的其他candidate pair被**。这样就阻止了哪些表面上看起来很有吸引力实际上会失败的那些检查。

这里我们将frozen作为一个单独的机制来描述主要用于说明的目的,实际上它是整个ICE流程的一部分。ICE的优先级算法会自动确保合适的candidate 是**的并且按照合适的顺序启动检测。

2.5 检查机制的安全考虑

由于ICE机制用于发现用于agent之间媒体收发的地址,因此确保这个流程不被劫持来将媒体发往错误的位置就很重要。每一个STUN的连通性检查都需要进行消息认证码(MAC)的计算,这个认证码通过信令通道进行交换。MAC提供了消息完整性机制以及数据源的认证以阻止攻击者伪造或者修改连通性检查消息。特别来说,如果SIP协议主叫使用ICE,并且它的会叫分叉(fork)了,那么ICE交换再每个分叉的接收者之间独立进行。这种情况下,信令层秘钥的交换是每个分叉的接收者都有独立的ICE key交换。

2.6 ICE判定

ICE检测按照特定的顺序执行,先检测优先级高的candidate pair,然后再检测优先级低的。一种简单的方式是,一旦每条流的每个componenet都有一条pair检测成功时,ICE就可以给出判定了。而实际上,还存在更合理的做法,下面会接着描述。在检测中,可能存在一个高优先级的检测时间比低优先级的检测耗时更长的情形。这种情况下,让检测机制多运行一段时间可能会得到更好的结果。更为基本的是,pair的优先级定义其实未必就是通信链路好坏的等级。例如,我们的目标是选择一条低延时的媒体路径,那么使用中继很可能就比不使用中继时延高,但这仅仅是可能。使用RTT测量机制,结果可能会显示出低优先级pair反而比高优先级的更好的情形。

基于此,ICE流程会配置通信中的一个agent为controlling agent,另一个为controlled agent。controlling agent有权提名哪个candidate被启用来进行媒体通信。这种提名有两种做法:regular提名方式和aggressive提名方式。

在regular提名方式下,controlling agent会让检测流程持续进行,直到每个流都存在至少一个有效的candidate pair。然后从这些有效的candidate pair中选择一个作为提名的candidate pair,基于这个提名的candidate pair发送第二个STUN请求,这个请求会设置一个标志用于指示这个pair被提名了。流程如图4所示。

rfc5245中文翻译(持续更新中)

一旦这个STUN事务完成,双方都取消掉在这个媒体流上的其他后续检测。ICE将会采用这个pair用于媒体发送。这样的pair被称为selected pair。

在aggressive提名方式下,controlling agent会在所有的STUN请求中设置提名标记。这种方式下,一旦一个检测成功,那么ICE流程就完成了,也不用发送第二个STUN请求。selected pair就是优先级最高的那个有效的pair。aggressive提名方式比regular提名方式流程更为高效,但是缺乏灵活性。aggressive提名流程如图5所示。

rfc5245中文翻译(持续更新中)

所有流的检测都完成了,如果selected pair同原来的媒体协商中的SDP的m行和c行的地址(default candidate)不一样,那么controlling agent会发送一个更新后的OFFER。

ICE判定后,单条或者所有的流在任何时候可以被任意一方重启ICE流程。重启操作通过发送一个更新后的OFFER来指示。

2.7 Lite实现

为了能在呼叫中支持ICE,双方agent都应该支持它。但是某些agent一致部署在公网上具有公网的IP地址,可以直接同任何同等的对端通信。为了让这些设备更容易的支持ICE,ICE定义了一种特殊的实现方式成为Lite实现(相对于一般流程称为Full实现)。Lite实现无需收集candidate,任何流中都只包含自身的host candidate。Lite agent也不执行连通性检测或者运行状态机制,他们只要能够正常响应连通性检测的请求即可。当一个lite实现的agent同一个full实现的agent通信时,full agent将会作为controlling的角色,而lite agent会作为controlled的角色。如果通信双方都是lite实现的话,那么都会启动任何检测流程。

为了指导Lite实现,参考附录A的讨论。

需要重点指出的是将Lite实现加入到本规范是为了给Full实现提供基础。即使对于那些一直处于公网的设备来说,可以的话支持Full实现也应该是优选的。

3 术语

(略)

4 发送初始OFFER

为了协商流程中发送初始的OFFER,agent需要先做 (1) 收集candite (2) candidate排序 (3) 剔除冗余candidate (4) 选择默认candidate (5) 编码构造发送OFFER。除了第5步,其他的在Full和Lite实现方式都不同。

4.1 Full实现的要求

4.1.1 收集candidate

agent需要再会话启动前夕收集candidate。这个时机可能是用户接口间接要求,或者是初始会话的显示请求。每个candidate都是一个传输地址,包括类型和一个base。本文定义了四中类型--host candidate,server reflexive candidate, peer reflexive candidate和relayed candidate。server relfexive candidate通过STUN或者是TURN收集,relayed candidate通过TURN收集。peer reflexive candidate可以在ICE的后续阶段中获取到,它是连通性检查过程中产生的。而一个candidate的base就是收集这个candidate时实际发出请求消息的那个candidate。

4.1.1.1 host candidate

第一步就是收集host candidate。host candidate通过在本主机上接口(物理的或者虚拟的,例如v*n)IP地址上绑定UDP端口(通常是临时的)可以获取到。

对于agent期望使用的每个UDP媒体流来说,应该为这个主机上的每个IP地址的每个流的每个component获取一个candidate。通过在特定的IP地址绑定UDP端口可以获取到每个candidate。一个host candidate总是与一个特定的component有关。每个component都会分配一个ID,称之为component ID。对于基于RTP的媒体流来说,RTP本身有一个component ID是1,RTCP的component ID是2。如果agent使用了RTCP,那么也必须为它获取candidate。如果agent同时使用了RTP和RTCP的话,那么最后会得到rfc5245中文翻译(持续更新中)个candidate,K是IP地址的数目。

host candidate的base就是它本身。

4.1.1.2 server reflexive和relayed candidate

agent应该获取server reflexive和relayed candidate。这里说应该意味着可以根据业务状况改变这个约束。因为对于从来不连接外部网络或者是只在封闭网络内部通信的agent来说使用STUN或者是TURN是不必要的。这种情况下,Full实现可以被用于多宿主或者双栈的主机选择合适的candidate。TURN服务器费用较高,启动ICE流程后,只有在两个agent都处于对称性NAT后面的时候才会用到。因此一些部署场景下倾向于不支持这类小众场景从而不使用TURN服务器。如果一个agent不收集server reflexive candidate或者relayed candidate的话,建议该功能上还是完全支持但是通过配置方式关闭,这样将来条件发生变化是可以通过配置重启启用。

如果agent需要同时收集server reflexive和relayed candidate的话,那么需要TURN服务器。如果只是收集server reflexive candidate的话,那么STUN服务器就可以了。

agent紧接着将所有的host candidate同STUN或者TURN服务器结对,服务器可能是配置的也可能通过其他手段发现的。如果是配置的,建议配置为域名的方式,可以采用rfc5398的DNS流程发现STUN服务器,使用rfc5766的DNS流程发现TURN服务器。

本规范只考虑使用单个STUN或者TURN服务器。如果服务器存在多个选择(例如通过SRV DNS学习到有多条DNS记录),那么对于特定的一个会话,所有的candidate应该使用同一个STUN或者TURN服务器。这有助于改善ICE的流程效率。该处理的结果就是一个host candidate同STUN或者TURN服务器的pair列表。然后agent选择一个pair,从这个pair的host candidate向服务器发送Binding或者Allocate请求。向STUN服务器的Bingding请求不需要认证,任何响应中的alternate-server属性都要忽略。agent必须支持rfc5389定义的Binding请求的前向兼容模式。Allocate请求应该使用一个长期凭证进行认证,凭证可以通过其他方式获得。

然后没过Ta毫秒,agent就可以产生一个新的STUN或者是TURN事务。这个事务既可以是前一个事务由于可恢复的错误响应失败(例如认证失败)导致的重试,也可以是基于另一个host candidate同服务器pair的新事务。agent应该保持新事物产生的间隔不要唱过Ta毫秒。第16节描述了如果设置Ta定时器和STUN重传定时器RTO。

agent将会收到binding或者是Allocate的响应。成功的Allocate响应会向agent提供一个server reflexive candidate(通过映射地址参数获取到)和一个relayed candidate(包含在XOR-REALYED-ADDRESS参数中)。如果Allocate请求由于服务器资源不足的原因被拒绝,agent应该替换使用Binding请求来获取server reflexive candidate。Binding请求的响应则只会提供server reflexive candidate(同样通过映射地址参数获取到)。server reflexive candidate的base就是Allocate或者Binding请求发送的那个host candidate,而relayed candidate的base则是他自己。如果relayed candidate同host candidate一样(不常见但是有可能),则必须忽略掉。

4.1.1.3 计算foundation

最后agent会给每个candidate赋予一个foundation。foundation是在一个会话范围内有效的标识符。满足下列条件的两个candidate具有相同的foundation ID:

  • 同样的类型(host,relayed,server reflexive或者是peer reflexive)。
  • base具有相同的IP地址(端口可以不同)。
  • 对于reflexive 和relayed candidate,是从同一个STUN后者TURN服务器获取到的。
  • 采用相同的传输协议(TCP,UDP等)

反之如果两个candidate的类型不一样,base地址不一样,获取的STUN或者TURN服务器不是同一个,或者协议不一样,那么他们的foundation就不应该相同。

4.1.1.4 candidate保活

一旦server reflexive或者是relayed candidate分配成功,他们需要一直保持到ICE处理结束。对于Binding请求获取到的server reflexive candidate,这个绑定关系需要通过额外的Bingding请求来保持。而通过Allocate获取到资源绑定的刷新,则需要rfc5766定义的Refresh事务来完成。这个Refresh事务同样会刷新server reflexive candidate。

4.1.2 设置candidate优先级

优先级排序的处理结果就是每个candidate设置一个优先级。对每个candidate,在对应的媒体流里面都应该有一个唯一的优先级,必须是1到rfc5245中文翻译(持续更新中)之间的一个正整数。这个优先级被ICE用来确定连通性检测的优先级顺序和candidate选择的顺序。

agent应该按照4.1.2.1节描述的公式计算优先级,参数设置遵循4.1.2.2节描述的原则。如果agent向选择使用不同的公式,ICE的流程完成时间会更长,因为两端的agent的配合的不一致。

4.1.2.1 建议公式

使用这个公式计算优先级需要综合考虑candidate类型的选择顺序和本地IP地址的选择顺序(如果是多宿主主机的话)。将这两个选择合并计算一个candidate的优先级。计算公式如下:

rfc5245中文翻译(持续更新中)

type preference必须是0到126(包含0和126)之间的一个数字,表示类型的优选。126是最优选择,0是最次选择。设置为0表示这种类型的candidate是最后的选择。相同类型的candidate,type preference必须一样,反之不同类型的candidate,type preference不能一样。peer reflexive的type preference必须必server reflexive的type preference值大。注意基于4.1.1节获取到的candidate列表里面不会有peer reflexive candidate,这种类型只能在ICE的连通性检查流程中学习到。

local preference必须是0到65535(包含0和65535)之间的一个数字,在多宿主的主机中,表示某个特定IP地址的优选顺序。65535是最优选择,0是最次选择。如果只有一个IP,该值必须设置为65535。更通用的说法,如果某个流的某个component具有多个相同类型的candidate,那么他们各自的local preference值需要唯一。本规范中,这种情况只会发生在多宿主的场景下。对于双栈的主机,local preference应该设置为rfc3484中描述的IP地址的优先级值(precedence value)。

component ID为相应candidate的component ID,取值范围为1到256(包括1和256)。

4.1.2.2 类型和本地优选项选择的指导方针

type preference和local  preference值设置的第一个考虑因素就是媒体中介的应用,例如TURN服务器,v*n服务器。或者是NAT网关。当存在中介媒体的场景下,媒体在到达接收端之前首先要经过媒体中介。relayed candidate就是一种使用了媒体中介的类型。另外一种就是通过v*n接口下获取到的host candidate。当媒体通过中介传输时,会增加传输时延。同样由于增加的路由跳数会增大丢包率。它还有可能提升业务运营费用,因为用于转发媒体的媒体中介由运营商提供的。如果上述因素比较重要,那么relayed类型的优先级就应该比host类型的优先级低。建议host类型的值设置为126,server reflexive的值设置为100, peer reflexive的值设置为110,而relayed类型的值设置为0。进一步来说,如果一个主机是多宿主的或者有多个IP地址,那么从v*n获取到的host candidate的local preference应该设置为0。

优先级选择的第二个考虑因素是IP地址族。ICE在IPV4和IPV6协议下都能工作。因此它提供了一种转换机制,允许双栈主机优选IPV6地址建立连接,但是在IPV6网络断开(例如rfc3056描述的6to4中继失败的情况)的情况下回滚到IPV4工作。对于同时支持IPV6和6to4地址的主机同样有用。这种情况下,IPV6地址会被指定更高优先级的local preference,其次是6to4地址,再次是IPV4地址。这样可以是该主机立即启用IPV6地址,一旦连接的对端不支持本地IPV6连接的时候回滚采用到6to4地址。

第三个考虑因素是安全性。如果一个用户是远程工作者,因此既有本地的连接,也有通往公司的v*n连接。这个用户期望在同公司内部的语音通信使用公司网络。而同公司外部的人通信时采用本地网络。这种情况下,v*n的地址就要比其他地址优先级高。

第四个考虑的因素是就是网络拓扑感知程度。这对使用了中介媒体的candidate最为有效。如果agent预先设置或者是动态发现了这些中介媒体相对于自己的网路距离,那么他就可以将距离更近的中介媒体相关的candidate赋予更高的local preference值。

4.1.3 剔除冗余candidate

接下来agent将会剔除冗余的candidate。如果两个candidate的传输地址相同,而且base一致,则认为存在一个冗余的candidate。注意如果两个candidate虽然传输地址相同但是base不一样则不认为是冗余。常见的情况是,如果agent不在NAT后面的话,server reflexive candidate和host就是冗余的。agent应该剔除冗余的两个candidate中优先级较低的那个。

4.1.4 选择默认candidate

如果一个candidate是默认的,那么在同一个不支持ICE流程的对端进行通信时,这个candidate就会作为对端媒体的目标地址。这个目标地址称为default destination。在同ICE感知的对端进行通信时,如果默认的candidate在ICE处理后没有被选择用于媒体通信,那么刷新的OFFER/ANSWER协商流程就用来“修正”SDP,使得default destination同ICE的选择相一致。如果ICE流程最后选择的刚好就是默认的candidate,不要求有这个刷新协商流程。

agent必须选择一系列的默认candidate,每个有效流的每个组件各一个。这里说有效流是指端口号不为0(rfc3264中用于拒绝一个流)。因此标记为a=inactive或者是带宽设置为0的流也是有效流。

建议默认candidate设置为最有可能被采用来作为同对端通信的candidate。建议默认是顺序是relayed candidate(如果存在),server reflexive candidate(如果存在),最后是host candidate。

4.2 Lite实现的要求

Lite实现只使用host candidate。一个Lite实现必须给每个流的每个组件不分配或者分配1个IPV4地址的candidate。它有可能不分配或者分配多个IPV6的candidate,不要超过本机IPV6地址数目。由于每个流的component不能有多个IPV4的candidate,因此如果本机存在多个IPV4地址的话,那么必须从其中选一个。如果主机支持双栈,那么给每个component分配一个IPV4的candidate,再分配一个全局的IPV6地址。Lite实现ICE流程无法动态从这些candidate中选择,因此一定范围内不建议超过一个candidate,因为只有连通性检测才能决定最后用哪个。

每个component都有一个ID叫做component ID。对于基于RTP的流,RTP自身的ID是1,RTCP是2。如果启用了RTCP,那么也必须给他分配ID。

每个candidate都有一个foundation。不同的IP地址foundation必须不一样,反之相同的必须一样。给每个IP分配一个简单的递增的数字就可以了。另外,每个candidate必须设置一个媒体流范围的唯一的优先级。取值如下:

rfc5245中文翻译(持续更新中)

如果只支持IPV4,那么IP precedence 设置为65535.如果支持IPV6或者双栈,那么IP precedence 的设置参考rfc3484。

下一步agent为每个流的每个component选择一个默认的candidate。如果只支持IPV4,那么每个component只有一个candidate,他就是默认的candidate。如果是IPV6或者双栈主机,那么默认candidate的选择基于本地策略。默认是选择最优可能被对端 用于收发媒体的那个。对于只支持IPV6的主机,典型的就是全局的IPV6地址,对于双栈主机,建议用IPV4地址。

4.3 SDP编码

Full实现和Lite实现对于SDP的编码处理是一样的。

agent将会为每个需要支持的媒体流创建一个m行。SDP中媒体流的顺序对ICE处理有影响。ICE将会首先对第一个m行的媒体流做连通性检测,然后按照m行顺序依次执行。因此,agent应该将最重要的那个(如果有的话)流放到SDP的第一个。

一个媒体流的所有candidate都有一个candidate属性。第15节提供了构造这个属性的规则。这个属性包括IP地址,端口,传输协议,另外还有告知对端用于ICE流程正常工作的内容:优先级,foundation和component ID。另外还包括一些有助于调试或者其他功能的辅助信息:类型已经相关candidate的地址。

agent之间的STUN连通性检测使用STUN定义的短期凭证机制进行认证。这个机制依赖于一个用户名和密码,这些信息通过上层控制协议进行交换。ICE是通过OFFER/ANSWER机制来实施。用户名是通过将两个agent的用户名片段拼接而成,中间通过逗号隔开。每个agent同样提供一个密码用于验证接收消息的完整性检查。用户名片段和密码通过ice-ufrag和ice-pwd属性进行交换。除了提供安全机制,用户名具有消除检测操作同媒体流之间的区分和关联。设计目的参考附录B.4。

如果一个agent是Lite实现,它必须在SDP包含一个“a=ice-lite”的会话级别属性。如果是Full实现,则不能包含该属性。

默认candidate通过设置SDP媒体流的default  destination 来支持。对于基于RTP的,通过将IP地址和端口放到c行和m行来实现。如果使用了RTCP,必须通过rfc3605定义的a=rtcp属性来编码RTCP的candidate。如果没有使用RTCP,必须使用rfc3556定义的b=RS:0和b=RR:0来指示。

即使作为default destination的传输地址如果是同非ICE的对端通信,也必须出现一个或者多个a=candidate行中。

ICE提供扩展机制允许offer或者answer包含一系列的标识符用于指示agent支持的扩展。如果agent支持这些扩展,需要再ice-option属性中包含这些标识符。

如下是一个包含了ICE属性的SDO消息(为了可读性做了换行):

rfc5245中文翻译(持续更新中)

一旦一个agent发送了offer或者answer,则需准备在每个candidate上同时接收STUN和媒体报文。如11.1节讨论,媒体报文有可能先于以此candidate作为default destination的offer或者answer出现。

5 接收初始OFFER

当一个agent收到一个初始OFFER,它将检测offerer是否支持ICE,决定自己的角色,收集candidate,排序,选择默认candidate,编码和发送answer。对于full实现来说,还将构造check list以及开始连通性检测。

5.1 验证ICE是否支持

agent需要判定一下条件满足,才可以继续ICE的流程:在收到SDP中,每个流的媒体组件的default destination都出现在一个candidate属性中。例如对于RTP来说,c行和m行的IP地址和端口号出现在candidate属性中,rtcp属性的端口号也出现在candidate属性中。

如果这个条件不满足,那么agent必须按照rfc3264定义的正常流程处理而不是用本规范的后续ICE流程,除了以下的处理:

1. 遵循第10节的要求处理,该节描述了所有的agent的保活流程。

2. 如果由于存在candidate但是没有任何一个匹配default destination的原因导致不走ICE流程,还需要answer中包含一个a=ice-mismatch行。

3. 如果本端的默认candidate是从TURN获取到的relayed candidate,那么一收到这个SDP,就需要根据SDP里面的IP地址向TURN服务器创建permission。否则初始阶段对端在媒体流中发送的报文就可能会丢失。

5.2 角色判定

一个会话中,每个agent都要设定一个角色。角色分两种:controlling和controlled。controlling agent负责选择通信最终采用的candidate pair。对于full实现的agent,以为这需要对每一个流选择的candidate进行提名,在需要的时候基于ICE的选择结果发送刷新offer。对Lite实现的agent来说,作为controlling意味着基于OFFER和ANSWER(对于IPV4,只有一个pair)选择一个candidate pair,如果有必要发送刷新的offer体现这个选择(对于IPV4,永远不需要)。controlled  agent被动接受candidate pair的选择结果,也不产生刷新的offer去告知这个信息。本节后续会详细描述controlling和controlling节点各自的处理流程。

角色的选择以及对应的处理行为如下:

都是full实现:产生offer的一方作为controlling,另一端作为controlled。双方都构造check list列表,运行ICE状态机,执行连通性检测。controlling agent根据8.1节所述逻辑提议ICE最终选择的pair,然后双方都根据8.1.2节描述结束ICE流程。对于附录B.11描述的特殊场景下,双方都会误以为自己是controlling或者controlled。为了解决这个问题,每个agent都必须选择一个名为tie-breaker的随机数,该随机数在0到rfc5245中文翻译(持续更新中)之间平均分布(也就是一个64位的正整数)。这个数字用于在连通性检测时侦测和修正这种场景,详见7.1.2.2节描述。

一个full实现,一个lite实现:full实现作为controlling,lite作为controlled。由full实现的agent构造check list列表,运行ICE状态机,执行连通性检测。并且该agent还要根据8.1节所述逻辑提议ICE最终选择的pair,然后根据8.1.2节描述结束ICE流程。lite实现agent指示监听连通性监测请求,并且响应,然后根据8.2节所述进行ICE判定。对于lite实现,每个处理的媒体流都认为是Running态,整个ICE流程的状态也认为是处于Running态。

都是lite实现:产生offer的一方作为controlling,另一端作为controlled。这种场景下,都不启动连通性检测。只要offer/answer交换完成,双方都按照第8节描述的无连通性检测的流程处理。特殊场景下双方都可能认为他们是controlled或者是controlling角色,在后一种情况下,冲突由携带offer/answer的上层协议通过glare detection的能力进行解决。每个处理的媒体流都认为是Running态,整个ICE流程的状态也认为是处于Running态。

一旦角色被选定,那么这个结果将会一直保持直到ICE重启(参考9.1节)。ICE重启会导致角色和tie-breakers的重新选择。

5.3 收集candidate

在answer方一侧的处理流程与offer一方的流程一样,对于full实现参考流程4.1.1节描述,对于lite实现参考4.2节描述。这个动作建议在收到offer理解触发,甚至应该在通知用户呼叫到达之前。在agent启动时优肯就开始这个动作了。

5.4 设置candidate优先级

在answer方一侧的处理流程与offer一方的流程一样,对于full实现参考流程4.1.2节描述,对于lite实现参考4.2节描述。

5.5 选择默认candidate

在answer方一侧的处理流程与offer一方的流程一样,对于full实现参考流程4.1.4节描述,对于lite实现参考4.2节描述。

5.6 SDP编码

在answer方一侧的处理流程与offer一方的流程一样,full实现和lite实现一样,参考4.3节描述.

5.7 构造check list

只有full实现才构造check list。lite实现跳过这个步骤。

通过offer/answer交换,每个有效的媒体流都有一个check list。为了构造这样的check list,agent需要构造candidate pair,计算candidate pair的优先级,根据优先级进行排序,修剪这个排序后列表然后设置这个列表的状态。这些步骤下面将详细讲述。

5.7.1 构造candidate pair

首先,agent将一个流中的每个local candidate与同一个流的对端的每一个remote candidate结对构成pair。为了防止18.5.2节描述的攻击,agent可能限制接收offer或者answer中的candidate数目。一个local candidate只同那些相同的component ID和相同地址类型的remote candidate结对。因此有可能有些local candidate或者remote candidate无法结对。如果一个agent没有为一个流的所有component包含candidate的时候就会出现这个情况。这种情况下,这条媒体流的component数目会被减小,取双方提供的该流所有component ID的最大值中最小的那个值。

在使用RTP的场景中,这种情况会出现在一侧agent支持RTCP,而另外一端不支持的场景。举例来说,如果offerer能够支持RTP和RTCP复用端口(通过rfc5761定义的方式通过SDP属性来指示)。但是由于他不知道是否对端能够支持这种复用方式,因此他就offer中每个流携带了两个component。如果answerer也支持这种复用,那么将会在answer中每个流只包含一个component的candidate,就是最终复用的那个。ICE流程处理将这种情况视为只有一个component。

如果一个candidate pair的local和remote candidate都是默认的candidate,这个candidate pair很自然的被称为默认candidate pair。对于两方agent都不支持ICE的情况下,这个pair将会最终用于传输媒体。

为了帮助理解,图6展示了这些关键观念之间的关系--传输地址,candidate, candidate pair以及check list。另外指出了candidate和candidate pair的主要属性。

rfc5245中文翻译(持续更新中)

5.7.2 计算pair的优先级和排序

一旦这些pair构造完成,就将赋予它一个优先级。我们使用G代表controlling agent提供的candidate的优先级,使用D代表controlled agent提供的candidate的优先级。那么这个pair的优先级计算公式为:

rfc5245中文翻译(持续更新中)

这里G>D?1:0是一个表达式,意思是如果G比D大则为1,否则为0。一旦优先级设定后,就将这些pair按照优先级降序的方式进行排列。如果两个pair的具有相同的优先级,那么他们的排列顺序是任意的。

5.7.3 修剪pairs

这些排序后的pair列表决定了后续连通性检测的顺序。每次检测涉及到从local candidate发送请求到remote candidate。由于agent不能直接从server reflexive candidate发送请求,而只能从它的base candidate,因此agent会遍历排序后的candidate pair,如果local candidate是server reflexive类型,则将server reflexive candidate替换为它的base。执行这个操作后,agent必须修剪这个pair列表,将local candidate和remote candidate都相同的优先级低的pair去掉。结果就是该流的check list--一个排序后的candidate pair列表。

另外,为了限制18.5.2节描述的攻击,agent必须限制所有check list项的数目,并且该数目是可配的。建议默认是100,可以按照优先级从低到高方式以此裁剪直到check list项数目小于等于100。可能的话建议取更小的值,在实际的配置中可以包括一个the maximum number of plausible checks的配置项。这个配置的要求是为了提供一个工具,一旦部署发现问题时可以修改这个值。

5.7.4 计算状态

check list中每个candiate pair都有一个foundation和一个状态。这个foundation就是local和remote candidate的foundation的合并值。这个状态值是check list经过一定的算法给出的。状态存在五种取值:

Waiting:这个pair上还未执行检测,一旦处于check list中优先级最高waiting状态的pair,就会启动检测。

In-Progress:真正检测,但是事务还未完成。

Succeeded:已经检测完成并且成功。

Failed:已经检测完成但是失败了,可能是未收到响应,也可能是收到无法恢复的响应。

Frozen:检测机制被冻结,直到其他检测成功后运行这个pair解冻迁移到Waiting状态为止。

ICE运行中,pair的状态迁移按照图7所示。

rfc5245中文翻译(持续更新中)

一个check list中的pair的初始状态按照以下步骤检查设置:

1. 该check list的所有的pair设置为Frozen状态

2. agent检查第一条流(offer或者answer中SDP的一个m行表示的流)的check list。并且对于具有相同foundation的所有的pairs,将component ID最小的那个pair状态设置为Waiting,如果存在多个,则选优先级最高的那个。

某个check list会有些pair处于Waiting状态,而其他的check list所有的pair都处于Frozen状态。如果一个check list中存在Waiting状态的pair,称为active check list。所有的pair都处于Frozen状态的称为frozen check list。

check list自身也有一个状态,表征了那条流上的ICE检测状态。有三种状态:

Running:该流中ICE流程还在执行。

Completed:该流的所有component都已经产生了nominated pair。因此ICE已经完成,媒体流可以发送。

Failed:该流上的ICE流程检测失败。

当check list初始构造出来时,设置为Running状态。

整个ICE处理也有一个状态。如果ICE流程正在处理则处于Running态,如果ICE处理完成但是失败了,则处于Completed状态。状态迁移的规则如后续描述。

5.8 调度检测

只有full实现才产生检测。lite实现跳过该节所述的步骤。

一个agent可以执行ordinary检测和triggered检测。对于每个流,两种检测都受到一个周期性定时器的控制。agent维护一个FIFO队列,称之为triggered check queue,包含了下一个有效时刻将可以发送检测请求的candidate pair。定时器超时,agent将会从这个队列中取头一个,发送检测请求,并且将该pair设置为In-Progress。如果这个队列为空,那么ordinary检测。

一旦agent按照5.7节描述构造好check list,会为每个active check list设置一个定时器。这个定时器每Ta*N秒超时一次,N是active check list的数目(初始只有一个active check list)。具体实现可以将定时器超时频率设置得更低一些。实现同样要仔细地将这些定时器分散开来,防止这些定时器同时超时。Ta和重传定时器RTO的设置餐卡16节描述。乘数N使得aggregate 检测的流量分散到所有的active check list。定时器首次超时立即触发,一旦offer/answer交互完成立即启动 一次检测,Ta,秒后启动后续的检测(初始只有一个active check list)。

如果定时器超时没有triggered检测发送,那么agent必须按照下列步骤选择一个ordinary检测:

1. 寻找check list中状态为Waiting的pair中优先级最高的pair

2. 如果存在这样的pair:

* 基于该pair从local candidate向remote candidate发送STUN检测。构造STUN检测请求的步骤参考7.1.2节描述。

* 设置这个pair的状态为In-Progress。

3. 如果没有这样的pair:

* 寻找check list中状态为Frozen 的pair中优先级最高的pair。

* 如果存在这样的pair:

  +解冻此pair

  +基于此pair发起检测,状态切换为In-Progress

* 如果不存在这样的pair:

  +停止该check list的定时器

在计算消息完整性时,用到了从对端SDP中获取到的用户名片段和密码。使用到的本端的用户名片段是可以直接取到的。

6 接收初始ANSWER

本节描述一个agent收到一个ANSWER时所进行的流程,它将检测对端是否支持ICE,决定自己的角色,对于full实现来说,还将构造check list以及开始ordinary 连通性检测。

如果ICE被SIP使用,分叉会导致一个OFFER触发多个ANSWER。这种情况下对于每个ANSWER,ICE的处理时完全并行的,各自没有关联。就好像OFFER和这个ANSWER是一个独立的协商一样,具有自己的pair集合,check list,状态等等。唯一的特殊情况是一个pair的处理同另一个candidate的释放时的冲突,参考8.3节描述。

6.1 验证ICE是否支持

offerer的处理逻辑同answerer的一样,除了不用SDP中添加a=ice-mismatch以外。

某些场景下,answerer会忽略掉一个或者多个媒体流中的a=candidate属性,并且在answer中指示a=ice-mismatch。这个信号是要告诉offerer该会话不会启用ICE因为某些中间媒体修改了媒体component的地址但是没有相应修改candidate属性。第18节描述何种情况下会产生该问题。对于此问题本规范对于如何处理没有提供指导。

6.2 角色判定

offerer的处理流程同answerer一致,参考5.2节。

6.3 构造check list

只有full实现才构造check list。offerer的处理流程同answerer一致,参考5.7节。

6.4 启动Ordinary检测

只有full实现才启动ordinary检测。offerer的处理流程同answerer一致,参考5.7节。

7 执行连通性检测

本节描述连通性检测如何实施。所有的ICE实现要求遵循rfc5389,而不是老的rfc3489。尽管如此,一个full实现除了能发送检测请求(作为STUN客户端)还要能接收请求(作为STUN服务器端)。而lite实现只需要能接收检测请求就可以了。

7.1 STUN客户端流程

该流程定义了agent如何发送一个连通性检测。该检测可能为ordinary 或者是triggered 检测。这些流程只适用于full实现。

7.1.1 创建Relayed candidate的Permission

如果这个检测时通过一个relayed candidate发送的,需要首先创建Permission。为了创建Permission,需要遵循rfc5766定义的流程。这个Permission必须是用于发送到remote candidate的IP地址的。建议agent延迟创建TURN channel直到ICE完成,这期间通过CreatePermission请求来创建Permission。一旦建立,agent必须保持Permission**直到ICE判定。

7.1.2 发送请求

检测通过从local candidate向remote candidate发送一个Binding请求而产生。rfc5389描述了如果构造生成一个Binding请求。连通性检测必须使用STUN短期凭证机制。前向兼容rfc3489不应该使用或者假设被使用。必须使用指纹机制。

ICE扩展STUN定义了一些新的属性:包括PRIORITY, USE-CANDIDATE,ICE-CONTROLLED和ICE-CONTROLLING。这些新属性正式定义在19.1节,他们的使用如后续描述。这些扩展属性只用于ICE的连通性检测。

7.1.2.1 PRIORITY和USE-CANDIDATE

agent必须在Binding请求中包含PRIORITY属性,这个属性的值必须等于根据4.1.2节流程计算出来的值,对于peer reflexive candidate,该值可以通过检测流程学习到。(peer reflexive candidate的学习流程参考7.1.3.2.1节)这个优先级的值同该pair中local candidate的计算方式一样,除非这个candidate的类型是peer reflexive candidate。

controlling agent还可能在Binding请求中携带USE-CANDIDATE属性。controlled不能携带该属性。这个属性表示controlling agent期望终止这个component上的检测并且使用本pair作为最终使用。对于何时在请求中携带该属性8.1.1节提供了指导。

7.1.2.2 ICE-CONTROLLED和ICE-CONTROLLING

如果agnet的角色是controlled,则必须在请求中包含ICE-CONTROLLED属性。反正必须包含ICE-CONTROLLING属性。这两个属性的值为5.2节流程计算出来的tie-breaker值。这些属性的完整定义在19.1节。

7.1.2.3 构造凭证

用于连通性检测的Binding请求必须使用STUN短期凭证机制。凭证的用户名通过拼接对端发过来的username片段和本端的username片段。中间以冒号隔开。密码则使用对端提供的password。以如下场景为例:agent L是offerer,R是answerer。L的username片段为LFRAG,密码为LPASS。R的username片段为RFRAG,密码为RPASS。那么L发送给R的检测请求,使用的用户名为RFRAG:LFRAG,密码为RPASS。请求的响应使用的用户名和密码与请求的相同(注意子响应中不会出现USERNAME属性)。

7.1.2.4 DiffServ处理

如果agent对通信的媒体报文使用了Diffserv字段标记(rfc2457),那么对于检测报文应该使用相同的标记。

7.1.3 处理响应

当一个Binding响应收到后,会通过transition ID字段关联上Binding请求(rfc5389)。然后关联上发送该请求的candidate pair。本节描述了对于ICE流程对于响应响应消息处理的额外流程。

7.1.3.1 失败场景

如果STUN事物收到了一个487(Role Conflict)错误响应,那么就会检查在请求中包含了ICE-CONTROLLED还是ICE-CONTROLLING属性。如果请求包含了ICE-CONTROLLED属性,且本端当前为controlled的话,那么会将本端角色切换到controlling。反之切换到controlled角色。一旦切换后,会立即将触发487响应的candidate pair加入triggered check队列并且将该pair设置为Waiting状态。一旦该pair上发送新的请求,请求中的ICE-CONTROLLED或者ICE-CONTROLLING属性必须反应该agent的新角色。(注意原来的tie-breaker值无需重新选择)

角色的变更会导致pair优先级的重新计算,因为这个优先级值是角色值得函数。同时还会影响该agent的职责:本端是否需要选择nominated pair已经基于ICE的结论发送刷新的offer。

agent可以支持接收ICMP错误。如果这个STUN事务收到了一个ICMP错误,则设置这个pair的状态为Failed。如果该事务收到一个不可恢复的错误(rfc5389),同样设置该pair的状态为Failed。

agent必须检测响应消息的地址和端口号:响应的源IP和端口号必须等于请求的目的IP和端口号,响应的目的IP和端口号必须等于请求的源IP和端口号。换句话说,请求和响应的传输地址必须是对称的,如果不满足,则设置该pair的状态为Failed。

7.1.3.2 成功场景

满足以下条件认为检测成功:

  • 收到成功响应
  • 响应的源IP和端口号等于请求的目的IP和端口号
  • 响应的目的IP和端口号等于请求的源IP和端口号

7.1.3.2.1 发现Peer Reflexive Candidates

agent需要检测响应中的映射地址,如果这个传输地址不同于任何一个local candidate,那么他就代表了一个新的candidate——一个peer reflexive candidate。同其他candidate一样,他同样具有类型,base,优先级以及foundation。这些项的取值如下:

  • 类型设置为peer reflexive。
  • base设置为检测请求发送的那个local candidate
  • 优先级等于Binding请求中的PRIORITY属性的值
  • foundation根据4.1.1.3节流程选择

然后这个peer reflexive candidate加入到该媒体流的local candidate列表中。这个candidate的username片段和password同流中其他candidate的一样。这个candidate没有同其他对端candidate结对,这个不是必须的。基于7.1.3.2.2节流程,会立即产生一个valid pair。如果agent期望将这个peer reflexive candidate同除其他的(除开当前transaction的对端candidate)对端candidate结对的话,可以发送一个刷新的offer,并且携带这个新的candidate。这将触发他同所有其他的对端candidate结对。

7.1.3.2.2 构造Valid Pair

agent将会构造一个新的candidate pair,且其local candidate等于响应映射的那个地址,而remote candidate则等于请求发送的目标地址。这个pair称为valid pair,因为已经被STUN连通性检测验证过了。这个valid pair可能等同于触发检测的那个pair,也可能等同于check list的其他项,也有可能不同于任何一项。如果这个pair等同于触发检测的pair或者任何一个check list中的其他pair,那么那个pair也会被加入到VALID LIST中。该列表为agent为每个媒体流维护的一个队列。在ICE流程启动时该队列为空,在检测过程中不断添加而成。

这个pair不在check list中时很常见的情形。回想起check list的构造过程中,这些pair的local candidate没有一个是server reflexive类型的,对于server reflexive类型的candidate,都替换为他们的base candidate,并且可能因为冗余而被修剪掉了。当STUN检测的响应回来时,如果两个agent中间存在NAT,那么映射地址将是一种reflexive类型的地址,那么这种情况下,具有这种local candidate的pair将同任何check list中的pair相同。

如果这个pair不在任何check list中,那么agent将会为这个pair计算优先级:根据他的本端和对端candidate以及5.7节算法。local candidate的优先级取决于他的类型。如果不是peer reflexive类型,则等于SDP中为该candidate所赋的值。如果是peer reflexive类型,则等于响应对应Binding请求中携带的PRIORITY 属性的值。remote candidate的优先级则取对端的SDP中的相关值。如果对端地址在在remote candidate列表中不存在该值,那么这个检测随后应该有一个triggered check。这种情况下,这个remote candidate的优先级可以取这个triggered check的Binding请求中的PRIORITY属性值。然后将这个pair加入到VALID LIST中。

7.1.3.2.3 更新pair状态

 

7.1.3.2.4 更新Nominated标志

 

7.1.3.3 Check List和定时器状态更新

 

7.2 STUN 服务器端流程

7.2.1 Full实现的额外流程

7.2.1.1 检测和修正角色冲突

7.2.1.2 获取映射的地址

7.2.2 Lite实现的额外流程

8 ICE定论

9 后续的OFFER/ANSWER请求

10 保活

11 媒体处理

12 使用SDP

13 与ANAT的关系

14 可扩展性考虑

15 语法

16 设置Ta和RTO

17 样例

18 安全考虑

19 STUN扩展

20 可操作性考虑

21 IANA考虑

22 IAB考虑

23 致谢

(略)

24 参考

(略)

附A Lite和Full实现

附B 设计动机