以下是 将原 Kamailio 路由逻辑转换为 Lua 脚本 的完整实现:
一、Lua 路由脚本
创建文件 /usr/local/kamailio/etc/kamailio/kamailio-test.lua
,内容如下:
lua
-- kamailio-test.lua
-- 主请求路由函数
function request_route()
-- 初始检查:最大跳数
if KSR.maxfwd.process_maxfwd(10) < 0 then
KSR.sl.send_reply(483, "Too Many Hops")
return
end
-- 处理 CANCEL 请求
if KSR.pv.is_method("CANCEL") then
if KSR.tm.t_check_trans() > 0 then
KSR.tm.t_relay()
end
return
end
-- 处理 REGISTER 请求
if KSR.pv.is_method("REGISTER") then
if KSR.registrar.save("location") < 0 then
KSR.sl.reply_error()
end
return
end
-- 仅允许 INVITE 请求
if not KSR.pv.is_method("INVITE") then
KSR.sl.send_reply(405, "Method Not Allowed")
return
end
-- 查找用户位置
if KSR.registrar.lookup("location") < 0 then
KSR.sl.send_reply(404, "User Not Found")
return
end
-- 转发请求到目标(UAS)
KSR.tm.t_relay()
end
二、修改 Kamailio 配置文件
更新 /usr/local/kamailio/etc/kamailio/kamailio-test.cfg
,主要内容如下:
kamailio
#!KAMAILIO
####### 全局参数 #########
debug=3
log_stderror=no
memdbg=5
memlog=5
children=4
listen=udp:192.168.1.70:5060
####### 加载模块 #########
loadmodule "app_lua.so" # 关键:加载 Lua 模块
loadmodule "tm.so"
loadmodule "sl.so"
loadmodule "rr.so"
loadmodule "maxfwd.so"
loadmodule "textops.so"
loadmodule "siputils.so"
loadmodule "xlog.so"
loadmodule "registrar.so"
loadmodule "usrloc.so"
####### 模块参数配置 #########
modparam("usrloc", "db_mode", 0)
modparam("siputils", "rpid_avp", "$avp(s:rpid)")
modparam("app_lua", "load", "/usr/local/kamailio/etc/kamailio/kamailio-test.lua") # 指定 Lua 脚本路径
####### 路由逻辑 #########
# 主路由直接调用 Lua 脚本
request_route {
lua_exec("request_route");
}
三、关键改动说明
1. 模块加载
- 新增
app_lua.so
模块:用于支持 Lua 脚本执行。 - 调整模块顺序 :确保
app_lua
先于其他模块加载。
2. Lua 脚本绑定
modparam("app_lua", "load", "...")
:指定 Lua 脚本路径。lua_exec("request_route")
:在request_route
中调用 Lua 函数。
3. Lua 逻辑对照
原配置逻辑 | Lua 实现 |
---|---|
mf_process_maxfwd |
KSR.maxfwd.process_maxfwd() |
is_method |
KSR.pv.is_method() |
t_check_trans |
KSR.tm.t_check_trans() |
t_relay |
KSR.tm.t_relay() |
save("location") |
KSR.registrar.save("location") |
lookup("location") |
KSR.registrar.lookup("location") |
四、测试验证
1. 启动 Kamailio
bash
/usr/local/kamailio/sbin/kamailio -f /usr/local/kamailio/etc/kamailio/kamailio-test.cfg -DD -E
2. 观察日志
正常启动后应输出:
DEBUG: app_lua [lua_support.c:64]: lua_sr_init_mod(): Lua script loaded: /usr/local/kamailio/etc/kamailio/kamailio-test.lua
3. 测试 SIP 请求
-
注册请求:
bashsipp -sn uac 192.168.1.70:5060 -s 1001 -m 1 -r 1 -d 1000 -inf users.csv
-
users.csv
示例:csvSEQUENTIAL 1001;[authentication username=1001 password=123456]
-
-
INVITE 请求:
bashsipp -sn uac 192.168.1.70:5060 -s 1001 -i 192.168.1.62 -m 1 -r 1 -d 1000
五、高级调试
1. Lua 脚本日志
在 Lua 脚本中添加调试日志:
lua
KSR.log(LOG_NOTICE, "INVITE received from " .. KSR.pv.get("$si"))
2. 查看用户位置
通过 Kamailio 控制台检查注册状态:
bash
kamcmd ul.dump
六、常见问题
1. Lua 模块未加载
错误日志:
ERROR: module app_lua not found
解决方法:
-
确保编译时启用了 Lua 支持:
bashmake include_modules="app_lua" cfg
2. Lua 脚本权限问题
错误日志:
ERROR: app_lua [lua_support.c:101]: lua_sr_load_script(): failed to load script
解决方法:
-
检查脚本路径是否正确:
bashls -l /usr/local/kamailio/etc/kamailio/kamailio-test.lua
总结
通过将路由逻辑迁移到 Lua,您可以:
- 灵活扩展:利用 Lua 的完整编程能力实现复杂逻辑。
- 热更新:修改 Lua 脚本后无需重启 Kamailio(部分场景支持)。
- 代码复用:共享 Lua 库函数跨多个 Kamailio 实例。
知识补充
在 Kamailio 的 Lua 脚本中,KSR
是一个 全局对象 ,它是 Kamailio 提供的 Lua API 的核心接口。通过 KSR
,Lua 脚本可以调用 Kamailio 的核心功能、模块函数以及访问 SIP 消息的变量和属性。
KSR 的作用
KSR
是 Kamailio 与 Lua 脚本之间的桥梁,提供了以下功能:
- 访问 Kamailio 模块函数 :
- 例如:
KSR.tm.t_relay()
调用tm
模块的t_relay
函数。
- 例如:
- 访问 Kamailio 变量 :
- 例如:
KSR.pv.get("$si")
获取 SIP 消息的源 IP 地址。
- 例如:
- 执行 Kamailio 核心功能 :
- 例如:
KSR.maxfwd.process_maxfwd(10)
检查最大跳数。
- 例如:
- 日志记录 :
- 例如:
KSR.log(LOG_NOTICE, "Log message")
输出日志。
- 例如:
KSR 的结构
KSR
是一个分层的对象,其结构如下:
- 模块命名空间 :
- 每个 Kamailio 模块在
KSR
中有一个对应的命名空间。 - 例如:
tm
模块的函数通过KSR.tm
访问。
- 每个 Kamailio 模块在
- 核心功能 :
- 核心功能(如日志、变量访问)通过
KSR
直接访问。 - 例如:
KSR.log()
用于日志记录。
- 核心功能(如日志、变量访问)通过
KSR 的常用方法
以下是一些常用的 KSR
方法:
1. 核心功能
-
日志记录:
luaKSR.log(LOG_NOTICE, "This is a log message")
LOG_NOTICE
是日志级别,其他级别包括LOG_DEBUG
、LOG_ERROR
等。
-
变量访问:
lualocal src_ip = KSR.pv.get("$si") -- 获取源 IP local method = KSR.pv.get("$rm") -- 获取 SIP 方法
2. 模块功能
-
tm
模块:luaKSR.tm.t_relay() -- 转发请求 KSR.tm.t_check_trans() -- 检查事务
-
sl
模块:luaKSR.sl.send_reply(200, "OK") -- 发送 SIP 响应
-
maxfwd
模块:luaif KSR.maxfwd.process_maxfwd(10) < 0 then KSR.sl.send_reply(483, "Too Many Hops") end
-
registrar
模块:luaif KSR.registrar.save("location") < 0 then KSR.sl.reply_error() end
-
pv
模块:luaif KSR.pv.is_method("INVITE") then KSR.log(LOG_NOTICE, "INVITE received") end
KSR 的底层实现
KSR
是通过 Kamailio 的 Lua 模块 (app_lua.so
) 实现的。它封装了 Kamailio 的核心功能和模块函数,使其可以在 Lua 脚本中直接调用。
-
模块加载:
-
在 Kamailio 配置文件中加载
app_lua.so
模块:kamailioloadmodule "app_lua.so"
-
指定 Lua 脚本路径:
kamailiomodparam("app_lua", "load", "/path/to/script.lua")
-
-
函数映射:
- Kamailio 的 C 函数通过 Lua API 暴露给 Lua 脚本。
- 例如:
t_relay()
函数在 Lua 中通过KSR.tm.t_relay()
调用。
示例:KSR 的使用
以下是一个完整的 Lua 脚本示例,展示了 KSR
的常见用法:
lua
-- kamailio-test.lua
function request_route()
-- 获取 SIP 方法
local method = KSR.pv.get("$rm")
KSR.log(LOG_NOTICE, "Received " .. method .. " request")
-- 检查最大跳数
if KSR.maxfwd.process_maxfwd(10) < 0 then
KSR.sl.send_reply(483, "Too Many Hops")
return
end
-- 处理 REGISTER 请求
if KSR.pv.is_method("REGISTER") then
if KSR.registrar.save("location") < 0 then
KSR.sl.reply_error()
end
return
end
-- 处理 INVITE 请求
if KSR.pv.is_method("INVITE") then
if KSR.registrar.lookup("location") < 0 then
KSR.sl.send_reply(404, "User Not Found")
return
end
KSR.tm.t_relay()
end
-- 其他请求返回 405
KSR.sl.send_reply(405, "Method Not Allowed")
end
总结
KSR
是 Kamailio 提供的 Lua API 接口,用于访问 Kamailio 的核心功能和模块函数。- 通过
KSR
,Lua 脚本可以实现与原生 Kamailio 配置相同的功能,同时具备更高的灵活性和可扩展性。 - 熟悉
KSR
的使用是编写 Kamailio Lua 脚本的关键。