11. Channels (通道)
通道 (Channels) 为客户端和服务器使用 ChannelData 消息发送应用程序数据提供了一种方式,其开销比 Send 和 Data 指示更少。
ChannelData 消息(参见第 11.4 节)以一个携带通道号 (Channel Number) 的两字节字段开始。此字段的值分配如下:
-
0x0000至0x3FFF:这些值永远不能用于通道号。 -
0x4000至0x7FFF:这些值是允许的通道号(16,383 个可能的值)。 -
0x8000至0xFFFF:这些值保留供将来使用。
由于这种划分,可以通过检查消息的前两位来区分 ChannelData 消息和 STUN 格式的消息(例如,Allocate 请求、Send 指示等):
-
0b00:STUN 格式的消息(因为 STUN 格式消息的前两位始终为零)。 -
0b01:ChannelData 消息(因为通道号是 ChannelData 消息中的第一个字段,通道号在范围 0x4000 - 0x7FFF 内)。 -
0b10:保留 -
0b11:保留
保留的值可能在将来用于扩展通道号的范围。因此,实现禁止 (MUST NOT) 假设 TURN 消息总是以 0 位开始。
通道绑定 (Channel Bindings) 始终由客户端发起。客户端可以在分配的生存期内的任何时间将通道绑定到对等方。客户端可以在与对等方交换数据之前将通道绑定到对等方,或者在与对等方交换数据(使用 Send 和 Data 指示)一段时间之后绑定,或者可以选择永远不绑定通道到对等方。客户端还可以将通道绑定到某些对等方,而不将通道绑定到其他对等方。
通道绑定特定于分配,因此在一个分配的通道绑定中使用通道号或对等方传输地址不会影响它们在不同分配中的使用。如果分配过期,其所有通道绑定也随之过期。
通道绑定由以下内容组成:
-
通道号。
-
传输地址(对等方的)。
-
过期时间计时器。
在分配的上下文中,通道绑定由通道号或对等方的传输地址唯一标识。因此,同一通道不能绑定到两个不同的传输地址,同一传输地址也不能绑定到两个不同的通道。
通道绑定持续 10 分钟,除非刷新。刷新绑定(通过服务器接收将通道重新绑定到同一对等方的 ChannelBind 请求)将过期时间计时器重置回 10 分钟。
当通道绑定过期时,通道变为未绑定。一旦未绑定,通道号可以绑定到不同的传输地址,传输地址可以绑定到不同的通道号。为了防止竞争条件,客户端必须 (MUST) 在通道绑定过期后等待 5 分钟,然后再尝试将通道号绑定到不同的传输地址或将传输地址绑定到不同的通道号。
当将通道绑定到对等方时,客户端应该 (SHOULD) 准备好在发送 ChannelBind 请求后立即在通道上从服务器接收 ChannelData 消息。在 UDP 上,客户端可能在收到 ChannelBind 成功响应之前从服务器接收 ChannelData 消息。
在另一个方向上,客户端可以 (MAY) 选择在接收到 ChannelBind 成功响应之前发送 ChannelData 消息。但是,这样做会冒着 ChannelData 消息被服务器丢弃的风险,如果 ChannelBind 请求由于某种原因未能成功(例如,如果请求通过 UDP 发送时数据包丢失,或服务器无法满足请求)。希望安全的客户端应该在通道绑定确认之前排队数据或使用 Send 指示。
11.1. Sending a ChannelBind Request (发送通道绑定请求)
使用 ChannelBind 事务创建或刷新通道绑定。ChannelBind 事务还创建或刷新到对等方的权限(参见第 8 节)。
要启动 ChannelBind 事务,客户端构造 ChannelBind 请求。要绑定的通道在 CHANNEL-NUMBER 属性中指定,对等方的传输地址在 XOR-PEER-ADDRESS 属性中指定。第 11.2 节描述了对这些属性的限制。
将通道重新绑定到它已经绑定的相同传输地址提供了一种刷新通道绑定和相应权限而无需向对等方发送数据的方法。但请注意,权限需要比通道更频繁地刷新。
11.2. Receiving a ChannelBind Request (接收通道绑定请求)
当服务器接收到 ChannelBind 请求时,它按照第 4 节加上此处提到的特定规则进行处理。
服务器检查以下内容:
-
请求同时包含 CHANNEL-NUMBER 和 XOR-PEER-ADDRESS 属性。
-
通道号在范围 0x4000 至 0x7FFE(包括)内。
-
通道号当前未绑定到不同的传输地址(相同的传输地址可以)。
-
传输地址当前未绑定到不同的通道号。
如果任何这些测试失败,服务器回复 400(错误请求,Bad Request)错误。
服务器可以 (MAY) 对 XOR-PEER-ADDRESS 属性中允许的 IP 地址和端口值施加限制 - 如果不允许某个值,服务器拒绝请求并返回 403(禁止,Forbidden)错误。
如果请求有效,但服务器由于某些容量限制或类似原因无法满足请求,服务器回复 508(容量不足,Insufficient Capacity)错误。
否则,服务器回复 ChannelBind 成功响应。成功的 ChannelBind 响应中没有必需的属性。
如果服务器可以满足请求,则服务器使用 CHANNEL-NUMBER 属性中的通道号和 XOR-PEER-ADDRESS 属性中的传输地址创建或刷新通道绑定。服务器还按照第 8 节中的描述为 XOR-PEER-ADDRESS 属性中的 IP 地址安装或刷新权限。
注意:服务器无需执行任何特殊操作来使用"无状态栈方法"实现通过 UDP 的 ChannelBind 请求的幂等性。重传的 ChannelBind 请求将简单地刷新通道绑定和相应的权限。此外,客户端必须在将先前绑定的通道号或对等方地址绑定到不同的通道之前等待 5 分钟,从而消除了事务最初失败但在重传时成功的可能性。
11.3. Receiving a ChannelBind Response (接收通道绑定响应)
当客户端收到 ChannelBind 成功响应时,它更新其数据结构以记录通道绑定现在处于活动状态。它还更新其数据结构以记录相应的权限已安装或刷新。
如果客户端收到 ChannelBind 失败响应,表明客户端和服务器之间的通道信息不同步(例如,意外的 400"错误请求"响应),则推荐 (RECOMMENDED) 客户端立即删除分配,并使用新分配重新开始。
11.4. The ChannelData Message (通道数据消息)
ChannelData 消息用于在客户端和服务器之间传输应用程序数据。它具有以下格式:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Channel Number | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
/ Application Data /
/ /
| |
| +-------------------------------+
| |
+-------------------------------+
Channel Number 字段指定数据传输所在的通道号,从而指定发送或将要接收数据的对等方的地址。
Length 字段指定应用程序数据字段的字节长度(即,它不包括 ChannelData 头的大小)。请注意,0 是有效的长度。
Application Data 字段携带客户端试图发送到对等方或对等方发送到客户端的数据。
11.5. Sending a ChannelData Message (发送通道数据消息)
一旦客户端将通道绑定到对等方,则当客户端有数据要发送到该对等方时,它可以使用 ChannelData 消息或 Send 指示,也就是说,客户端在通道存在时不必使用通道,并且在向对等方发送数据时可以自由混合使用这两种消息类型。另一方面,如果通道已绑定到对等方,服务器必须 (MUST) 使用 ChannelData 消息。
ChannelData 消息的字段按第 11.4 节中的描述填写。
在 TCP 和 TLS-over-TCP 上,ChannelData 消息必须 (MUST) 填充到四字节的倍数,以确保后续消息的对齐。填充不反映在 ChannelData 消息的长度字段中,因此 ChannelData 消息的实际大小(包括填充)是 (4 + Length) 向上舍入到最接近的 4 的倍数。在 UDP 上,不需要填充,但可以 (MAY) 包含。
然后在与分配关联的 5 元组上发送 ChannelData 消息。
11.6. Receiving a ChannelData Message (接收通道数据消息)
ChannelData 消息的接收方使用前两位将其与 STUN 格式的消息区分开来,如上所述。如果消息使用保留范围(0x8000 至 0xFFFF)中的值,则静默丢弃该消息。
如果 ChannelData 消息在 UDP 数据报中接收,并且如果 UDP 数据报太短而无法包含 ChannelData 消息声称的长度(即,UDP 头长度字段值小于 ChannelData 头长度字段值 + 4 + 8),则静默丢弃该消息。
如果 ChannelData 消息通过 TCP 或 TLS-over-TCP 接收,则 ChannelData 消息的实际长度如第 11.5 节所述。
如果 ChannelData 消息在未绑定到任何对等方的通道上接收,则静默丢弃该消息。
在客户端,推荐 (RECOMMENDED) 如果客户端认为对对等方没有活动权限,则客户端丢弃 ChannelData 消息。在服务器上,接收 ChannelData 消息禁止 (MUST NOT) 刷新通道绑定或到对等方的权限。
在服务器上,如果未检测到错误,服务器通过按如下方式构造 UDP 数据报将应用程序数据中继到对等方:
-
源传输地址是分配的中继传输地址,其中分配由 ChannelData 消息到达的 5 元组确定。
-
目标传输地址是通道绑定到的传输地址。
-
UDP 头之后的数据是 ChannelData 消息的数据字段的内容。
然后将生成的 UDP 数据报发送到对等方。请注意,如果 ChannelData 消息中的 Length 字段为 0,则 UDP 数据报中将没有数据,但仍会形成并发送 UDP 数据报。
11.7. Relaying Data from the Peer (从对等方中继数据)
当服务器在与分配关联的中继传输地址上接收到 UDP 数据报时,服务器按照第 10.3 节中的描述进行处理。如果该节指示应该发送 ChannelData 消息(因为有通道绑定到发送 UDP 数据报的对等方),则服务器按照第 11.5 节中的描述构造并发送 ChannelData 消息。