目录
一.概述
Kamailio是一款SIP服务器。它可以在高并发环境中,做SIP呼叫的均衡负载处理,是多进程模式(使用fork)。Kamailio支持异步的TCP、UDP、SCTP、TLS、WebSocket,支持WebRTC,支持IPv4和IPv6,支持异步操作,支持负载均衡、主备用路由(Fail-Over),支持AAA(记账、鉴权和授权),支持很多SQL和noSQL数据库后端如MySQL、PostgreSQL、Oracle、Redis、MongoDB等,支持消息队列如RabbitMQ、Kafka等,支持JSON-RPC和XML-RPC控制协议以及SNMP监控等诸多特性。
二.配置文件
kamailio.cfg的结构可以分为三个部分,分别是全局参数、模块设置、路由区块。
1. 全局参数部分
name=value
名称对应官方文档(https://www.kamailio.org/w/documentation/)中的核心参数,如果名称与核心参数不匹配的话,Kamailio无法启动。
值通常是整数、bool或字符串

Go
log_facility=LOG_LOCAL0
children=4
disable_tcp=yes
alias="sip.mydomain.com"
listen=udp:10.0.0.10:5060
比如在上面的例子中,如果 Kamailio日志登录到syslog,你可以控制该设施进行日志记录。当你想把所有 Kamailio日志转到另一个日志时,这非常有用。LOG_LOCAL0是rsyslogd中的概念,就是日志流的分类,会根据这些分类导出到不同文件。默认值是LOG_DAEMON。
children=4 UDP接口的子接口数量(每个接口一组- ip:port)。缺省值为8。例如,如果你配置代理监听3个UDP端口,它将创建3xchildren processes子进程来处理传入的UDP消息。
disable_tcp=yes 用来调整TCP的行为,全局参数用于禁用SIP服务器中的TCP支持,默认值是no
alias="sip.mydomain.com" 别名就是域名,用于设置服务器的别名主机名,它可以设置多次,每个值都被添加到一个列表中,以便在选中"myself"时匹配主机名。有必要在别名定义中包含端口("port="或"listen="定义中使用的端口值,alias:5060=other.domain.com),否则loose_route()函数将无法按预期的方式工作。
listen=udp:10.0.0.10:5060 设置SIP服务器应该监听的网络地址。它可以是IP地址、主机名或网络接口id或协议、地址、端口的组合。该参数可以在同一个配置文件中多次设置,服务器监听指定的所有地址。如果省略了这个指令,SIP服务器就会监听所有指令接口
2.模块设置部分
包含加载模块和设置模块参数的指令。它包含指令loadmodule和modparam。在默认配置文件中,以设置模块路径的行开头(对mpath core参数的赋值)
loadmodule "debugger.so"
...
modparam("debugger", "cfgtrace", 1)
loadmodule "debugger.so" 启用kamailio的交互调试功能,实时跟踪SIP消息处理流程
modparam("debugger", "cfgtrace", 1) 启用配置跟踪,参数含义分别是模块名称、配置跟踪参数、启用跟踪。如果为0就是禁用跟踪
3.路由区块部分
包含了Kamailio处理的SIP流量的路由逻辑的路由块。唯一的强制路由块是request_route,它包含决定SIP请求路由的操作。
request_route {
per request initial checks
route(REQINIT);
...
}
branch_route[MANAGE_BRANCH] {
xdbg("new branch [T_branch_idx\] to ru\n");
route(NATMANAGE);
}
onreply_route[MANAGE_REPLY] {
if (has_totag()) {
route(IN_DIALOG_REPLY);
}
route(HANDLE_NAT_REPLY);
}
主请求路由(request_route):调用子路由REQINIT
分支路由(branch_route):调用子路由NATMANAGE
主响应路由(onreply_route)
"伪变量"一词用于指可以被赋予的特殊符号作不同脚本函数的参数,这些参数将被替换在函数执行之前的值,开头用字符"$"标记
$T_branch_idx 执行branch_route[]的分支的索引(第一个分支从1开始)。如果在branch_route[]块之外使用,则值为'0'。
$ru SIP请求的URI的引用,它是R/W变量(可以直接在配置文件中赋值给它)
4.伪变量
是Kamailio核心系统提供的变量,用于访问SIP消息、系统状态等信息。当Kamailio收到SIP消息时,会自动解析并填充这些变量,它覆盖SIP消息、网络、系统等各方面。
$ru = "sip:1001@192.168.1.100:5060" # 指定新的请求行
$rm = "INVITE" # 从 SIP 请求方法提取
$si = "192.168.1.50" # 从网络包提取源IP
第一个变量是可读可写的,请求URI,可以修改来改变SIP消息目的地
第二个和第三个都是只读变量,分别是请求方法和源IP地址,修改会导致错误
三.架构
1.总述
Kamailio采用模块化架构,从整体看主要分为核心和模块两大类。
图中为Kamailio 1.x架构

Kamailio v3.0.x(或更新版本)的架构进行了重构,把原本核心的数据库API、管理接口API移出,重构为内部库

假设有一个INVITE请求到达:
①接收:SIP TRANSPORT LAYER(SIP传输层)从INTERNET接收到UDP数据包(也可以是UDP/TCP/TLS/WSS)
②解析:SIP PARSER(SIP解析器)将其转换为内部结构sip_msg
③执行路由脚本:CONFIG INTERPRETER开始执行kamailio.cfg对应的路由逻辑(比如route{...})
④调用功能模块:在脚本执行中,遇到类似lookup("location")或ds_select_dst()的命令,就会通过MODULE INTERFACE调用对应的LOCATION MODULES或ROUTING MODULES
⑤访问数据:模块在需要查询用户或路由规则时,通过DB API调用DB DRIVER MODULES,从DB SERVER获取数据
⑥管理与监控:这时管理员通过WEB GUI发送一个"查看当前呼叫数"的命令,该命令通过MI TRANSPORT MODULES和MI API传递给核心,核心返回数据并在界面上展示。
⑦发送响应:最终,处理后的INVITE消息再通过SIP TRANSPORT LAYER发送到网络。
演示:./register_test.sh 1 10.0.2.15:5060发起一个注册请求,查看日志进行分析:
①接收:SIP TRANSPORT LAYER接收数据包
Received SIP message,这是TCP传输层接收到的REGISTER请求。

②解析:SIP PARSER转换为内部结构

解析器逐行解析SIP消息,识别方法为REGISTER,URI等信息。
③执行路由脚本:CONFIG INTERPRETER

<script>标签表明正在执行kamailio.cfg中的路由脚本,这是配置解释器在执行。
④调用功能模块:MODULE INTERFACE

正在解析目标地址,是通过路由模块实现的。
⑤发送响应:SIP TRANSPORT LAYER
请求转发:

响应返回:

通过TCP传输层发送完整的SIP消息。
2.核心
核心包括内存管理器、SIP消息解析器、锁定系统、DNS和传输层管理、配置文件解析器和解释器、计时器API;内部库包括一些来自旧Kamailio核心的组件,数据库抽象层(DB API),管理接口(MI API),统计引擎等
3.模块
目前仓库中有超过150个模块,通过加载模块,可以获得以下功能:注册商和用户位置管理;计费、授权与认证;有状态处理-SIP事务管理;异步SIP请求处理
4.SIP消息处理
Kamailio配置文件的执行在收到来自网络SIP请求和SIP回复的处理流程不同。
(1)SIP请求处理

①所有请求都从传输层进入,执行主路由
②路由脚本决定三分之一:
立即回复并结束(认证失败、错误请求等)
简单无状态转发(高性能代理)
完整有状态处理(支持分支路由、失败处理等)
③最终都通过传输层发送响应或转发请求
(2)SIP回复处理

四.底层实现
1.多进程模型
(1)进程表数据结构模型

(2)进程创建流程


(3)进程间通信IPC机制
Unix域socket通信

文件描述符传递


子进程的sockfd[1]和父进程的sockfd[0]通信
通过"/opt/kamailio/sbin/kamcmd ps"查看kamailio的多进程

5375:主管理进程,启动和监控所有子进程
定时器进程组:有三个独立的定时器进程,分别处理不同精度的定时任务
5377:慢定时器
5378:主定时器,SIP事务超时处理、对话状态维护
5379:次级定时器,与主定时器配合,处理不同时间粒度的任务
5380:控制处理程序,处理kamcmd命令
5385:TCP主进程,监听TCP端口,接收TCP连接,将连接分配给工作进程
5381-5384:4个工作进程,从TCP连接读取SIP消息、解析SIP消息、执行路由脚本
(children参数可以在cfg文件中tcp_children进行配置)
2.Epoll多路复用机制
(1)io_wait_h数据结构
通用字段

epoll专用字段

(2)初始化函数

初始化调用时机

模式选择逻辑
内核版本>=2.5.66 默认使用水平触发

(3)资源清理
销毁函数

epoll销毁

3.共享内存
(1)底层机制
有两种共享内存的方式
第一种MMAP(内存映射)
MAP_ANON:创建匿名内存区域,不与任何文件关联;/dev/zero:特殊设备文件,提供全零的内存页

第二种System V SHM
shmget():创建或获取共享内存段
shmat():将共享内存附加到进程地址空间
IPC_PRIVATE:每次创建新的共享内存段

4.锁定系统
(1)多平台锁定支持
Futex,用户态快速路径,避免系统调用

FAST_LOCK,快速自旋锁,自选等待,低延迟。适用于高并发短临界区

Pthread互斥锁

POSIX信号量,需要跨进程锁定时,用于进程间同步

编译时根据目标平台自动选择最快的锁实现

(2)高级锁定功能
递归锁,同一进程可多次获取锁,记录持有者防止死锁
