前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Kamailio 预处理器指令简述

Kamailio 预处理器指令简述

作者头像
杜金房
发布于 2025-04-13 09:17:13
发布于 2025-04-13 09:17:13
9800
代码可运行
举报
运行总次数:0
代码可运行

Kamailio 是一款开源的 SIP 服务器,用于构建大规模实时通信平台。

Kamailio 的预处理器指令(Preprocessor Directives)以单个 # 开头,执行诸如宏定义、文件包含、检查条件是否满足、字符串替换等预处理操作,方便大家写出灵活并且强大的路由脚本。

众所周知,OpenSIPS 自身是不带预处理功能的,需要借助带三方工具(比如 M4)来实现预处理器能力。而 Kamaiilio 在这方面就有优势。

以下是一些常用的 Kamailio 预处理器指令及其功能:

include_file、import_file

include_file 包含文件,该文件必须存在,否则就启动失败。

import_file 也是包含文件,但该文件可以存在,也可以不存在(kamailio 继续运行)。

包含文件的好处主要是可以把路由脚本拆成若干文件,增强可读性,也方便维护。比如我们可以把所有的宏定义组织到一个文件,模块和模块参数放到另外一个文件,请求路由、分支路由、回复路由、失败路由的处理独立成不同的一个文件。

define、ifdef、ifndef、else、endif 等宏指令

define 定义宏,ifdef、ifndef、else、endif 等的用法跟 C 语言的宏指令是很类似。

举例:

  • #!define WITH_SIPTRACE # 定义一个宏 WITH_SIPTRACE,作用是:是否需要 SIPTRACE 功能
  • #!define FLT_NATS 5 # 定义宏并赋值,NAT 事务标志为 5

试举一个相对比较完整的路由例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#!define FLT_NATS 5                           # NAT 事务标志
#!define FLB_NATB 6                           # NAT 分支标志
#!define FLB_NATSIPPING 7                     # NAT SIP PING 分支标志,Kamailio 主动向终端发送 SIP PING 请求

# ...

route[NATDETECT] {
  if (nat_uac_test("19")) {                 # NAT UAC 检查,参数可以是 8319 + 64),其中 64 检查 UAC Transport 是否为 WS(或者 WSSif (is_method("REGISTER")) {          # 如果是注册请求
      fix_nated_register();             # 修复来自 NAT 的注册请求
    } else {
      if(is_first_hop()) {              # 如果 Kamailio 是边沿 SIP Proxy,不是中间的 SIP Proxy
        set_contact_alias();          # 重写 Contact 头
      }
    }
    setflag(FLT_NATS);                    # 设置 NAT 事务标志
  }
  return;
}

route[REGISTRAR] {
  if (!is_method("REGISTER")) return;       # 如果请求的方法不是 REGISTER,那么马上返回

  if (isflagset(FLT_NATS)) {                # 如果已经设置了 NAT 事务标志
    setbflag(FLB_NATB);                   # 设置 NAT 分支标志
    setbflag(FLB_NATSIPPING);             # 同时设置 NAT SIP PING 分支标志
  }
  if (!save("location")) {
    sl_reply_error();
  }
  exit;
}

如果 Kamailio 不支持宏定义,把 FLT_NATS、FLB_NATB 等写成数字,可读性就很差了。

再举一例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#### 如果需要 SIPTRACE 功能,那么就定义 WITH_SIPTRACE
#### 如果不需要,就不定义这个宏

#!define WITH_SIPTRACE                        # 定义宏 WITH_SIPTRACE
                                              # 如果连续二个或者更多 #,比如 “##!define WITH_SIPTRACE”,就成了注释

#!ifdef WITH_SIPTRACE                         # 检查是否定义了 WITH_SIPTRACE/* heplify-server 地址 */
#!define HEPLIFY_SERVER "sip:127.0.0.1:9060"
#!define FLT_SIPTRACE 22

loadmodule "siptrace.so"
modparam("siptrace", "duplicate_uri", HEPLIFY_SERVER)
modparam("siptrace", "hep_mode_on", 1)
modparam("siptrace", "trace_to_database", 0)  # SIP 信令不写数据库
modparam("siptrace", "trace_flag", FLT_SIPTRACE)
modparam("siptrace", "trace_on", 1)

route[SIPTRACE] {
  sip_trace_mode("d"); # "d" 的意思是 sip 对话(dialog), 包括了 SIP 请求和 SIP 应答(默认只包括 SIP 请求)
  sip_trace();
  setflag(FLT_SIPTRACE);
  return;
}
#!endif                                       # 结束 “#!ifdef WITH_SIPTRACE

defenv、defenvs

defenv 定义环境变量

下面是一个能实际运行的完整路由脚本:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
debug=2
children=2
fork=no
auto_aliases=no
log_stderror=yes
loadmodule "pv.so"
#!defenv KAM_SIP_PORT=SIP_PORT                # 定义宏 KAM_SIP_PORT,其值来自环境变量 SIP_PORT
listen=udp:127.0.0.1:KAM_SIP_PORT
loadmodule "jsonrpcs.so"
loadmodule "sl.so"
loadmodule "ctl.so"
loadmodule "corex.so"
loadmodule "kex.so"

request_route {
  sl_send_reply("200", "OK");
  exit;
}

先运行 export SIP_PORT=5070 设置环境变量 接着运行 kamailio,控制台输出如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 0(2280) INFO: <core> [core/sctp_core.c:74]: sctp_core_check_support(): SCTP API not enabled - if you want to use it, load sctp module
Listening on
             udp: 127.0.0.1 [127.0.0.1]:5070
Aliases:

WARNING: no fork mode
 0(2280) INFO: <core> [core/tcp_main.c:5218]: init_tcp(): using epoll_lt as the io watch method (auto detected)
...

defenvs 的作用跟 defenv 类似,但前者多了双引号

我们在刚才那个脚本的基础上增加一行,全部内容为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
debug=2
children=2
fork=no
auto_aliases=no
log_stderror=yes
loadmodule "pv.so"
#!defenv KAM_SIP_PORT=SIP_PORT                # 定义宏 KAM_SIP_PORT,其值来自环境变量 SIP_PORT
#!defenvs KAM_SIP_DOMAIN=SIP_DOMAIN           # 定义宏 KAM_SIP_DOMAIN,其值来自环境变量 SIP_DOMAIN
listen=udp:127.0.0.1:KAM_SIP_PORT
loadmodule "jsonrpcs.so"
loadmodule "sl.so"
loadmodule "ctl.so"
loadmodule "corex.so"
loadmodule "kex.so"

request_route {
  sl_send_reply("200", "OK");
  exit;
}

先运行 export SIP_PORT=5070 && export SIP_DOMAIN=kamailio.org 设置环境变量

再运行 kamailio,等 kamailio 成功启动之后,再运行 kamcmd core.ppdefines_full,输出内容为(节选):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  name: KAM_SIP_PORT
  type: 0
  value: 5070
}
{
  name: KAM_SIP_DOMAIN
  type: 0
  value: "kamailio.org"   # 多了双引号
}

subst、substdef、substdefs

subst 字符串替换。

下面是成功的例子:

  • #!subst "/DBNAME/kamailio/g" # 数据库名字替换为 kamailio, g 代表全局替换
  • #!subst "/DBPASSWD/xyz/" # 数据库密码替换为 xyz
  • #!subst "!NATS_URL!nats://113.13.13.13:4222!g" # 这里不能再用 / 当分隔符,要用 !

下面的例子单个 subst 没问题,但放一起就会出问题:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#!subst "/SIP_PORT/5060/g"
#!subst "/SIP_PORT_2/5080/g"  # 处理成 /5060_2/5080/g,subst 执行的是字符串替换

substdef 的作用跟 subst 是一样的,用 kamcmd core.ppdefines_full 去观察,subst 是没有 ID 定义的,而 substdef 则有 ID 定义(KEMI 用 KX 模块可以访问这个 ID)。

substdefs 比 substdef 多双引号。

define 和 substdef 组合

请看下面这个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#!substdef "!MYSQL_USERNAME!kamailio!g"
#!substdef "!MYSQL_PASSWORD!1234@abde!g"
#!substdef "!MYSQL_HOST!127.0.0.1!g"
#!substdef "!MYSQL_PORT!3306!g"
#!substdef "!MYSQL_DBNAME!kamaiilio!g"

#!define MYSQL_DBURL "mysql://MYSQL_USERNAME:MYSQL_PASSWORD@MYSQL_HOST:MYSQL_PORT/MYSQL_DBNAME"

modparam("auth_db", "db_url", MYSQL_DBURL)

如果数据库密码里面有 “@”,或者别的特殊符号,需要把 define 和 substdef 组合起来使用。

defexp、ifexp、defexps

defexp、ifexp 等是 2022 年 9 月新增加的预处理指令。

下面是一个简单的例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#!ifexp KAMAILIO_VERSION >= 5006000   # `kamcmd core.ppdefines_full` 能查
...
#!else
...
#!endif

下面例子稍微复杂一点(很实用):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
loadmodule "htable.so"
...
#!ifexp Mod_htable
#!else
loadmodule "htable.so"                # 如果 htable 模块尚未加载,现在就加载 htalbe
#!endif

可以用上面的技巧避免某个模块重复装载。

更详细的说明可以参考下面链接:

  • https://www.kamailio.org/wikidocs/cookbooks/devel/core/#ifexp
  • https://github.com/miconda/snexpr
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-04-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FreeSWITCH中文社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • subst、substdef、substdefs
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档