Featured image of post kamailio gzcompress模块

kamailio gzcompress模块

背景

gzcompress模块用于压缩和解压缩消息体,不仅可以用在SIP消息上,还能用在HTTP消息上。

通过Content-Encoding头来决定是否要压缩和解压缩的。 当udp数据超过MTU时, 使用该功能比较有效果。压缩的大小为原来的50%~67%左右, 依赖zlib库。

官方文档地址: gzcompress

本次测试的版本为

kamailio 5.8.5

重要参数解析

1
2
3
4
5
6
# 表示要进行压缩和解压缩的头名称,默认: Content-Encoding 
modparam("gzcompress", "header_name", "Encoded")
# 表示要进行压缩和解压缩的头的值,默认: deflate
modparam("gzcompress", "header_value", "gzip")
# 是否和sanity模块绑定,默认: 0
modparam("gzcompress", "sanity_checks", 1)

实战

官方测试示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#!KAMAILIO

debug=3
memdbg=5
memlog=5

children=2

log_stderror=yes
listen=udp:172.16.4.111:5461
listen=tcp:172.16.4.111:5461

tcp_accept_no_cl=yes
http_reply_parse=yes

mpath="modules/"

loadmodule "sl.so"
loadmodule "pv.so"
loadmodule "xlog.so"
loadmodule "corex.so"
loadmodule "textops.so"
loadmodule "xhttp.so"
loadmodule "gzcompress.so"

modparam("gzcompress", "header_value", "deflate")

request_route {
	xlog("received sip request from $si:$sp\r\n");

	if(src_port==5060) {
		remove_hf("Content-Encoding");
		$du = "sip:127.0.0.1:9";
	} else {
		append_hf("Content-Encoding: deflate\r\n");
		$du = "sip:127.0.0.1:5060";
	}
	forward();
	exit;
}

event_route[xhttp:request] {
	xlog("received http request from $si:$sp,$rb,$hdr(Content-Encoding)\n");
	append_to_reply("Content-Encoding: deflate\r\n");
    xhttp_reply("200", "OK", "application/json",
        "{\"status\":\"ok\",\"data\":\"hello\"}");
}

event_route[xhttp:request]中, 获取请求,然后在返回的请求头中添加Content-Encoding字段, xhttp_reply会自动把body压缩。

测试HTTP请求

使用golang编写http客户端,发送的body使用zlib压缩,示例为:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package main

import (
        "bytes"
        "compress/zlib"
        "encoding/json"
        "fmt"
        "io"
        "net/http"
)

func main() {
        data := map[string]interface{}{
                "name": "test",
                "city": "Taipei",
        }

        // 1. 转成 JSON
        jsonBytes, err := json.Marshal(data)
        if err != nil {
                panic(err)
        }

        // 2. zlib 压缩
        var buf bytes.Buffer
        zw := zlib.NewWriter(&buf)
        _, err = zw.Write(jsonBytes)
        if err != nil {
                panic(err)
        }
        zw.Close() // 必须关闭,否则数据不完整

        // 3. 创建 HTTP 请求
        req, err := http.NewRequest("POST", "http://172.16.4.111:5461/", &buf)
        if err != nil {
                panic(err)
        }

        // 设置头部
        req.Header.Set("Content-Type", "application/json")
        req.Header.Set("Content-Encoding", "deflate")

        // 4. 发送
        client := &http.Client{}
        resp, err := client.Do(req)
        if err != nil {
                panic(err)
        }
        defer resp.Body.Close()

        // 5. 打印响应
        body, _ := io.ReadAll(resp.Body)
        fmt.Println("Status:", resp.Status)
        fmt.Println("Response:", string(body))
}

使用go run main.go运行客户端, 可以看到kamailio的日志为:

1
39(1152) INFO: <script>: received http request from 172.16.1.136:55992,{"city":"Taipei","name":"test"},deflate

kamailio会自动把zlib压缩的body解压, 所以可以直接使用$rb来获取请求体。

如果发送的body没有压缩,则kamailio会报错,但是还是能获取到body的内容:

1
2
3
4
41(1154) ERROR: gzcompress [gzcompress_mod.c:276]: gzc_msg_received(): error decompressing body (-3)
41(1154) INFO: <script>: received http request from 172.16.80.13:21776,
{"city":"Taipei","name":"test"}
,deflate

测试SIP请求

基础玩法

测试方法:

kamailio做代理, 软电话1005注册到kamailio(172.16.4.111)上, 软电话1008注册到freeswitch(172.16.4.114)上, 然后1005拨打1008, kamailio的配置方式为:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
route[LOCATION] {

#!ifdef WITH_SPEEDDIAL
        # search for short dialing - 2-digit extension
        if($rU=~"^[0-9][0-9]$") {
                if(sd_lookup("speed_dial")) {
                        route(SIPOUT);
                }
        }
#!endif

#!ifdef WITH_ALIASDB
        # search in DB-based aliases
        if(alias_db_lookup("dbaliases")) {
                route(SIPOUT);
        }
#!endif

        $avp(oexten) = $rU;
        #if (!lookup("location")) {
        #       $var(rc) = $rc;
        #       route(TOVOICEMAIL);
        #       t_newtran();
        #       switch ($var(rc)) {
        #               case -1:
        #               case -3:
        #                       send_reply("404", "Not Found");
        #                       exit;
        #               case -2:
        #                       send_reply("405", "Method Not Allowed");
        #                       exit;
        #       }
        #}
        
        # when routing via usrloc, log the missed calls also
        #if (is_method("INVITE")) {
        #       setflag(FLT_ACCMISSED);
        #}
        #t_on_failure("1");
        #t_relay();
        #exit;
        $du ="sip:172.16.4.114:5060";
        append_hf("Content-Encoding: deflate\r\n");
        route(RELAY);
        exit;
}

测试的sip图为: 1005拨打1008

  1. 软电话1005发送INVITEkamailio上的详细请求为: 1005发送INVITE到kamailio

  2. kamailio转发INVITEfreeswitch上的详细请求为: kamailio转发INVITE到freeswitch

可以看到body这块压缩了:218/339=0.643

  1. freeswitch回复183kamailio上的详细请求为: freeswitch回复183到kamailio

freeswitch因为支持zlib压缩, 所以回复的183body也压缩了。

  1. kamailio回复1831005上的详细请求为: kamailio回复183到1005

  2. freeswitch回复200OKkamailio上的详细请求为: freeswitch回复200OK到kamailio

  3. kamailio回复200OK1005上的详细请求为: kamailio回复200OK到1005

因为软电话不支持zlib解压,然后就报错直接发送BYE挂断了。

那能否左边不压缩,右边压缩呢?这就是进阶玩法了。

进阶玩法

配置在基础玩法的基础上,添加如下配置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
onreply_route[MANAGE_REPLY] {
        xlog("L_INFO","incoming reply---$rm|$rs|$tu|$rU|$fU|$si|$Ri:$Rp\n");
        remove_hf("Content-Encoding");
        if(status=~"[12][0-9][0-9]") {
                route(NATMANAGE);
        }
        if (is_present_hf("Record-Route")) {
                remove_hf("Record-Route");
                append_hf("Record-Route: <sip:172.16.4.111:5461;lr>\r\n");
                xlog("L_INFO","has record-route..\n");
        }
        return;
}

onreply_route上, 移除Content-Encoding头域, 就可以了。

完整的信令图和基础的玩法一致。

  1. 软电话1005发送INVITEkamailio上的详细请求为: 1005发送INVITE到kamailio

  2. kamailio转发INVITEfreeswitch上的详细请求为: kamailio转发INVITE到freeswitch

  3. freeswitch回复183kamailio上的详细请求为: freeswitch回复183到kamailio

  4. kamailio回复1831005上的详细请求为: kamailio回复183到1005

可以看到183body没有压缩。

  1. freeswitch回复200OKkamailio上的详细请求为: freeswitch回复200OK到kamailio

  2. kamailio回复200OK1005上的详细请求为: kamailio回复200OK到1005

总结

该模块主要压缩的是body信息, 想要压缩转发的消息只需要带上Content-Encoding: deflate头域即可。

同理,如果不想要压缩,只需要移除Content-Encoding头域即可。

本博客已稳定运行
发表了57篇文章 · 总计94.35k字
本站总访问量 次 · 您是本站第 位访问者
粤ICP备2025368587号-1| 使用 Hugo 构建
主题 StackJimmy 设计