【mod_sofia模块源码阅读】

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:
	......
	}
	......
}

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

  • 9
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值