mod_sofia模块在freeswitch中用于SIP通话,所以理解该模块对用于处理通话的问题还是很有帮助的
freeswitch 版本为1.6.20
首先看模块的加载函数
其宏定义的原型在switch_types.h中
#define SWITCH_MODULE_LOAD_ARGS (switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool)
#define SWITCH_MODULE_LOAD_FUNCTION(name) switch_status_t name SWITCH_MODULE_LOAD_ARGS
SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load);
在加载函数中会对模块的全局变量mod_sofia_globals sofia初始化
struct mod_sofia_globals {
switch_memory_pool_t *pool; //内存池管理器
switch_hash_t *profile_hash; //sip_profile的hash表
switch_hash_t *gateway_hash; //internal或external的网关列表
switch_mutex_t *hash_mutex; //本结构hash表互斥信号量
uint32_t callid; //呼叫ID
int32_t running; //是否已运行的标志
int32_t threads; //线程号
int cpu_count; //本机CPU个数
int max_msg_queues; //最大的消息队列数
switch_mutex_t *mutex; 本结构互斥信号量
char guess_ip[80]; // nat环境下, 智能分析出的可访问地址
char hostname[512]; //分析出的本机名称
switch_queue_t *presence_queue; //状态队列
switch_queue_t *msg_queue; //sip消息队列
switch_thread_t *msg_queue_thread[SOFIA_MAX_MSG_QUEUE]; //不同队列所对应的分析线程句柄数组
int msg_queue_len; //消息队列的长度
struct sofia_private destroy_private;
struct sofia_private keep_private;
int guess_mask;
char guess_mask_str[16];
int debug_presence; //调试的状态标志, 从sofia.conf.xml文件中读取
int debug_sla; //调试的路由域标志
int auto_restart; //是否自动重启的标志, 从sofia.conf.xml文件中读取
int reg_deny_binding_fetch_and_no_lookup; /* backwards compatibility */
int auto_nat; //是否自动nat环境分析, 从sofia.conf.xml文件中读取
int tracelevel; //日志等级, 从sofia.conf.xml文件中读取
char *capture_server;
int rewrite_multicasted_fs_path;
int presence_flush;
switch_thread_t *presence_thread; //状态处理线程句柄
uint32_t max_reg_threads; //最大注册线程数
time_t presence_epoch;
mod_sofia_globals sofia全局变量使用系统分配的内存池创建消息队列和状态队列。
加载函数mod_sofia_load
SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
{
switch_chat_interface_t *chat_interface;
switch_api_interface_t *api_interface;
switch_management_interface_t *management_interface;
switch_application_interface_t *app_interface;
struct in_addr in;
switch_status_t status;
memset(&mod_sofia_globals, 0, sizeof(mod_sofia_globals));
......
switch_mutex_lock(mod_sofia_globals.mutex);
mod_sofia_globals.running = 1;
switch_mutex_unlock(mod_sofia_globals.mutex);
......
}
定义了一个api_interface指针,用于往核心中添加API。接着将全局变量清零。在一定的初始化后将全局变量的running 成员设为1,标志着该模块实在运行。
在初始化完成后来到
if (config_sofia(SOFIA_CONFIG_LOAD, NULL) != SWITCH_STATUS_SUCCESS) {
mod_sofia_globals.running = 0;
switch_goto_status(SWITCH_STATUS_GENERR, err);
return SWITCH_STATUS_GENERR;
}
sofia_msg_thread_start(0);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for profiles to start\n");
switch_yield(1500000);
config_sofia()函数非常长,在sofia.c中定义的。它解析sofia.conf.xml配置文件。初始化与Profile相关的的数据结构,并启动Profile。例如负责内部通话的internal Profile和外部通话的extenal Profile。启动函数在4940行launch_sofia_profile_thread(profile).
在sofia.c 2817行定义
void launch_sofia_profile_thread(sofia_profile_t *profile)
{
//switch_thread_t *thread;
switch_threadattr_t *thd_attr = NULL;
switch_threadattr_create(&thd_attr, profile->pool);
switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_threadattr_priority_set(thd_attr, SWITCH_PRI_REALTIME);
switch_thread_create(&profile->thread, thd_attr, sofia_profile_thread_run, profile, profile->pool);
}
启动一个新线程sofia_profile_thread_run(),同时将profile作为数参数。
在新线程中3076行,调用nua_creat()函数创建一个UA,nua_creat函数是Sofia-SIP提供的库函数,他将启动一个新UA,监听相关的端口(例如内部UA 5060端口),等待消息到来。
void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void *obj)
{
sofia_profile_t *profile = (sofia_profile_t *) obj;
//switch_memory_pool_t *pool;
sip_alias_node_t *node;
......
do {
profile->nua = nua_create(profile->s_root, /* Event loop */
sofia_event_callback, /* Callback for processing events */
profile, /* Additional data to pass to callback */
.
.
.)
}
......
}
当收到SIP请求时,便会回调sofia_event_callback()函数,在回调函数中处理消息(如果该消息是第一次invite还会创建新的session),接着执行sofia_queue_message()函数,对全局变量sofia_msg_thread_start(mod_sofia_globals.msg_queue_len + 1);加1,最后将消息push全局变量mod_sofia_globals.msg_queue中。
对事件处理的线程在config_sofia()函数执行后的,sofia_msg_thread_start()函数开始的。
该函数定义在sofia.c 2233行,
void sofia_msg_thread_start(int idx)
{
......
if (idx >= mod_sofia_globals.msg_queue_len) {
int i;
mod_sofia_globals.msg_queue_len = idx + 1;
for (i = 0; i < mod_sofia_globals.msg_queue_len; i++) {
if (!mod_sofia_globals.msg_queue_thread[i]) {
switch_threadattr_t *thd_attr = NULL;
switch_threadattr_create(&thd_attr, mod_sofia_globals.pool);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
//switch_threadattr_priority_set(thd_attr, SWITCH_PRI_REALTIME);
switch_thread_create(&mod_sofia_globals.msg_queue_thread[i],
thd_attr,
sofia_msg_thread_run,
mod_sofia_globals.msg_queue,
mod_sofia_globals.pool);
}
......
}
}
......
}
根据当前的需要启动多少消息处理线程。
线程函数sofia_msg_thread_run在sofia.c 2189行定义,
void *SWITCH_THREAD_FUNC sofia_msg_thread_run(switch_thread_t *thread, void *obj)
{
void *pop;
switch_queue_t *q = (switch_queue_t *) obj;
......
switch_mutex_lock(mod_sofia_globals.mutex);
msg_queue_threads++;
switch_mutex_unlock(mod_sofia_globals.mutex);
......
for(;;) {
if (switch_queue_pop(q, &pop) != SWITCH_STATUS_SUCCESS) {
switch_cond_next();
continue;
}
if (pop) {
sofia_dispatch_event_t *de = (sofia_dispatch_event_t *) pop;
sofia_process_dispatch_event(&de);
} else {
break;
}
}
......
}
在该线程中使用一个无限循环 ,不断从队列mod_sofia_globals.msg_queue中取出消息,然后使用sofia_process_dispatch_event函数发送出去。
继续看sofia_process_dispatch_event函数,定义在sofia.c 的2162行,调用our_sofia_event_callback()函数,
void sofia_process_dispatch_event(sofia_dispatch_event_t **dep)
{
sofia_dispatch_event_t *de = *dep;
nua_handle_t *nh = de->nh;
nua_t *nua = de->nua;
sofia_profile_t *profile = de->profile;
sofia_private_t *sofia_private = nua_handle_magic(de->nh);
*dep = NULL;
our_sofia_event_callback(de->data->e_event, de->data->e_status, de->data->e_phrase, de->nua, de->profile,
de->nh, sofia_private, de->sip, de, (tagi_t *) de->data->e_tags);
......
}
在 our_sofia_event_callback函数中switch语句的分支中有很多nua_i和nua_r开头的SIP消息。前作者表示收到一条响应消息,后者表示收到一条请求消息。
static void our_sofia_event_callback(nua_event_t event,
int status,
char const *phrase,
nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
sofia_dispatch_event_t *de, tagi_t tags[])
{
struct private_object *tech_pvt = NULL;
auth_res_t auth_res = AUTH_FORBIDDEN;
switch_core_session_t *session = NULL;
switch_channel_t *channel = NULL;
sofia_gateway_t *gateway = NULL;
int locked = 0;
int check_destroy = 1;
......
switch (event) {
case nua_r_get_params:
case nua_i_fork:
......
case nua_i_invite:
if (session && sofia_private) {
if (sofia_private->is_call > 1) {
sofia_handle_sip_i_reinvite(session, nua, profile, nh, sofia_private, sip, de, tags);
} else {
sofia_private->is_call++;
sofia_handle_sip_i_invite(session, nua, profile, nh, sofia_private, sip, de, tags);
}
}
break;
case nua_i_publish:
......
}
......
}
至此对收到的具体消息类型进行不同的处理。