17. 示例 (Example)
该示例基于图 8 中的简化拓扑.
+-----+
| |
|STUN |
| Srvr|
+-----+
|
+---------------------+
| |
| Internet |
| |
| |
+---------------------+
| |
| |
+---------+ |
| NAT | |
+---------+ |
| |
| |
| |
+-----+ +-----+
| | | |
| L | | R |
| | | |
+-----+ +-----+
Figure 8: Example Topology
两个 agents, L 和 R, 正在使用 ICE. 二者都是 full-mode ICE 实现, 并且在作为 controlling 方时使用 aggressive nomination. 两个 agents 都只有一个 IPv4 地址. 对于 agent L, 该地址是私有地址空间 [RFC1918] 中的 10.0.1.1; 对于 agent R, 该地址是 public Internet 上的 192.0.2.1. 二者配置了相同的 STUN server (为简化示例而如此显示, 实际上 agents 不需要使用相同的 STUN server), 该 server 在 IP 地址 192.0.2.2 和端口 3478 上监听 STUN Binding requests. 本示例不使用 TURN servers. agent L 位于 NAT 后面, agent R 位于 public Internet 上. 该 NAT 具有 endpoint independent mapping property 和 address dependent filtering property. NAT 公网侧的 IP 地址是 192.0.2.3.
为便于理解, transport addresses 使用具有助记名称的变量列出. 名称格式为 entity-type-seqno, 其中 entity 指 transport address 所在 IP 地址所属实体, 取值为 "L", "R", "STUN" 或 "NAT". type 对于 public transport addresses 为 "PUB", 对于 private transport addresses 为 "PRIV". 最后, seq-no 是序列号, 对特定实体上同一类型的每个 transport address 都不同. 每个变量都有 IP 地址和端口, 分别表示为 varname. IP 和 varname. PORT, 其中 varname 是变量名.
STUN server 具有 advertised transport address STUN-PUB-1 (即 192.0.2.2:3478).
在 call flow 本身中, STUN messages 标注了若干属性."S=" 属性指示消息的 source transport address."D=" 属性指示消息的 destination transport address."MA=" 属性用于 STUN Binding response messages, 指 mapped address."USE-CAND" 表示存在 USE-CANDIDATE 属性.
call flow 示例省略了 STUN authentication 操作和 RTCP, 并聚焦两个 full 实现之间单个媒体流的 RTP.
L NAT STUN R
|RTP STUN alloc. | |
|(1) STUN Req | | |
|S=$L-PRIV-1 | | |
|D=$STUN-PUB-1 | | |
|------------->| | |
| |(2) STUN Req | |
| |S=$NAT-PUB-1 | |
| |D=$STUN-PUB-1 | |
| |------------->| |
| |(3) STUN Res | |
| |S=$STUN-PUB-1 | |
| |D=$NAT-PUB-1 | |
| |MA=$NAT-PUB-1 | |
| |<-------------| |
|(4) STUN Res | | |
|S=$STUN-PUB-1 | | |
|D=$L-PRIV-1 | | |
|MA=$NAT-PUB-1 | | |
|<-------------| | |
|(5) Offer | | |
|------------------------------------------->|
| | | |RTP STUN
alloc.
| | |(6) STUN Req |
| | |S=$R-PUB-1 |
| | |D=$STUN-PUB-1 |
| | |<-------------|
| | |(7) STUN Res |
| | |S=$STUN-PUB-1 |
| | |D=$R-PUB-1 |
| | |MA=$R-PUB-1 |
| | |------------->|
|(8) answer | | |
|<-------------------------------------------|
| |(9) Bind Req | |Begin
| |S=$R-PUB-1 | |Connectivity
| |D=L-PRIV-1 | |Checks
| |<----------------------------|
| |Dropped | |
|(10) Bind Req | | |
|S=$L-PRIV-1 | | |
|D=$R-PUB-1 | | |
|USE-CAND | | |
|------------->| | |
| |(11) Bind Req | |
| |S=$NAT-PUB-1 | |
| |D=$R-PUB-1 | |
| |USE-CAND | |
| |---------------------------->|
| |(12) Bind Res | |
| |S=$R-PUB-1 | |
| |D=$NAT-PUB-1 | |
| |MA=$NAT-PUB-1 | |
| |<----------------------------|
|(13) Bind Res | | |
|S=$R-PUB-1 | | |
|D=$L-PRIV-1 | | |
|MA=$NAT-PUB-1 | | |
|<-------------| | |
|RTP flows | | |
| |(14) Bind Req | |
| |S=$R-PUB-1 | |
| |D=$NAT-PUB-1 | |
| |<----------------------------|
|(15) Bind Req | | |
|S=$R-PUB-1 | | |
|D=$L-PRIV-1 | | |
|<-------------| | |
|(16) Bind Res | | |
|S=$L-PRIV-1 | | |
|D=$R-PUB-1 | | |
|MA=$R-PUB-1 | | |
|------------->| | |
| |(17) Bind Res | |
| |S=$NAT-PUB-1 | |
| |D=$R-PUB-1 |
| |MA=$R-PUB-1 | |
| |---------------------------->|
| | | |RTP flows
Figure 9: Example Flow
首先, agent L 从其本地 IP 地址获得一个 host candidate (图中未显示), 并从该 candidate 向 STUN server 发送 STUN Binding request, 以获得 server reflexive candidate (消息 1-4). 回忆一下, NAT 具有地址和端口独立映射属性. 这里, 它为该 UDP request 创建 NAT-PUB-1 的 binding, 该 binding 成为 RTP 的 server reflexive candidate.
agent L 为 host candidate 设置 type preference 126, 为 server reflexive 设置 100.local preference 为 65535. 基于此, host candidate 的 priority 为 2130706431, server reflexive candidate 的 priority 为 1694498815.host candidate 被分配 foundation 1, server reflexive 被分配 foundation 2. 它选择 server reflexive candidate 作为 default candidate, 并将其编码到 m 和 c lines 中. 生成的 offer (消息 5) 如下 (为清晰起见进行了折行):
v=0
o=jdoe 2890844526 2890842807 IN IP4 $L-PRIV-1.IP
s=
c=IN IP4 $NAT-PUB-1.IP
t=0 0
a=ice-pwd:asd88fgpdd777uzjYhagZg
a=ice-ufrag:8hhY
m=audio $NAT-PUB-1.PORT RTP/AVP 0
b=RS:0
b=RR:0
a=rtpmap:0 PCMU/8000
a=candidate:1 1 UDP 2130706431 $L-PRIV-1.IP $L-PRIV-1.PORT typ
host
a=candidate:2 1 UDP 1694498815 $NAT-PUB-1.IP $NAT-PUB-1.PORT typ
srflx raddr $L-PRIV-1.IP rport $L-PRIV-1.PORT
将变量替换为其值后的 offer 如下 (为清晰起见进行了折行):
v=0
o=jdoe 2890844526 2890842807 IN IP4 10.0.1.1
s=
c=IN IP4 192.0.2.3
t=0 0
a=ice-pwd:asd88fgpdd777uzjYhagZg
a=ice-ufrag:8hhY
m=audio 45664 RTP/AVP 0
b=RS:0
b=RR:0
a=rtpmap:0 PCMU/8000
a=candidate:1 1 UDP 2130706431 10.0.1.1 8998 typ host
a=candidate:2 1 UDP 1694498815 192.0.2.3 45664 typ srflx raddr
10.0.1.1 rport 8998
agent R 收到该 offer. agent R 会获得一个 host candidate, 并从它获得一个 server reflexive candidate (消息 6-7). 由于 R 不在 NAT 后面, 该 candidate 与其 host candidate 相同, 并且二者共享相同 base. 因此, 它丢弃该冗余 candidate, 最终只有一个 host candidate. 使用与 L 相同的 type 和 local preferences, 该 candidate 的 priority 为 2130706431. 它为其单个 candidate 选择 foundation 1. 其生成的 answer 如下:
v=0
o=bob 2808844564 2808844564 IN IP4 $R-PUB-1.IP
s=
c=IN IP4 $R-PUB-1.IP
t=0 0
a=ice-pwd:YH75Fviy6338Vbrhrlp8Yh
a=ice-ufrag:9uB6
m=audio $R-PUB-1.PORT RTP/AVP 0
b=RS:0
b=RR:0
a=rtpmap:0 PCMU/8000
a=candidate:1 1 UDP 2130706431 $R-PUB-1.IP $R-PUB-1.PORT typ host
填入变量后:
v=0
o=bob 2808844564 2808844564 IN IP4 192.0.2.1
s=
c=IN IP4 192.0.2.1
t=0 0
a=ice-pwd:YH75Fviy6338Vbrhrlp8Yh
a=ice-ufrag:9uB6
m=audio 3478 RTP/AVP 0
b=RS:0
b=RR:0
a=rtpmap:0 PCMU/8000
a=candidate:1 1 UDP 2130706431 192.0.2.1 3478 typ host
由于双方都没有指示自己是 lite, 发送启动 ICE 处理的 offer 的 agent (agent L) 成为 controlling agent.
agents L 和 R 都将 candidates 配成 pairs. 二者最初都有两个 pairs. 但是, agent L 会 prune 包含其 server reflexive candidate 的 pair, 只剩一个. 在 agent L 处, 该 pair 的 local candidate 为 $L_PRIV_1, remote candidate 为 $R_PUB_1, candidate pair priority 为 4.57566E+18 (注意, 实现会将其表示为 64-bit integer, 以免丢失精度). 在 agent R 处, 有两个 pairs. 最高优先级 pair 的 local candidate 为 $R_PUB_1, remote candidate 为 $L_PRIV_1, priority 为 4.57566E+18; 第二个 pair 的 local candidate 为 $R_PUB_1, remote candidate 为 $NAT_PUB_1, priority 为 3.63891E+18.
agent R 为第一个 pair (两个 host candidates 之间) 开始其 connectivity check (消息 9). 由于 R 是该会话的 controlled agent, 该 check 省略 USE-CANDIDATE 属性. agent L 的 host candidate 是私有地址且位于 NAT 后面, 因此该 check 不会成功, 因为分组无法从 R 路由到 L.
当 agent L 收到 answer 时, 它执行其唯一的 connectivity check (消息 10-13). 它实现 aggressive nomination algorithm, 因此在该 check 中包含 USE-CANDIDATE 属性. 由于该 check 成功, agent L 创建一个新 pair, 其 local candidate 来自 Binding response 中的 mapped address (消息 13 中的 NAT-PUB-1), remote candidate 是 request 的 destination (消息 10 中的 R-PUB-1). 该 pair 被加入 valid list. 此外, 由于 Binding request 包含 USE-CANDIDATE 属性, 它被标记为 selected. 由于该媒体流的一个 component 在 Valid list 中已有 selected candidate, 此流的 ICE 处理进入 Completed 状态. agent L 现在可以根据需要发送媒体.
agent R 在收到来自 agent L 的 STUN Binding request (消息 11) 后不久, 会生成其 triggered check. 该 check 恰好匹配其 check list 上的下一个 check, 即从其 host candidate 到 agent L 的 server reflexive candidate. 该 check (消息 14-17) 将成功. 因此, agent R 使用 response 中的 mapped address 作为 local candidate (R-PUB-1), 使用 request 的 destination (NAT-PUB-1) 作为 remote candidate, 构造新的 candidate pair. 该 pair 被加入该媒体流的 Valid list. 由于该 check 是针对包含 USE-CANDIDATE 属性的 check 反方向生成的, 该 candidate pair 被标记为 selected. 因此, 此流的处理进入 Completed 状态, agent R 也可以发送媒体.