admin管理员组

文章数量:1438525

【mod

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,标志着该模块实在运行。

二、SIP服务加载和消息接收

在初始化完成后来到


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中。

三、SIP消息的处理

对事件处理的线程在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:......}......
}

至此对收到的具体消息类型进行不同的处理。

本文标签: mod