排查rtmp协议推流时握手bug
概况
转推流程序的过程:从一个观看地址拉流,然后推流到另一个推流地址。主要用于cdn之间转推,目前市面上大多数cdn厂商都愿意不支持动态转推,因此只能通过转推流程序进行转推。
bug现象:使用obs studio推流到微赞可以成功,但是使用Erlang版本的转推流程序推流到微赞却失败。
日志如下:
很显然是rtmp_handshake:create_c2/2
函数出现匹配错误,对应代码如下:
rtmp握手过程中C1数据包匹配<<_:32, 0:32, _/binary>>
格式后和S2数据包匹配不成功,程序直接crash dump。因此需要弄清楚rtmp握手过程中是否有对S2和C1进行匹配验证。
Rtmp握手过程
此处重点关注rtmp握手过程中的C1和S2数据包。
先看官方文档中的握手过程,中文翻译版本可以参见:rtmp规范1.0。 官方文档中对于是否要保证C1和S2完全一致,并没有明确说法。因此可以先参见obs studio依赖的**librtmp
库,看握手过程是如何处理的。obs studio依赖的librtmp
**的代码如下连接:
- https://github.com/obsproject/obs-studio/blob/master/plugins/obs-outputs/librtmp/rtmp.c
- https://github.com/obsproject/obs-studio/blob/master/plugins/obs-outputs/librtmp/handshake.h
第一个链接rtmp.c中的代码是推流地址中没有加密串的情况下的握手过程代码,第二个链接handshake.h中的代码是推流地址中有加密串的情况下的握手过程代码。代码中使用条件编译CRYPTO
宏来选择编译不同的代码。其中HandShake
函数属于客户端的握手函数,SHandShake
属于服务端的握手函数。非加密版本具体C语言代码如下(已添加对应的中文注释进行说明):
rtmp握手过程中确实存在对S2和C1进行匹配验证的操作,但是这个操作并不影响握手是否是成功的,只是添加了一条warnning日志而已。因此obs studio还是能推流成功。相对应的在我们的转推流程序中,需要针对这个情况不进行强认证,删除掉匹配的操作即可。
抓包分析
以微赞和网宿为例
网宿推流没有走加密流程,S2和C1匹配,具体数据包截图如下:
微赞推流走加密流程,S2和C1不匹配,具体数据包截图如下:
到此,整个rtmp推流握手过程就比较清楚了。
因此只需要将Erlang代码的流程更改下即可(删除S2和C1的匹配过程),见下面的Erlang代码:
至此,转推流成功,示例图如下:
结论
虽然Adobe公司自己出的rtmp协议不是iso标准的,但是你们这些公司好歹也尽量按照规定来啊,贼鸡儿坑。
参考:
- obs-studio: https://github.com/obsproject/obs-studio
- obs studio握手:https://github.com/obsproject/obs-studio/blob/master/plugins/obs-outputs/librtmp/handshake.h
- RTMPdump(libRTMP)握手源代码:https://blog.csdn.net/leixiaohua1020/article/details/12954329
- rtmp协议过程分析:https://www.cnblogs.com/lidabo/p/7355262.html
- librtmp使用示例: https://github.com/leixiaohua1020/simplest_librtmp_example
- rtmplib rtmp协议过程分析:https://www.cnblogs.com/lidabo/p/7355262.html