news 2026/6/15 20:40:10

Kamailio 的 select 框架

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Kamailio 的 select 框架

选择框架

(作者:米哈尔·马蒂斯卡)

你可能会问,选择框架究竟为何会被引入?最主要的原因是,以往每当你需要检查入站消息的任意部分(如消息头)时,都必须编写新的模块或新的函数来实现该功能。此外,受历史局限性的影响,这类函数最多只能接收两个参数。若需要传入更多参数,就必须采用变通方案:先设置好相关属性,再由该函数对属性进行校验。因此,为了让路由脚本更具可读性和易懂性,一种全新的功能组件——选择框架,应运而生并得到了支持。

在脚本中,每个选择项都通过其唯一名称来标识。设计这种标识符的初衷,是让它的含义尽可能直观易懂。例如,当你看到@to.uri.user时,就能立刻明白它的作用是从To消息头所包含的URI中提取用户名。在脚本里,无论你在何处看到选择项标识符,它所代表的实际上都是对应的值,这个值会在路由脚本的执行过程中被调用。

为了保证选择框架的执行效率,选择项标识符会在SER启动阶段完成解析和固化。如果标识符无效,系统会输出错误信息,且SER将无法启动。而在请求路由脚本的执行阶段,仅需发起一次函数调用——如果该调用需要用到选择项标识符,就会将解析后的标识符作为参数传入。从性能角度来看,调用某个模块中的专用函数,与调用代表选择项标识符的函数,二者几乎没有差异。

工作原理概述

我们所说的选择项,本质上是一种标准化调用方式,用于调用那些在SER内核或各类模块中被定义为“选择函数”的方法。选择项标识符以@符号开头,由若干文本元素组成,元素之间用英文句点.分隔;部分场景下,还可以在方括号[]内添加单个整数或字符串作为参数。

选择项可在路由脚本的以下场景中使用:

  1. 表达式求值过程中;
  2. 作为属性赋值操作的右值;
  3. 作为部分函数的调用参数(此用法仅适用于支持该特性的函数,且参数必须是包含选择项标识符的文本,因此需要用双引号括起来)。

此外,在Xlog日志格式化功能中,选择项也可作为组成最终日志内容的元素,其格式为%@select.identifier.as.usual

选择函数的返回值为文本字符串,但需要注意的是,在以下两种情况下,返回值也可能是长度为0的空字符串:一是该空值本身是合法的(例如某些URI参数允许为空);二是选择函数在消息头中未找到目标值,或在解析消息时遇到语法错误。这类异常情况会对条件表达式产生影响——只要选择项的求值过程出现错误,无论其结果是否为空字符串,条件表达式的最终判断结果都会为false

选择项标识符规则

选择项标识符以@符号开头,后接至少1个、最多30个文本元素,元素之间用英文句点.分隔。标识符的元素大小写不敏感,你可以通过大小写区分来突出某些元素,但建议优先使用小写形式。

部分选择函数支持传入参数(例如重复消息头的索引、消息头名称或鉴权域),这类参数需要放在方括号[]内,嵌入到标识符中。参数索引从1开始计数(程序员需特别注意这一点),这种设计更符合直观认知;同时,你也可以使用负数索引表示反向计数,例如用-1表示获取最后一个消息头。

合法的标识符示例

@the.simplest @another.with!["parameter"] @yet.another![1].parameter![2] @you.can.also.mix.string!["like-this"].and.integer![1].parameters

嵌套选择项

你可能会发现SIP请求中存在一些重复的模式,例如许多SIP消息头中都包含URI元素。选择框架支持复用内核中已有的URI解析器和选择函数(也可以是参数值解析器,包括消息头参数或URI参数解析器,或是其他你能想到的解析器),并将其作用于选择项的中间结果,以此简化开发流程。

这种用法被称为嵌套选择项(如果感兴趣,可参考开发者文档),它会将一次选择项调用拆分为两次(或多次)独立的函数调用:第一次调用会返回URI文本作为临时结果,随后该临时结果会被传入内置的URI选择处理机制,最终生成目标结果。

例如,@hf_value!["X-any-header"].nameaddr.uri.user的执行逻辑为:

  1. 提取X-any-header消息头的值;
  2. 假设该值符合RFC规范中对name-addr格式的定义,将其传入name-addr选择解析器;
  3. 解析器从URI中提取用户名,并将其作为该选择项的最终返回值。

所有返回URI的选择项结果,都可以传入专门的URI选择函数,从而访问URI的各个组成部分。

以下选择项均可返回对应的URI:
@request_uri@dst_uri@next_hop@from.uri@to.uri@refer_to.uri@rpid.uri@contact.uri@record_route.uri,以及@hf_value!["any-header"].nameaddr.uri

若只需获取用户名,只需在选择项标识符后追加.user即可。无论第一步获取的是哪一个URI,.user这个标识符后缀的含义和用法都是完全相同的。

URI嵌套选择项标识符列表

标识符功能说明
type返回标准化(小写)的URI类型,例如sipsipsteltels
user返回URI中的用户名
pwd返回URI中的密码
host返回URI中的主机地址
port返回URI中的端口号(以上标识符的功能均通俗易懂)
transport返回URI中transport参数的值;若该参数不存在,则返回基于URI类型的默认传输协议
hostport返回URI中的主机:端口组合值;若端口未指定,则使用基于URI类型的默认端口
params返回URI中的完整参数部分,例如user=phone;phone-context=+1234
params!["parameter-name"]返回URI中指定参数的值

选择项在表达式中的应用

选择项可用于条件表达式,常见用法如下:

  1. 非空判断

    if (@select.value) {...}

    当选择项返回非空字符串时,条件判断结果为true

    注意:这种用法已被废弃,SER启动时会输出警告信息。在Sip-router中,该写法的逻辑变为:仅当返回值为非空且非零的数字字符串(如"123")时,条件才为true
    推荐使用标准写法:

    if (@select.value!="")

    if (!strempty(@select.value))
  2. 等值判断

    if (@select.value=="string") {...} if ("string"==@select.value) {...}

    当选择项求值过程无错误,且返回值与"string"完全相等时,条件为true。表达式右侧可以是任意值(包括AVP变量、PV变量或其他选择项),而非仅限于常量。

  3. 不等值判断

    if (@select.value!="string") {...} if ("string"!=@select.value) {...}

    用于判断两个字符串是否不相等。若选择项求值过程出错,条件判断结果也会为false

  4. 正则匹配

    if (@select.value=~"reg.*expr.?") {...}

    当选择函数返回的字符串匹配指定正则表达式时,条件为true注意:该运算符的左右操作数顺序不可随意调换,例如:

    if ("string"=~@select.value) {...}

    其逻辑是判断固定字符串"string"是否匹配选择项返回值作为正则表达式的规则,这通常不符合实际需求。

选择项可用于任意类型的表达式中,包括赋值操作的右值、if条件判断、while循环条件或switch分支判断等。
示例:

$attribute=@the.select.you.want

选择项在函数参数中的应用

部分函数支持将选择项的返回值作为调用参数,但该特性仅适用于明确支持此功能的函数。这类函数的参数会存储选择项标识符,函数会在SER启动阶段负责解析并固化该标识符,在运行阶段调用对应的选择函数以获取参数值。

若选择项求值过程出错,函数会返回false,且函数后续的执行逻辑通常会被跳过。

系统选择项

随着选择框架的优势逐渐显现,开发者开始探索更多可通过选择项访问的功能,系统选择项便是其中之一。这类选择项的标识符均以@sys开头,例如:

  • @sys.pid:返回当前进程ID的字符串形式
  • @sys.now:返回Unix时间戳
  • @sys.utc:返回UTC时间戳(适用于多时区场景)
  • @sys.unique:生成并返回一个随机的UUID(版本2)

模块中的选择项

选择框架是一种功能强大的工具,且可通过SER的模块机制轻松扩展。以TLS模块为例:脚本中需要获取或校验的大量TLS相关信息,都需要依赖TLS模块才能实现。因此,所有与TLS相关的选择项都隶属于TLS模块——当你加载该模块后,这些选择项即可使用;若未加载模块,SER会因检测到无效的选择项标识符而拒绝启动。

从使用角度来看,模块提供的选择项与内核原生的选择项并无差异,你无需关心选择项的具体来源,只需确保已加载所有必需的模块即可。

选择项完整列表

关于Sip-router开发版本(主分支)中已定义的所有选择项,可参考官方文档:http://sip-router.org/docbook/sip-router/branch/master/select_list/select_list.html。


追踪:• 选择项

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/15 18:30:51

RK3568平台YOLOv11模型部署全流程实战:环境搭建、模型转换与性能优化解析

文章目录 【深度实战】RK3568平台YOLO11模型从零到部署完整指南 前言 技术架构概览 一、开发环境搭建 1.1 Anaconda环境配置 1.2 RKNN工具链安装 下载核心组件 安装依赖和工具包 1.3 PyTorch环境配置 二、数据集准备与标注 2.1 数据集结构设计 2.2 图像标注工具配置 标注操作流…

作者头像 李华
网站建设 2026/6/15 18:04:41

节点Device (P2P0)的子节点Device (S5F0)不存在

第5个:节点Device (P2P0)的子节点Device (S5F0)不存在1: kd> g Breakpoint 54 hit eax00000000 ebxf743a948 ecx00000000 edx00000000 esi89781000 edi00008004 eipf741d900 espf791ad18 ebpf791ad34 iopl0 nv up ei pl nz na po nc cs0008 ss0010 ds0…

作者头像 李华
网站建设 2026/6/15 18:46:07

无需钥匙串快速创建 iOS 开发 / 发布证书 P12 CSR

在不少团队里,iOS 证书管理并不是只在一台 Mac 上完成的事情。 证书可能需要被多个构建节点使用,也可能需要在 Windows 或 Linux 环境下生成并分发。 问题往往出在钥匙串本身,它和 macOS 强绑定,不利于自动化,也不适合…

作者头像 李华
网站建设 2026/6/15 18:31:06

区块链交易所开发:为什么说这是数字金融时代的“新基建”?

引言:数字货币浪潮下的交易革命当比特币从“极客玩具”跃升为全球资产配置的新选项,当以太坊的智能合约催生出万亿级DeFi生态,数字货币交易已从边缘实验走向主流金融的核心舞台。据CoinGecko数据,全球数字货币交易所日均交易量已突…

作者头像 李华
网站建设 2026/6/15 13:17:27

三相计量芯片RN8302B驱动校正程序设计与实现

一、驱动程序架构 RN8302B的驱动程序需包含SPI通信模块、寄存器配置模块、数据采集模块和校准算法模块,其核心流程如下: 1. 初始化:配置SPI接口、复位芯片、设置工作模式。 2. 寄存器配置:设置通道使能、滤波参数、校准模式。 3. …

作者头像 李华