写在前面的话:里面的截图除非特殊说明,都是来自sr_module.h
参考:https://blog.csdn.net/ttomqq/article/details/38821411
一、关于版本
定义每一个模块都要说明这个模块的结构,以便于让kamailio能解释它,包括模块导出函数的结构cmd_export_和模块整体的结构module_exports。在sr_module.h中有两种版本的模块结构,一个是SER,一个是kam,是这样定义的:
这里的cmd_export_t和module_exports即可代表ser的也可以代表kam的。在自己定义模块时候直接由结构的内容体现是哪种版本(个数)。
模块导出函数结构:
模块结构:
有默认使用哪种版本的定义,猜想应该是从这里默认定义的:
默认版本是SER的,但是没找到用另一个版本kam所代表的数值,在json_mod.c中就是用的kam版本的(下图)
但是里面的版本声明 MODULE_VERSION仍然是SER的意思,这里面应该有一些定义是没注意到的,也就是什么时候可以用kam版本,这个我没找到,希望有大神能帮我解惑。
二、结构具体含义
1、对于模块导出函数结构:
第一个参数是该module导出到opensips脚本中的函数名。
第二个参数是对应的具体执行函数。cmd_function的函数定义为
从第二个参数起都是字符串。具体使用多少个参数由结构体第三个参数决定。
对于cmd_function,返回值小于0表示函数执行出错,返回值等于0会使该次脚本执行结束;返回值大于0表示函数执行正常。
第四个参数fixup function,主要用于将脚本传入的参数转换成int、正则表达式等其他种类的参数。常用的类型转换定义在mod_fix.h中,一般直接调用。
第五个参数用于描述该导出函数可以在哪段路由中被执行。可选的值定义在route.h中:
kam版本比ser的多了一个free_fixup_function参数,用于释放fixup function执行时申请的内存。
2、对于模块结构:
char* name: 模块的名字。
ser_cmd_export_t* cmds:前面定义的模块导出函数,这里如果一个模块里多于两个导出函数的情况下就要定义ser_cmd_export_t类型的结构体数组cmds[],每一个元素都是一个ser_cmd_export_t类型的结构体,各对应一个导出函数。
rpc_export_t* rpc_methods:远程程序调用的导出函数(rpc.h中定义的)。
param_export_t* params:参数导出,很多参数的时候也是定义一个param_export_t类型的数组,每个数组元素都是对这个参数的说明,例如acc_mod.c中的184行(部分):
init_function init_f: 模块初始化化函数,只在启动的时候被执行一次。
response_function response_f: 用于回复,有yes或no,null也行,不知道做什么的。
destroy_function destroy_f: 模块销毁时被调用。
onbreak_function onbreak_f;:不知道做什么的,onbreak_function在120行:
typedef void (*onbreak_function)(struct sip_msg*);是指向sip_msg结构体的一个指针。
child_init_function init_child_f: 模块在每个子进程中的初始化函数。因kamailio的架构是多进程的,像数据库连接这些必须在每个子进程内自己创建一份。
unsigned int dlflags: 一般都把值设为DEFAULT_DLFLAG,后面的stat_、nn_、pv_还没看是做什么的。
proc_export_t* procs: 定义模块自己的独立运行进程。
三、编写一个简单的模块
1、写模块主体代码test.c文件
在目录/usr/local/src/kamailio-5.1/kamailio/src/modules(也就是下载kamailio源码的位置那)建立一个名为test的文件夹,编写模块主体代码test.c文件。
cd /usr/local/src/kamailio-5.1/kamailio/src/modules
sudo mkdir test
cd test
sudo vi test.c /*根据自己常用的编辑器来即可*/
test.c文件如下:
/*
*时间:2018年3月29日16点24分
*作者:cxy
*模块名:test
*导出函数名:my_test
*功能:在初始化的时候在日志输出“cxy-initializing...”,在每一个request(invite,subscribe,
*register,cancel等等)到来时候输出“Receive message 123456”,为了看是否模块添加成功
*输入:123456(或者其他)
*输出:Receive message 123456(或者其他)
*/
#include "../../core/sr_module.h"
MODULE_VERSION
static int mod_init(void);
static int my_test(struct sip_msg* _msg, char *param);
/* Exported functions */
static cmd_export_t cmds[]={
{"my_test", (cmd_function)my_test, 1, 0, ANY_ROUTE}, /*在任何路由块都能用*/
{0, 0, 0, 0, 0}
};
/* Module interface */
struct ser_module_exports exports = {
"test", /**< null terminated module name */
cmds, /**< null terminated array of the exported
commands */
0, /**< null terminated array of exported rpc methods */
0, /**< null terminated array of the exported module parameters */
mod_init, /**< Initialization function */
0, /**< function used for responses, returns yes or no; can be null */
0, /**< function called when the module should be "destroyed", e.g: on ser exit;
can be null */
0,
0, /**< function called by all processes after the fork */
};
static int my_test(struct sip_msg* _msg, char *param)
{
LM_INFO("Receive message %s\n", param);
return 1;
}
static int mod_init(void)
{
LM_INFO("cxy-initializing...\n");
return 0;
}
2、编写Makefile文件
如果这个module不需要连接其他额外的库,只要把NAME后面生成库的名字改成test.so。如下所示:
#
#test makefile
#
#WARNING: do not run this directly. it should be run by the master Makefile
include ../../Makefile.defs
auto_gen=
NAME=test.so
LIBS=
DEFS+=-DSER_MOD_INTERFACE
include ../../Makefile.modules
3、编译
编译这个模块,除非在src目录下的主Makefile的exclude_modules中加入了这个模块的名字,就不编译这个模块。
cd /usr/local/src/kamailio-5.1/kamailio
sudo make all
sudo make install
(按理说不用再次安装吧?但是如果不再安装的话我发现生成的库文件test.so不能被导入/usr/local/lib64/kamailio/modules中,还是说是应该要安装一遍的?)
由于一开始我是仿照https://blog.csdn.net/ttomqq/article/details/38821411里面的test模块,修改了一些版本的差异,一开始我是按照kamailio版本写的模块但总是提示警告,提示我有多余的元素。经过比较,不管是cmd模块导出函数声明还是module模块导出声明,SER版本的的确是比kam版本的元素个数要少(SER版本cmd有5个元素,module有9个;kam版本cmd有6个,module有12个)。默认版本是SER,因此下面的警告根源在版本这里,改成了SER版本就行了。
4、载入新模块
不载入的话kamailio不会自己添加这个功能的,在kamailio.cfg文件中相应位置加入以下语句:
loadmodule "test.so"
把新编写的模块加入路由之中,在路由逻辑的request逻辑下插入:
my_test("123456");
5、验证模块是否添加成功
打开kamailio,注册用户并登陆,见https://blog.csdn.net/qq_36069590/article/details/79106771,可以看到路由被执行到时,日志有输出:
PS:这里有什么说错的麻烦能告诉我一下,谢谢!作为一个kamailio初学者,我感觉要学的东西太多了,这可能是和我专业不是计算机相关的有关吧。知识是一点点积累的,需要什么就去学什么就好了,涉及到基础的东西就去系统的看看教材或视频。今天花了一下午把昨天学到的东西记录在这里,在这里就顺便给自己打打气,加油cxy。
任重而道远,与君共勉。