一个FreeSWITCH Bug修复手记

好久不写技术文章了,今天走一个。

今天有人在微信群里提了一个问题:“杜老师,想麻烦您看一下,电话打进去之后就会出现崩溃,卡了两天了,麻烦您有时间可否帮忙看一下,多谢多谢了,加您好友了 Image。”

看到这条消息的时候,我正好在排查一个公司客户的问题,虽然没有彻底解决,但已定位到一些关键点,正好可以换换脑子,就帮他看了一下。Back Trace 如下:

[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `./freeswitch'.
Program terminated with signal 11, Segmentation fault.
#0  0x00007f7e79c303b1 in __strcasecmp_l_avx () from /lib64/libc.so.6
(gdb) where
#0  0x00007f7e79c303b1 in __strcasecmp_l_avx () from /lib64/libc.so.6
#1  0x00007f7e64f46813 in sofia_reg_parse_auth (profile=profile@entry=0x1707bd0, authorization=authorization@entry=0x7f7e2c03e590,
    sip=sip@entry=0x7f7e2c03d1f8, de=de@entry=0x7f7e38014990, regstr=0x7f7e7b3991d0 <sip_method_name_invite> "INVITE",
    np=np@entry=0x7f7de99f4e30 "dc6885f2-39b0-4d3d-970a-1b197a16d371", nplen=nplen@entry=128, ip=ip@entry=0x7f7de99f4190 "10.2.18.244",
    network_port=58257, v_event=v_event@entry=0x7f7de99f4d58, exptime=exptime@entry=300, regtype=regtype@entry=REG_INVITE,
    to_user=to_user@entry=0x7f7e2c03dbc8 "7788", auth_params=auth_params@entry=0x7f7de99f4130, reg_count=reg_count@entry=0x7f7de99f4138,
    user_xml=user_xml@entry=0x7f7de99f4d60) at sofia_reg.c:3427

粗看 Back Trace 也没看出具体问题,虽然看到问题大约出在 sofia_reg.c:3427 行,但也不想花时间去翻代码,然后就问了以下几个问题:

  • FreeSWITCH 什么版本
  • 什么操作系统?

答复是:

  • 1.10.7
  • CentOS 7.9

看着版本还比较新,就翻了一下代码,如下:

3420	if (input2) {
3421		if (sofia_make_digest(use_alg, &bigdigest, (void *)input2, &digest_outputlen) != SWITCH_STATUS_SUCCESS) {
3422			switch_safe_free(input2);
3423			goto end;
3424		}
3425	}
3426
3427	if (input2 && !strcasecmp(bigdigest, response)) {

初步判断问题出在 3421 行,bigdigest 指针有问题。接着,该同学又提供了 FreeSWITCH 崩溃前的日志如下:

[ERR] switch_utils.c:4584 Unknown message digest md5
[ERR] switch_utils.c:4584 Unknown message digest md5
[ERR] switch_utils.c:4584 Unknown message digest md5

这个就比较明确了,找到代码,发现这里返回了 SWITCH_STATUS_FALSE:

4581	md = EVP_get_digestbyname(digest_name);
4582
4583	if (!md) {
4584		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown message digest %s\n", digest_name);
4584		return SWITCH_STATUS_FALSE;

再对比 sofia_make_digest 函数,发现该函数调用了 switch_digest_string,进而调用了 switch_digest,但是没有处理返回值,因而导致后续判断不准确造成崩溃。

修复的方法显而易见,参见这里

当然,理论上讲这个函数是不可能返回 FALSE 的,进一步交流发现它用的 OpenSSL 库版本比较低,不知道什么原因导致那个 md5 相关的函数未正常执行,把这个问题留给他当课后作业自己去研究了,本次修改仅是修复了崩溃问题,但他的电话应该还不能正常打。但他在这个问题上已经折腾两天了,相信看到曙光的那一刻心情会大好。大家遇到问题也可以到微信群、QQ 群、知识星球等上面提问,如果我不是特别忙的话,一般是会回答的。

其实这个问题不算复杂。我以前也经常引用高人的话:

如果一个问题被描述的足够详细,那么解决方法是显而易见的。

所以,遇到问题不要慌,以前左耳朵耗子老师讲过一个“橡皮鸭程序调试法”(感兴趣的话自己搜下吧),也是这个道理。

顺便做个广告:欢迎大家试用我们的 XSwitch,有图形界面,简单好用。点击直达