1. 目录
7. Helloworld注册服务器的数据流过程展现... 5
2. 如何实现plug-in
要实现动态加载库文件,以palg-in的方式工作一定是以Dynamic Loader的方式实现的。
实现Dynamic Load方式的几个重要函数:
#include <dlfcn.h>
void *dlopen(const char *filename, int flag);
void *dlsym(void *handle, const char *symbol);
int dlclose(void *handle);
经查找发现dlopen()在sr_module.c:load_module(path)中只调用一次:
Sr_mocule.c:
handle=dlopen(path, RTLD_NOW); /* resolve all symbols now */
dlsym()发现三次:
Sr_mocule.c:
m_ver=(char **)dlsym(handle, DLSYM_PREFIX "module_version");
m_flags=(char **)dlsym(handle, DLSYM_PREFIX "module_flags");
exp = (struct module_exports*)dlsym(handle, DLSYM_PREFIX "exports");
dlclose()一次
sr_module.c
load_module(path)dlclose(handle);
从上边的几次调用来看,只有
exp = (struct module_exports*)dlsym(handle, DLSYM_PREFIX "exports");
才是从dynamic library中查找Symbol的,查找的符号是module_exports。找查到后把值赋给exp,再向下看:
exp = (struct module_exports*)dlsym(handle, DLSYM_PREFIX "exports");
if ( (error =(char*)dlerror())!=0 ){
LOG(L_ERR, "ERROR: load_module: %s\n", error);
goto error1;
}
if (register_module(exp, path, handle)<0) goto error1;
return 0;
把exp,path,hanmdle传给register_module()。正如其名,register_moduel把传入的module添加到全局变量modules上。
也就是说每一个module必须得实现接口module_exports,实际上的确如此。Module_exports把core部分和module部分连接起来。到每个module中发现module_exprotsq包含了如下信息:
Module name
Exported functions
RPC method
Exported parameters
Initialization function
定义模块的初始化函数。
Response function
Destroy function
OnCancel function
Child init function
3. ModuleInterface
要进行二次开发了解ModuelInterface是必要条件。具体以可参考serdev.pdf的Chapter 7. The Module Interface。(些处的版本是ser 0.8.7 module_exports已与现在的版本不同)
在此只简要说明一下:
主要的结构:
Structure sr_module , Structure module_exports
Structure sr_module,一个单向链表,所有注册到系统中的module表要保存在这个单向链表中。
Structure module_exports,每一个module考必须有一个这新导出结构,用来描述导出接口,用来让core部分进行调用。
下边对module_exports的部分成员进行说明:
module_exports. cmd_export_t
导出命令数组,它是一个多维数组,每一维中的意义是:
1)name:Command name
2)cmd_function:命令对应的function
3)param_no:function使用的parameters个数
4)fixup_function:???(Point to the function called to "fix" the parameters)
5)flags : function flags
module_exports.rpc_export_t
??( null terminated array of exported rpc methods)
Module_exports. response_function
??( function called when the module should
be "destroyed", e.g: on ser exit;
can be null)
Module_exports.child_init_function
在多进程结构中,每当调用完fork()后,将调用些函数。
4. 全局数据结构
|
类型:数据名称 |
定义位置 |
作用 |
|
modules |
Sr_module.c |
一个单向链表,用来记录module信息 |
|
dont_fork |
Main.c |
指定子进程个数 |
|
debug |
Main.c |
Log输出的门限,大于些值时才把log输出到syslog |
|
socket_info :udp_listen socket_info: tcp_listen socket_info: tls_listen |
Socket_info.h |
网络接口,socket 双向链表 |
|
process_count |
Main.c |
进程数,包括主进程 |
|
|
|
|
|
|
|
|
5. 进程关系
|
Main_Process
|
|
Slow Process
|
|
Time Process
|
|
Netwrok |
6. receive_msg过程
先理解receive_msg的处理过程,十分有助于理解系统如何处理sip消息。Receive_msg位于Receive.c文件中。它是由udp_rcv_loop()从socket中收到数据后,然后传给receive_msg().
Receive_msg做了下列工作:
1. 把msg从buf形式打包成为msg,并把socket等相关数据,都存放在msg 结构中。
2. clear_branches();
3. reset_static_buffer();
4. exec_pre_req_cb(msg);
5. run_actions(main_rt.rlist[DEFAULT_RT], msg)
6. exec_post_req_cb(msg);
7. exec_pre_rpl_cb(msg)
8. exec_post_rpl_cb(msg);
9. reset_avps();
10. free_sip_msg(msg);
11. pkg_free(msg);
在些基本上看到了一个msg从生成到结束(pkg_free(msg))。
Script_cb.c中的操作:
add_callback
register_script_cb
destroy_cb_list
destroy_script_cb
exec_pre_cb
exec_post_cb
exec_pre_req_cb
exec_post_reg_cb
exec_pre_rpl_cb
exec_post_rpl_cb
Action.c中
Do_action
Run_action
浙公网安备 33010602011771号