目录
前言
1、模块开发介绍
1.1 可选的5个export结构定义
1.2 定义模块的export结构
2、模块开发实战:呼叫超频控制模块
2.1 代码实现
2.2 加载模块并添加路由处理
2.3 模块源码下载
小结
提示:本篇有较多代码,电脑浏览效果更佳
前言
OpenSIPS支持丰富的拓展模块,可以根据不同的场景需求搭配不同的模块来实现。但当遇到定制化很强的复杂业务,现有模块不能满足需求的情况,或者需要自定义功能时,就可以考虑进行模块开发了。
1、模块开发介绍
OpenSIPS模块开发本身并不复杂,主要涉及到5个可选的export结构和最关键的module_exports结构,已及模块初始化和销毁的函数。
1.1 可选的5个export结构定义
这些结构都在sr_module.h中定义。
cmd_export_模块导出函数结构定义:
(手机查看代码显示不全可左滑)
该结构主要用于定义可以在脚本中调用的函数,其中flag标志位用于说明该函数可以在哪个类型的路由块中调用,取值是下列宏中的一个或多个算术或“”得到的值。
具体路由块介绍请参考OpenSIPS实战(三):路由脚本介绍与实战。
acmd_export_模块导出异步函数结构定义,与cmd_export_功能和用法相同,只是执行方式为异步,不阻塞当前请求的路由。(这里就不给出具体定义了)
param_export_定义模块导出参数结构:
定义的导出参数可以在脚本文件中,紧随模块加载配置之后,对这些参数进行赋值。
proc_export_结构定义:
如果模块需要独立进程来运行的,就需要创建这个结构对象,主要定义进程运行的函数。
dep_export_结构定义:
用于定义该模块需要依赖于那些OpenSIPS模块才能运行。
除了这几个export结构外,还有其他几个,如mi_export_(用于定义MI命令)和stat_export_(用于统计信息)这里不做过多介绍。
1.2 定义模块的export结构
模块定义结构定义了很多成员,使用时并不是所有成员都需要定义,现在如果不明白每个成员用来做什么不要紧,只要了解有哪些成员就好,后面结合实例再来理解。
这里特别介绍下cmd_export_定义的模块导出函数cmd_function,函数原型定义如下:
模块函数只接收字符串参数(这也是为什么需要同时定义fixup_function的原因),参数个数是可变的,最多支持6个参数,每个模块函数都默认传入sip_msg参数,调用时不需要指定。cmd_function返回值小于0表示失败,返回值等于0会使脚本执行结束;返回值大于0表示成功。
2、模块开发实战:呼叫超频控制模块
为了更好的理解本篇内容,这里以一个模块开发过程来讲解。但是我不想简单的开发一个只能打印“hello world”这样的模块,太敷衍了,也起不到示例的作用。所以我想写一个既简单又能玩起来的模块。思来想去我觉得可以开发一个针对主被叫呼叫频率进行控制的模块,然后花了一个下午,把这个模块开发调试了下,有效代码才100行。下面就来看看这个模块的实现。
2.1 代码实现
首先看下导出结构的定义
commands[]:提供一个名为“check_frequency”的导出函数,该函数根据参数指定检查主叫是否呼叫超频或者被叫是否被呼叫超频,模块中实现函数为CheckFrequency( )。该函数接收一个unsigned int参数指定检查方(主被叫),但在脚本中调用传入的参数都是字符串的,所以需要fixup_uint_null( )(OpenSIPS已经实现了该函数)函数修复。REQUEST_ROUTE指定该函数只能在请求路由(route)中调用。
parameters[]:提供两个导出参数,名为“max_frequency”的用于设置指定时间间隔内最大呼叫数,参数类型为整型,存储在max_frequency变量中;“time_interval”指定计算超频的时间间隔,参数类型为整型,存储在of_interval变量中。即在指定时间间隔(time_interval)内呼叫超过了这个最大呼叫数(max_frequency)就算超频。
deps:指定模块依赖于cachedb_local模块,如果OpenSIPS启动加载该模块时,cachedb_local模块没有被加载,就会报错并退出(abort)。
下面是模块结构对象exports的定义
模块结构传入了前面定义的commands、parameters、deps作为对应结构成员的值,最前面三个结构成员使用默认值就可以,没有用到的字段都置为NULL,模块的初始化和销毁函数应该始终都定义并赋值。这里mod_init和mod_destroy函数实现看后文。
模块初始化mod_init( )实现,主要是初始化了cachedb_local,用于在内存中存储号码呼叫的统计信息。cached_loacl模块使用哈希表实现,缓存基于共享内存,所以缓存内容在多进程间共享:
模块销毁函数mod_destroy( )的实现,主要是销毁cachedb_local,释放资源:
模块最核心功能CheckFrequency( )函数的实现:
CheckFrequency函数首先根据direction参数,确定要检查的是主叫还是被叫超频,并获得对应的号码。然后以号码为key将对应value值加1,设置key超时时间为of_interval,并返回自增后的值保存到val变量。最后检查当前值val是否大于设置的max_frequency值,如果大于则认为是超频,返回-1。
overf_cdbf.add操作首先检查key是否存在,不存在则插入键值并设置键超时。如果key存在则检查key是否超时,如果超时则删掉该key(cached_loacl使用链表存储重复key值的哈希表实现)项,以overf_cdbf.add传入的新值重新创建key项,并设置超时。如果key存在且没有超时,则value += 1(1是传入的第三个参数)。
这样呼叫超频控制模块就实现完成了。
最后在modues目录下新建over_frequency目录,源文件放到这个目录,编辑Makefile:
最后在over_frequency目录下编译,将生成的over_frequency.so动态库文件复制到模块安装目录,然后就可以开始测试(玩)了。
2.2 加载模块并添加路由处理
这里的示例配置同一主叫10分钟(600秒)内不能呼叫超过10次,否则返回“403 Over Frequency”并结束呼叫。time_interval的单位是秒。check_frequency函数参数1表示检查主叫,2表示检查被叫。
经过测试,结果如预期那样运行。10分钟内如果主叫呼叫了10次,再发起呼叫返回“403 Over Frequency”,从计时开始的10分钟后可以恢复正常呼叫,同时从再一次呼叫发起时间起重新计时,如果超过限制将继续禁止发起呼叫。
该模块实现还很简陋,没有考虑内存占用量、key的删除和时间段精确控制、单单用号码作为key导致可能的主被叫统计混在一起等,以及更多的业务需求场景,甚至可能OpenSIPS已经实现了这个功能。但是通过这个模块的开发,已经清楚的展示的OpenSIPS模块开发的过程,而且贴合实际应用,也是一个可玩性较强的模块。已经达到了这本篇文章的目的。
2.2 模块代码下载
领取专属 10元无门槛券
私享最新 技术干货