要对kamailio/opensips进行单步调试,就需要先了解其代码的结构及运行方式,kamailio/opensips使用Reactor和Proactor结合的IO网络模型,使用主进程负责监听网络,当有连接产生或首包到达时,就通过pipe将文件描述符发送给worker进程,worker进程就会负责此连接的数据取读、业务处理、数据发送等事情,然后再次等待此socket事件。当我们想要调试一段代码时,就先确认这段代码是运行在什么类型的进程中,通常用于处理SIP逻辑的代码都是在worker进程中执行的,下面是一个kamailio进程启动的实例:
[root@xx sipserver]# kamctl ps
Process:: ID=0 PID=6651 Type=attendant
Process:: ID=1 PID=6653 Type=udp receiver child=0 sock=172.16.0.16:53
Process:: ID=2 PID=6654 Type=udp receiver child=1 sock=172.16.0.16:53
Process:: ID=3 PID=6656 Type=udp receiver child=2 sock=172.16.0.16:53
Process:: ID=4 PID=6658 Type=udp receiver child=3 sock=172.16.0.16:53
Process:: ID=5 PID=6661 Type=slow timer
Process:: ID=6 PID=6662 Type=timer
Process:: ID=7 PID=6665 Type=MI FIFO
Process:: ID=8 PID=6668 Type=ctl handler
Process:: ID=9 PID=6669 Type=SNMP AgentX
Process:: ID=10 PID=6672 Type=tcp receiver (generic) child=0
Process:: ID=11 PID=6674 Type=tcp receiver (generic) child=1
Process:: ID=12 PID=6676 Type=tcp receiver (generic) child=2
Process:: ID=13 PID=6677 Type=tcp receiver (generic) child=3
Process:: ID=14 PID=6679 Type=tcp main process
上例中Type=tcp receiver和udp receiver这两种类型的进程都是处理SIP消息的,包括kamailio.cfg配置中route段都是在此进程中执行,通常我们为对SIP协议进行处理而开发的模块也都在此进程中执行。
kamailio和opensips在代码核心架构上是一致的,下面以kamailio为例说明如何使用gdb进行调试。调试程序有两种方法:
方法1直接用GDB运行kamailio:将kamailio.cfg配置为fork=no, 这样kamailio会以单进程方式运行,所以的逻辑都将在一个进程里执行,但单进程模式不支持TCP listen,所以要调试TCP逻辑,不能使用此方式。直接使用gdb调试kamailio主程序就行:
[root@xx ~]# gdb /usr/sbin/kamailio
GNU gdb (GDB) Red Hat Enterprise Linux (7.0.1-45.el5)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /usr/sbin/kamailio...done.
(gdb) b main.c:10
Breakpoint 1 at 0x45725c: file main.c, line 10.
(gdb) run
方法2 将kamailio运行起来后,再用gdb attach调试:第一种方法的缺点非常明显,不能调试TCP进程,也不能将kamailio多进程的优势发挥出来。将kamailio.cfg配置为fork=yes将以多进程方式启动,与此相关的参数还有两个:
children=1 ;配置处理udp端口数据的进程数量
tcp_children=1 ;配置处理tcp端口数据的进程数据,如果此参数未配置,默认使用children参数。
如果使用以上参数启动程序,如果listen参数有对应的端口,将会启动1个UDP处理进程和1个TCP处理进程,实例如下:
[root@xx sipserver]# kamctl ps
Process:: ID=0 PID=6651 Type=attendant
Process:: ID=1 PID=6653 Type=udp receiver child=0 sock=172.16.0.16:53
Process:: ID=5 PID=6661 Type=slow timer
Process:: ID=6 PID=6662 Type=timer
Process:: ID=7 PID=6665 Type=MI FIFO
Process:: ID=8 PID=6668 Type=ctl handler
Process:: ID=9 PID=6669 Type=SNMP AgentX
Process:: ID=10 PID=6672 Type=tcp receiver (generic) child=0
Process:: ID=14 PID=6679 Type=tcp main process
当kamailio收到TCP数据时,会由6672进程进行处理,我们可以使用gdb attach到指定进程进行调试,实例如下:
[root@xx ~]# gdb
GNU gdb (GDB) Red Hat Enterprise Linux (7.0.1-45.el5)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
(gdb) attach 6672
Attaching to process 6672
......
(gdb) b redis_base.c:100
Breakpoint 1 at 0x2b6c45e70082: file redis_base.c, line 100.
(gdb) c
Continuing.
然后再设置断点,执行run即可,当服务器收到SIP消息并运行到指定代码即可单步调试,在调试过程中再结合日志输出,对定位问题非常有帮助。