Twilio WebRTC的TURN中继在几分钟后随机停止工作。

12
我正在使用Twilio网络遍历服务作为我正在开发的本地应用程序的一部分,以执行点对点远程桌面连接。我们实现了WebRTC协议栈的子集,该子集相当于WebRTC数据通道(而不是WebRTC视频和音频协议)。当使用TURN中继时,从会话开始到几分钟到最多12分钟之间,TURN分配似乎会被随机无效。这个问题看起来非常类似于这个one,但提出的解决方法(发送静音音频)在我的情况下是不可接受的,因为我没有实现WebRTC音频/视频协议。
我已经为这个问题苦恼了两个星期,并将问题隔离为Twilio服务本身。为了比较,我使用了一个基于Web的WebRTC数据通道演示,使用火狐和Xirsys TURN服务器云。我有wireshark捕获显示火狐与Twilio断开连接,就像我的本地应用程序一样,而完全相同的火狐演示在使用Xirsys服务器时不会断开连接。
我最初使用的是Xirsys,但他们的服务不稳定,所以我转向了Twilio,这就是为什么我宁愿让Twilio解决这个问题而不是回到Xirsys。至少,我希望有两个WebRTC托管提供商可供选择,我知道它们应该可以正常工作。这就是我花时间详细解释问题的原因,以便能够得到解决。
以下是两个wireshark捕获(过滤掉点对点数据消息),显示Firefox使用WebRTC数据通道和Twilio TURN中继服务器:

enter image description here enter image description here

在第一次捕获中,4分钟后传输停止,第二次捕获后大约11分钟传输停止。在两次捕获中,Firefox检测到流量停止中继(在数据通道级别),并尝试通过发送寿命为零的刷新请求包进行优雅断开连接。两个优雅的断开连接都导致437分配不匹配错误,表明服务器甚至不知道Firefox正在尝试优雅关闭的分配情况。
对于我的本机应用程序,这通常采用创建权限请求消息的形式,该消息会因438“错误的随机数”错误而失败,如果客户端尝试更新不存在的分配上的权限,则基本上应该发生这种情况。错误代码438通常表示“过时的随机数”,这不是真正的错误,而是指示随机数已过期,客户端应使用包含在“错误”消息中的新随机数再次尝试。我花了一些时间才弄清楚,但即使错误代码是438,错误字符串也不同。我已经观察到与Xirsys的真正陈旧的随机数错误,并成功地使用错误响应中的新随机数更新了我的权限,因此我知道我可以在我的实现中正确处理此情况。
这是我使用的WebRTC数据通道演示的源代码: https://github.com/devolutions/webrtc-demo 为了比较,这是使用Xirsys TURN服务器云的相同Firefox数据通道演示:

enter image description here

在这个捕获过程中,我让演示运行了大约16分钟(它可以运行更长时间,我尝试过最长的是两个小时)。我们可以看到,在整个会话期间,流量一直在被中继,并且Firefox不断发送CreatePermission请求并成功。最后,优雅的断开连接是由Firefox关闭WebRTC数据通道触发的(而不是由于流量不再被中继而关闭)。与Twilio捕获不同,生存期为零的刷新请求成功:Xirsys TURN服务器仍然知道分配情况并返回成功响应,正如预期的那样。
值得注意的是,ICMP不可达错误是正常的,因为我认为在这种情况下,当响应返回时,Firefox不再侦听给定端口。换句话说,它发送了生存期为零的刷新请求,但没有等待答案返回。
目前,我别无选择,只能回到Xirsys,但我真的希望Twilio网络遍历服务可以修复。如果您对该问题有更多问题,请告诉我。
我已经上传了wireshark捕获文件here以供参考。
编辑:我修改了webrtc演示页面,使其在冰连接状态设置为“已断开”时不关闭连接。现在,当冰连接状态变为“失败”时,我会真正地断开连接。然而,实际上这并没有改变什么,因为在这种情况下,状态从“已断开”到“失败”只需要几秒钟。

由于我有新的相关截图和捕获内容,我正在更新原始问题以澄清Philipp Hancke指出的某些问题:

首先,这是一个新的捕获状态修复的截图(当状态变为“失败”时,浏览器才会关闭连接):

enter image description here

这次会话持续了整整18分钟,很有趣。这是在一个周六早上进行的,所以我猜问题可能与Twilio服务器当前的工作负载有关。然而,对我来说,它仍然以完全相同的方式失败。作为奖励,我们甚至有一个有效的陈旧nonce响应,并且被Firefox正确处理。
但是,如果我们从不同的角度观察相同的捕获,我们可以看到在Firefox认为连接已断开并发送生命周期为零的刷新请求之前,流量停止中继了30秒钟。与先前的捕获一样,服务器响应Allocation Mismatch错误,表示它不知道Firefox正在谈论哪个分配。

enter image description here

最后发送的8个数据包大小相同,因此我猜它们是重传。经过30秒的重传后,SCTP可能会认为传输已中断。
关于生存期为零的刷新请求,我进行了一项测试,在浏览器中早期关闭连接。在这种情况下,服务器识别分配并返回成功响应:

enter image description here

分配不匹配是最容易观察到的症状,但在我的本地应用程序测试中,我发现对于非零生命周期的刷新请求和CreatePermission请求(438“错误nonce”错误),也会出现类似的错误。然而,由于浏览器在30秒未传递数据后关闭连接,因此很难通过当前的webrtc演示观察到这些错误。如果我们可以将该超时时间更改为10分钟,那么我们也将看到这些错误。


这是一个又长又好的问题!!!! - shgnInc
1个回答

3

问题描述得非常好!

没有服务器日志,很难确定出了什么问题。我尝试使用appear.in的TURN服务器,它运行着最新版本的coturn,并且显示与Twilio服务器相同的行为。Xirsys似乎正在运行定制版本的coturn(从软件字段中可以看出是'Coturn-0.5' Xirsys Turn Services'),但coturn从未有过这样的版本。

在两个捕获中,Firefox检测到流量停止被中继(在数据通道级别),并通过发送寿命为零的刷新请求数据包尝试进行优雅的断开连接。

不完全正确。使用寿命为0的刷新请求来丢弃分配。此时无论服务器返回什么都无所谓,因为连接已经无法修复。

这是由peerjs关闭peerconnection引起的,如果iceconnectionstate更改为disconnected,则会在您的捆绑库版本中的这里

这太过激进(甚至不能解决问题),我们已经讨论过规范应该如何处理重新启动冰的事情,在这里,还链接到了有关断开状态的详细说明。

断开状态可能是由于丢失了一些数据包而发生的。但是,当出现轻微拥塞时,这是可能发生的。我建议在断开连接的情况下删除pc.close()。

如果您正在寻找其他TURN提供商,则Tokbox提供相同的服务。对于数据通道,适当运行的分布式TURN网络的延迟并不像VoIP那样重要,因此您可以在单个位置中运行自己的服务器。


这听起来像是coturn中的一个严重bug。作为基于UDP协议的TURN具有许多定时器,防止客户端在没有取消分配资源的情况下离开。例如,这可能是由于其中一个客户端未刷新权限(或刷新请求丢失)导致的。权限过期,导致数据包被静默丢弃,从而产生问题。为了排除这种可能性,需要在隔离环境中运行测试。 - Philipp Hancke
另一个可能的原因是凭据是基于时间的,在后续的分配请求中需要验证它们时已过期。这应该可以解决(请参见https://tools.ietf.org/html/draft-uberti-behave-turn-rest-00#section-4.2),但是...... 现在可能是在coturn存储库中提交错误报告的时候了。 - Philipp Hancke
我已经查看了RFC并且协议实现看起来都很好,计时器被Firefox和Chrome正确触发(刷新请求和创建权限请求)。我正在努力手动配置coturn以查看是否可以重现该问题,但我的主要担忧是我没有足够的流量与测试coturn服务器触发任何问题。我刚刚进行了一个测试,使用的是4.5.0.3版本,这是为Ubuntu 18.04打包的版本,它似乎工作得很好。您能告诉我您在appear.in服务器上使用的是哪个版本吗? - awakecoding
我已经使用单个coturn实例(4.5.0.7)进行了两个小时的测试,一切都很好。然而,我有一种感觉,问题不会在单个实例和非常少的流量下发生。在周末与twilio一起,中继工作了更长时间的事实似乎指向了一种在重负载下更快发生的错误类型。 - awakecoding
我的最新状态更新:我已经注册了Tokbox试用版,但它似乎是一个完全托管的解决方案,需要使用他们的SDK和信令服务器,所以对我来说不太适合。由于目前唯一适合我的WebRTC服务提供商是Xirsys,因此我已经开始在Azure上多个区域上托管coTURN。然而,到目前为止,我无法复制自己的coTURN实例中的问题,因此我无法向coTURN项目报告错误。我甚至不知道Twilio正在使用哪个版本。 - awakecoding
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接