kamailio源码对于初学者,阅读起来是有一定难度的,特别是kamailio里面最核心的路由脚本kamailio.cfg的理解。
静态方式阅读源码,往往无法深刻理解代码的运行逻辑,于是使用gdb工具来辅助理解源码将变得事半功倍。
那么在使用gdb调试之前,需要对kamailio的软件设计架构有个初步了解。kamailio是多进程架构,使用Reactor和Proactor结合的IO网络模型,使用主进程负责监听网络,当有连接产生或者首包到达时,就通过pipe(进程间管道通信)将文件描述符发给worker进程,worker进程就会负责此连接的数据读取、业务处理、数据发送等处理,然后再次等待socket事件。
下面是一个kamailio进程启动的实例:
[root@localhost sbin]# ./kamctl ps
{
"jsonrpc": "2.0",
"result": [
{
"IDX": 0,
"PID": 4919,
"DSC": "main process - attendant"
}, {
"IDX": 1,
"PID": 4920,
"DSC": "udp receiver child=0 sock=172.20.74.81:5060"
}, {
"IDX": 2,
"PID": 4921,
"DSC": "udp receiver child=1 sock=172.20.74.81:5060"
}, {
"IDX": 3,
"PID": 4922,
"DSC": "udp receiver child=2 sock=172.20.74.81:5060"
}, {
"IDX": 4,
"PID": 4923,
"DSC": "udp receiver child=3 sock=172.20.74.81:5060"
}, {
"IDX": 9,
"PID": 4928,
"DSC": "slow timer"
}, {
"IDX": 10,
"PID": 4929,
"DSC": "timer"
}, {
"IDX": 11,
"PID": 4930,
"DSC": "secondary timer"
}, {
"IDX": 12,
"PID": 4931,
"DSC": "JSONRPCS FIFO"
}, {
"IDX": 13,
"PID": 4932,
"DSC": "JSONRPCS DATAGRAM"
}, {
"IDX": 14,
"PID": 4933,
"DSC": "USRLOC Timer"
}, {
"IDX": 15,
"PID": 4934,
"DSC": "ctl handler"
}, {
"IDX": 16,
"PID": 4935,
"DSC": "TIMER NH"
}, {
"IDX": 17,
"PID": 4936,
"DSC": "tcp receiver (generic) child=0"
}, {
"IDX": 18,
"PID": 4937,
"DSC": "tcp receiver (generic) child=1"
}, {
"IDX": 19,
"PID": 4938,
"DSC": "tcp receiver (generic) child=2"
}, {
"IDX": 20,
"PID": 4939,
"DSC": "tcp receiver (generic) child=3"
}, {
"IDX": 21,
"PID": 4940,
"DSC": "tcp receiver (generic) child=4"
}, {
"IDX": 25,
"PID": 4944,
"DSC": "tcp main process"
}
],
"id": 4947
}
udp receiver和tcp receiver都是处理SIP消息的进程,包括kamailio.cfg配置中route段的代码都是在此进程中运行。为了方便调试,需要将kamailio配置为单进程运行模式,将kamailio.cfg中children=1
log_facility=LOG_LOCAL0
log_prefix="{$mt $hdr(CSeq) $ci} "
/* number of SIP routing processes for each UDP socket
* - value inherited by tcp_children and sctp_children when not set explicitely */
children=1 //默认为8
/* uncomment the next line to disable TCP (default on) */
# disable_tcp=yes
/* number of SIP routing processes for all TCP/TLS sockets */
# tcp_children=8
设置单进程模式后,运行如下
[root@localhost sbin]# ./kamctl ps
{
"jsonrpc": "2.0",
"result": [
{
"IDX": 0,
"PID": 5036,
"DSC": "main process - attendant"
}, {
"IDX": 1,
"PID": 5037,
"DSC": "udp receiver child=0 sock=172.20.74.81:5060"
}, {
"IDX": 2,
"PID": 5038,
"DSC": "slow timer"
}, {
"IDX": 3,
"PID": 5039,
"DSC": "timer"
}, {
"IDX": 4,
"PID": 5040,
"DSC": "secondary timer"
}, {
"IDX": 5,
"PID": 5041,
"DSC": "JSONRPCS FIFO"
}, {
"IDX": 6,
"PID": 5042,
"DSC": "JSONRPCS DATAGRAM"
}, {
"IDX": 7,
"PID": 5043,
"DSC": "USRLOC Timer"
}, {
"IDX": 8,
"PID": 5044,
"DSC": "ctl handler"
}, {
"IDX": 9,
"PID": 5045,
"DSC": "TIMER NH"
}, {
"IDX": 10,
"PID": 5046,
"DSC": "tcp receiver (generic) child=0"
}, {
"IDX": 11,
"PID": 5047,
"DSC": "tcp main process"
}
],
"id": 5050
}
(gdb) b auth_mod.c:854
Breakpoint 1 at 0x7fcba244f838: file auth_mod.c, line 854.
(gdb) c
Continuing.
Breakpoint 1, w_pv_auth_check (msg=0x7fcba9af8838, realm=0x7fcba9aabc18 "\250\006\253\251\313\177", passwd=0x7fcba9aabd78 "",
flags=0x7fcba9aabed8 "\320媩\313\177", checks=0x7fcba9aabf78 "0窩\313\177") at auth_mod.c:854
854 return pv_auth_check(msg, &srealm, &spasswd, vflags, vchecks);
(gdb) bt
#0 w_pv_auth_check (msg=0x7fcba9af8838, realm=0x7fcba9aabc18 "\250\006\253\251\313\177", passwd=0x7fcba9aabd78 "",
flags=0x7fcba9aabed8 "\320媩\313\177", checks=0x7fcba9aabf78 "0窩\313\177") at auth_mod.c:854
#1 0x00000000005eccf5 in do_action (h=0x7ffea97a06b0, a=0x7fcba9aae2b0, msg=0x7fcba9af8838) at core/action.c:1104
#2 0x00000000005f9e52 in run_actions (h=0x7ffea97a06b0, a=0x7fcba9aae2b0, msg=0x7fcba9af8838) at core/action.c:1584
#3 0x00000000005fa4ce in run_actions_safe (h=0x7ffea97a2de0, a=0x7fcba9aae2b0, msg=0x7fcba9af8838) at core/action.c:1648
#4 0x000000000044b5bc in rval_get_int (h=0x7ffea97a2de0, msg=0x7fcba9af8838, i=0x7ffea97a0c24, rv=0x7fcba9aae980, cache=0x0) at core/rvalue.c:949
#5 0x00000000004500ed in rval_expr_eval_int (h=0x7ffea97a2de0, msg=0x7fcba9af8838, res=0x7ffea97a0c24, rve=0x7fcba9aae978) at core/rvalue.c:1947
#6 0x0000000000450519 in rval_expr_eval_int (h=0x7ffea97a2de0, msg=0x7fcba9af8838, res=0x7ffea97a119c, rve=0x7fcba9aaf0a8) at core/rvalue.c:1955
#7 0x00000000005ec580 in do_action (h=0x7ffea97a2de0, a=0x7fcba9ab0de0, msg=0x7fcba9af8838) at core/action.c:1055
#8 0x00000000005f9e52 in run_actions (h=0x7ffea97a2de0, a=0x7fcba9aaac40, msg=0x7fcba9af8838) at core/action.c:1584
#9 0x00000000005eca0e in do_action (h=0x7ffea97a2de0, a=0x7fcba9aafaf8, msg=0x7fcba9af8838) at core/action.c:1070
#10 0x00000000005f9e52 in run_actions (h=0x7ffea97a2de0, a=0x7fcba9aa8050, msg=0x7fcba9af8838) at core/action.c:1584
#11 0x00000000005eca0e in do_action (h=0x7ffea97a2de0, a=0x7fcba9ab1ed8, msg=0x7fcba9af8838) at core/action.c:1070
#12 0x00000000005f9e52 in run_actions (h=0x7ffea97a2de0, a=0x7fcba9aa61a0, msg=0x7fcba9af8838) at core/action.c:1584
#13 0x00000000005e91ef in do_action (h=0x7ffea97a2de0, a=0x7fcba9a730e8, msg=0x7fcba9af8838) at core/action.c:703
#14 0x00000000005f9e52 in run_actions (h=0x7ffea97a2de0, a=0x7fcba9a6ec38, msg=0x7fcba9af8838) at core/action.c:1584
#15 0x00000000005fa596 in run_top_route (a=0x7fcba9a6ec38, msg=0x7fcba9af8838, c=0x0) at core/action.c:1669
#16 0x0000000000602cfa in receive_msg (
buf=0xfc3160 "REGISTER sip:172.20.74.81;transport=tcp SIP/2.0\r\nVia: SIP/2.0/TCP 172.20.74.55:5060;branch=z9hG4bK481F610A005680374a14ac\r\nFrom: \"DESKTOP-C9B9OA2\" <sip:00008001@172.20.74.81>;tag=417D83E1-AC5A0620\r\nTo:"..., len=920, rcv_info=0x7fcb9e07dba0) at core/receive.c:515
#17 0x0000000000686e29 in receive_tcp_msg (
tcpbuf=0x7fcb9e07df28 "REGISTER sip:172.20.74.81;transport=tcp SIP/2.0\r\nVia: SIP/2.0/TCP 172.20.74.55:5060;branch=z9hG4bK481F610A005680374a14ac\r\nFrom: \"DESKTOP-C9B9OA2\" <sip:00008001@172.20.74.81>;tag=417D83E1-AC5A0620\r\nTo:"..., len=920, rcv_info=0x7fcb9e07dba0, con=0x7fcb9e07db88)
at core/tcp_read.c:1413
#18 0x0000000000688f3a in tcp_read_req (con=0x7fcb9e07db88, bytes_read=0x7ffea97a3614, read_flags=0x7ffea97a360c) at core/tcp_read.c:1604
#19 0x000000000068d2f6 in handle_io (fm=0x7fcba9b02e10, events=1, idx=-1) at core/tcp_read.c:1855
#20 0x000000000067a394 in io_wait_loop_epoll (h=0xb6a960 <io_w>, t=2, repeat=0) at core/io_wait.h:1070
#21 0x000000000068ec91 in tcp_receive_loop (unix_sock=23) at core/tcp_read.c:1976
#22 0x0000000000537b1d in tcp_init_children (woneinit=0x7ffea97a3a9c) at core/tcp_main.c:5229
#23 0x000000000042df80 in main_loop () at main.c:1849
#24 0x00000000004377f9 in main (argc=5, argv=0x7ffea97a4188) at main.c:3078
(gdb)
设置断后,再使用SIP终端进程注册,当服务器收到SIP消息,并运行到指定代码时,即可单步调试,同时查看调用堆栈,对位定位问题以及跟踪源码非常有帮助。