文章目录
- 1. 背景
- 2. 问题分析
- 3. 案例解决
1. 背景
在开发呼叫中心应用时,使用 OpenSIPS 作为 SIP 注册服务器,测试发现偶现电话接通后 30s 左右自动挂断的问题。一个正常的 SIP 注册及呼叫流程如下所示,可以看到 OpenSIPS 作为转发层只负责代理转发请求
2. 问题分析
首先需要明确一点,对于被呼叫的 SIP 终端来说,如果一直收不到 SIP 服务器发送过来的 ACK 则认定会话异常,通常会在 30s 后主动发 BYE 结束会话。问题是确定的,根据以上流程图,具体分析时可以知道可能存在的问题点有两个:
OpenSIPS 未收到 FreeSWITCH 发送过来的 ACK
这种情况可能存在的问题是 FreeSWITCH 和 OpenSIPS 之间存在网络故障,导致 ACK 丢失。比较大的可能是 NAT 没有处理好,或者是网络协议不匹配等,可通过 sngrep 等工具抓包确认OpenSIPS 未正确转发 ACK
OpenSIPS 收到了 FreeSWITCH 发送的 ACK,但是出于自身的问题,未正确将其转发到目标 SIP 终端。这种情况需要检查 OpenSIPS 脚本中处理 ACK 请求的部分,确认脚本逻辑是否存在问题
3. 案例解决
虽然以上分析的终端 30s 自动挂断问题的根因毫无问题,但在实践过程中导致 ACK 丢失的原因千差万别,非常复杂。在笔者的案例中,开发的应用需要保持坐席侧的会话常驻,当坐席的软电话被挂断时,需要自动的重新拨打坐席分机,以实现常驻的特性。在这个前提下,偶现坐席分机软电话 30s 自动挂断的问题,经过长时间的探索,笔者终于找到了必现步骤
- 坐席分机注册在 OpenSIPS 后,FreeSWITCH 呼叫坐席分机,坐席接通并常驻
- 此时使坐席分机所在网络 IP 漂移,如切换 WIFI 网络
- 挂断坐席软电话,让系统自动重新拨打坐席分机
- 坐席分机接通后,必现 30s 自动挂断
重新拨打坐席分机的 SIP 信令流程如下图所示,其中可以看到两个异常点:
- OpenSIPS 将 INVITE 信令转发给了两个不同的 IP 地址。这里之所以有两个不同的地址,是因为切网操作导致本地 IP 地址漂移,SIP 终端在当前网络下注册到 OpenSIPS 产生了一个新的 location。而对 OpenSIPS 来说,收到 INVITE 信令后会将请求同时送达被叫分机号的两个 location,一个 location 上的终端接通后取消其他 location 上的会话即可。真正的问题在于,在这个场景中一个分机号的两个 location 并没有真实对应两个 SIP 终端,其中一个 location 实际上并没有终端设备存在,所以发往该 location 的 INVITE 信令没有响应,只能不断重试
- SIP 终端接通响应 200 后,FreeSWITCH 将 ACK 发往 OpenSIPS,但 OpenSIPS 并没有将 ACK 转发到 SIP 终端真实所在的 location 上,而是将 ACK 发往了没有终端设备存在的 location,导致真实 location 位置上的 SIP 终端没有收到 ACK,最终造成 30s 自动挂断
基于以上分析,可以得出案例的解决方案:
- 将分机注册的 location 限制为 1 个,可以参考 max_contacts 参数
- 修改 OpenSIPS 脚本中 ACK 的转发逻辑,将 ACK 转发到正确的 location