一、有状态与无状态转发的区分
1. 在请求处理中区分
-
有状态转发 :显示调用
t_relay()或t_newtran(),创建事务状态,支持重传、超时处理 -
无状态转发 :调用
forward(),简单转发SIP请求,不创建事务状态 -
不转发/拒绝 :调用
drop或exit终止处理,可配合sl_send_reply()发送拒绝响应
2. 在响应处理中区分
-
有状态处理 :在
onreply_route中调用t_reply()修改响应,关联特定事务 -
默认处理:Kamailio自动发现匹配的transaction对象并进行转发
-
无状态处理 :使用
sl_send_reply()立即发送响应,不关联事务
二、核心函数功能解析
请求处理函数
| 函数 | 状态 | 功能 | 典型场景 |
|---|---|---|---|
**t_relay()** |
有状态 | 创建事务状态,转发请求到下一目的地 | INVITE、BYE等需要状态跟踪的呼叫 |
**forward()** |
无状态 | 简单转发SIP请求,不维护状态 | OPTIONS探测、特定场景快速转发 |
**sl_send_reply()** |
无状态 | 立即发送响应,不关联事务 | 认证失败、方法不支持等错误响应 |
**drop/exit** |
- | 终止当前消息处理 | 处理完成、错误退出 |
响应处理函数
| 函数 | 状态 | 功能 | 使用位置 |
|---|---|---|---|
**t_reply()** |
有状态 | 发送与特定事务关联的SIP响应 | onreply_route中 |
| 自动转发 | 有状态 | Kamailio自动匹配事务并转发响应 | 系统自动处理 |
判断函数
| 函数 | 功能 | 返回值 |
|---|---|---|
**is_method()** |
判断具体请求或响应方法 | 布尔值 |
**t_check_trans()** |
判断是否为有状态事务 | 布尔值 |
**t_is_set("onreply_route")** |
判断是否配置了响应路由 | 布尔值 |
**t_check_status("4[0-9][0-9]")** |
判断是否为负面响应 | 布尔值 |
三、转发目标确定机制
1. sl_send_reply()
-
不需要寻找目标:直接回复给请求来源
-
自动使用 :
$si(来源IP)和$sp(来源端口) -
示例 :
sl_send_reply("401", "Unauthorized")
2. forward()
-
明确指定目标:
-
在函数参数中:
forward("udp:192.168.1.100:5060") -
通过
$du变量:$du = "sip:target@domain:5060"; forward()
-
3. t_relay()
-
通过
$du指定 :$du = "sip:192.168.1.100:5060"; t_relay() -
通过
$ru的目标域:自动解析域名,DNS查询SIP服务器 -
负载均衡模块 :
lb_start()或ds_select_dst()自动设置$du
4. t_reply()在 onreply_route中
-
目标自动确定:由事务管理器(tm模块)自动确定
-
不手动指定:只决定回复内容,不控制转发目标
-
返回路径:
-
SIP Via头机制:响应沿Via链自动返回
-
事务状态:tm模块记录原始请求来源信息
-
四、有状态与无状态模式对比
1. 无状态模式(不使用tm模块)
| 特性 | 说明 |
|---|---|
| 事务跟踪 | 无事务状态,tm模块不介入 |
| 响应匹配 | Via头自动匹配 |
| 目标确定 | 完全依赖Via头机制 |
| 函数调用 | 不能调用 t_reply() |
| 性能 | 高,无状态管理开销 |
| 可靠性 | 低,无重传机制 |
| 典型场景 | OPTIONS探测、简单转发 |
示例:
route {
if (is_method("OPTIONS")) {
forward("udp:monitor.server:5060");
exit;
}
}
2. 有状态模式(使用tm模块)
| 特性 | 说明 |
|---|---|
| 事务跟踪 | 完整事务状态管理 |
| 响应匹配 | 事务branch参数匹配 |
| 目标确定 | 事务状态 + Via头共同确定 |
| 函数调用 | 可调用 t_reply()等事务函数 |
| 性能 | 中,有状态管理开销 |
| 可靠性 | 高,支持重传、超时 |
| 典型场景 | INVITE、BYE等呼叫控制 |
示例:
route {
t_on_reply("MY_REPLY_ROUTE");
t_relay(); # 创建事务
}
onreply_route[MY_REPLY_ROUTE] {
t_reply("488", "Modified"); # 修改响应
}
五、tm模块工作机制
1. 事务创建时
int t_newtran(struct sip_msg* msg) {
// 保存来源信息
trans->uac_sock = msg->rcv; // 接收socket
trans->via1 = msg->via1; // 保存Via头
trans->branch = msg->branch; // 保存branch参数
}
2. 响应匹配时
struct tm_transaction* t_check_trans() {
// 通过Via的branch参数匹配事务
// 返回对应的事务结构
}
3. 响应发送时
int t_reply(struct sip_msg* msg, int code, char* reason) {
// 从匹配事务获取:
// 1. 目标地址 (uac_sock)
// 2. 原始Via头
// 3. 发送socket信息
// 构造并发送响应
}
六、关键变量说明
预定义变量
| 变量 | 含义 | 是否自动设置 |
|---|---|---|
**$ru** |
Request-URI(请求目标) | ✅ 自动解析 |
**$du** |
Destination URI(转发目标) | ❌ 需手动设置 |
**$fu** |
From URI(主叫) | ✅ 自动解析 |
**$tu** |
To URI(被叫显示) | ✅ 自动解析 |
**$si** |
来源IP地址 | ✅ 自动设置 |
**$sp** |
来源端口 | ✅ 自动设置 |
七、最佳实践建议
1. 请求处理选择
-
需要状态跟踪 :使用
t_relay()+ tm模块 -
简单快速转发 :使用
forward() -
立即错误响应 :使用
sl_send_reply()+exit
2. 响应处理选择
-
需要修改响应 :在
onreply_route中使用t_reply() -
只需记录日志 :在
onreply_route中记录但不修改 -
无状态场景:让响应自动透传
3. 目标设置策略
-
固定目标 :直接设置
$du = "sip:target:port" -
动态路由:使用负载均衡模块
-
域名解析:依赖DNS SRV/NAPTR记录
-
响应返回:依赖Via头/事务状态,不手动设置
八、总结
Kamailio通过不同的函数和模式提供了灵活的SIP消息处理能力:
-
有状态与无状态分离 :
t_relay()用于完整事务处理,forward()用于简单转发 -
目标确定多样化:从明确指定到自动发现,适应不同场景需求
-
响应处理自动化:通过Via头和事务状态,实现响应的自动正确返回
-
模块化设计:tm模块提供完整的事务管理,无状态模式提供高性能简单转发