OpenSIPS实战(六):添加自定义伪变量

目录

前言

1、什么是伪变量

2、添加伪变量的两种方法

    2.1 添加伪变量$appId场景实例

    2.2 使用核心伪变量实现$appId

    2.3 使用模块伪变量实现$appId

   2.4 使用脚本使用$appId伪变量

小结

 

 

 

前言

 

伪变量在编写脚本路由逻辑的过程中起到举足轻重的作用,路由逻辑可以通过伪变量获知SIP某个字段的值或者其它变量值。当我们希望在脚本中获知某个值,并使用这个值进行路由逻辑判断、存储等时,如果OpenSIPS没有提供这样的一个值,那这时可能就需要进行开发,添加一个自定义的伪变量来获得该值。

 

1、什么是伪变量

 

在使用OpensSIPS的脚本进行请求路由逻辑处理的过程中,我们经常会使用到一些已经预设了值的变量,如

$proto:请求的传输协议类型,如UDP、TCP、WS、WSS

$ci:请求的callid

$fU:From URI中的用户名

$rs:请求响应状态码

而这些变量不是理所当然就存在了的,这些就是OpenSIPS实现了的伪变量(Pseudo-Variable)。在脚本中可以直接调用获得这些伪变量,获取其值:

 

if ( proto == WS || proto == WSS)

      setflag(SRC_WS);

 xlog("$C(xg) callid:$ci from userid:$fU $C(xx)\n");

 

# $si - 引用消息的IP源地址, $sp - 引用消息的源端口

if ( lb_is_destination("$si","$sp","1") ) {

        lb_count_call("$si","$sp","1", "pstn");

}

onreply_route {

         if( $rs=="180" || $rs=="183") {

                  xlog("$C(xg) $tU ringing $C(xx)\n");

        }

}

 

2、添加伪变量的两种方法

 

有两种方法可以实现伪变量,第一种是添加为核心伪变量(core Pseudo-Variable),这种变量使用时是不需要包含其它模块的,所有路由中都可以调用。第二种是隶属于模块的伪变量,在模块中定义、实现,仅当该模块被加载(loadmodule)时才可用。

下面用实例来分别讲解两种定义伪变量的实现。

 

2.1 添加伪变量$appId场景实例

在我的实际使用场景中,需要获得注册到OpenSIPS上的SIP终端对应的appid(应用ID),并在注册的时候将appid和用户ID等注册信息保存到redis中,像这样:

...

       cache_raw_query("redis:group1",

                "HMSET user:$au appId $appId ip $Ri port $Rp");

...

但是保存注册信息到redis上的操作是在脚本中实现的,appid这个变量是不存在的,这时就可以考虑添加一个自定义的伪变量。

 

2.2 使用核心伪变量(core Pseudo-Variable)实现$appId

OpenSIPS所有的核心伪变量都定义在pvar.c文件中的_pv_names_table结构数组中 :

OpenSIPS伪变量是由pv_export_t数据结构来描述的。

下面是pv_export_t结构的定义:

 

下面是核心伪变量的实现步骤:

第一步:在pvar.h文件中的_pv_type枚举对象中添加一个类型,这里命名为“PVT_APPID”,用来设置pv_export_t伪变量结构中的type类型。

第二步:在_pv_names_table结构数组对象中添加一个新的自定义的伪变量结构。伪变量名为”appId”,变量类型为”PVT_APPID”,获取变量值函数getf的值为”pv_get_appid”,其他设置变量函数为空,因为在脚本中不需要修改这个变量值,所以setf值是空的。

 

第三步:实现pv_get_appid函数。

static str  str_appid = {_pv_appid, 32};

static int pv_get_appid(struct sip_msg *msg, pv_param_t *param,
        pv_value_t *res)
{
    if (str_appid.s[0] == '\0')
         return pv_get_null(msg, param, res);
    return pv_get_strval(msg, param, res, &str_appid);
}

(手机查看代码显示不全可左滑)

其中_pv_appid定义在auth_db模块的auth_db.h中,因为这里的实现是appid在注册的时候从数据库中读取userName和password字段用于鉴权的同时也读取出来的。读取出appid后存储到_pv_appid中(数据库读取这里省略,可以参考auth_db模块读取userName和password的代码实现)。

 

2.3使用模块伪变量实现

模块伪变量的实现是在创建模块的代码结构对象中,加入伪变量的结构对象实现的。上面讲到appid是在注册的时候从数据库中读取出来的,所以这里就在auth_db模块中添加appId伪变量的声明和实现。

 

第一步,切换到OpenSIPS源码根目录,进入modules/auth_db目录,编辑authdb_mod.c文件,加入声明模块伪变量的pv_export_t结构对象(OpenSIPS模块有很多类型的export结构,下一篇模块开发将详细介绍)。

 

static pv_export_t pvars[] = {
    {str_init("appId"), 1000, pv_get_appid, NULL, NULL, NULL, NULL, 0},
    {{0, 0}, 0, 0, 0, 0, 0, 0, 0}
};

伪变量名为“appId”,获取变量值函数getf的值为”pv_get_appid”,其他设置变量函数为空。这和核心伪变量的设置是一样的,包括pv_get_appid函数的实现,区别在于这里不需要区分变量类型,只要这个值不超过核心变量类型的枚举(_pv_type)定义的值就行,这里类型定义的值是1000。从定义pvars是一个数组对象可以看出,可以同时定义多个模块伪变量,这里只定义了一个。

第二步,将伪变量结构数组pvars加入到模块定义结构mod_exports中。

/*
 * Module interface
 */
struct module_exports mod_exports = { 
   "auth_db",
    MOD_TYPE_DEFAULT,/* class of this module */
    MODULE_VERSION,
    DEFAULT_DLFLAGS, /* dlopen flags */
    &deps,           /* OpenSIPS module dependencies */
    cmds,       /* Exported functions */
    0,          /* Exported async functions */
    params,     /* Exported parameters */
    0,          /* exported statistics */
    0,          /* exported MI functions */
    pvars,          /* exported pseudo-variables */
    0,          /* extra processes */
    mod_init,   /* module initialization function */
    0,          /* response function */
    destroy,    /* destroy function */
    child_init  /* child initialization function */
};

这样就定义模块伪变量就定义完成了。pv_get_appid函数和核心伪变量实现一样,_pv_appid对象也是在注册的时候从数据库中读取userName和password字段用于鉴权的同时也读取出来赋值的。

 

 

2.4 使用脚本使用$appId伪变量

现在可以在脚本中调用这个伪变量,在注册请求路由逻辑中加入保存注册信息到Redis的路由逻辑,注册时候保存,注销的时候删除掉保存的信息:

 

if (is_method("REGISTER")){
    ...
    $var(expire_value) = -1;
    if(is_present_hf("Expires")){
        $var(expire_value) = $(hdr(Expires){s.int});
    }else if($ct.fields(expires)){
        $var(expire_value) = $(ct.fields(expires){s.int});
    }
    # > 0 注册,== 0 注销
    if ($var(expire_value) > 0){
        cache_raw_query("redis:group1",
                "HMSET user:$au appId $appId ip $Ri port $Rp");
        cache_raw_query("redis:group1",
                 "EXPIRE user:$au $var(expire_value)");
    }else if($var(expire_value) == 0){
        cache_raw_query("redis:group1",
                "HDEL user:$au appId $appId ip $Ri port $Rp"); 
    }
    ...
}

需要注意的是,这里例子里只在注册的时候才会设置appId这个伪变量,所以不应该在注册请求路由之外使用这个伪变量,否则很可能将得不到预期的值。

 

小结

伪变量实现很容易,但是需要小心处理伪变量的赋值以及在脚本中的使用时机,不然得到的值可能是非预期的。在遇到可能需要实现伪变量的需求时,也要权衡是否有必要去实现,有没有更好的方法去实现这个需求,从而减少不必要的修改操作,避免出现风险。

 

(全文完)

 

提示:该公众号系列是循序渐进的,如果对该篇涉及到的内容有不清楚的,建议先阅读前几篇内容。

 

更多可以参考官网文档
http://www.opensips.org/Documentation/Development-Manual

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值