模块加载过程
启动事件处理线程池
启动事件处理线程池 :
SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
=> sofia_msg_thread_start(0);
=> sofia_msg_thread_run
=> sofia_process_dispatch_event
=> our_sofia_event_callback : 处理消息
这个线程的主要流程很简单就是从队列mod_sofia_globals.msg_queue
取出消息,消息结构体是sofia_dispatch_event_t,然后执行
sofia_process_dispatch_event(&de)
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);
启动服务器监听
SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
=> config_sofia(0, NULL)
=> launch_sofia_profile_thread
=> sofia_profile_thread_run
=> nua_create
=> su_home_new
=> nua_stack_init
=> nta_agent_create
=> nta_agent_add_tport
=> tport_tbind
=> tport_bind_server
=> tport_listen : 监听客户端发来的数据
1、sip默认有4个profile,internal、internal-ipv6、external、external-ipv6,所以会启动4条sofia_profile_thread_run线程,4个UA互不干扰。
2、profile线程的主流程
profile->s_root = su_root_create(NULL);
sofia_glue_init_sql(profile);
profile->nua = nua_create(profile->s_root, /* Event loop */
sofia_event_callback, /* Callback for processing events */
profile,...);
switch_snprintf(qname, sizeof(qname), "sofia:%s", profile->name);
switch_sql_queue_manager_init_name(qname, &profile->qm, 2 ...);
switch_sql_queue_manager_start(profile->qm);
worker_thread = launch_sofia_worker_thread(profile);
while (mod_sofia_globals.running == 1 && sofia_test_pflag(profile, PFLAG_RUNNING) && sofia_test_pflag(profile, PFLAG_WORKER_RUNNING)) {
su_root_step(profile->s_root, 1000);
profile->last_root_step = switch_time_now();
}
通过代码可以看到profile线程创建了几个主要的线程:
2.1 调用协议栈API创建UA代理,并设置了回调sofia_event_callback。这边启动了clone_main线程。
2.2 数据库操作是在单独线程执行。
2.3 创建了profile worker线程。
方便术语统一分别称之为:
- profile主线程
- profile clone线程
- profile db线程
- profile worker线程
3、各个线程做了什么:
profile worker线程:从实际队列mod_sofia_globals.general_event_queue弹出一个事件对象,然后调用general_event_handler(event)处理该对象。所以general_event_handler用来处理事件消息。
if (switch_queue_pop_timeout(mod_sofia_globals.general_event_queue, &pop, 100000) == SWITCH_STATUS_SUCCESS) {
do {
switch_event_t *event = (switch_event_t *) pop;
general_event_handler(event);
switch_event_destroy(&event);
pop = NULL;
switch_queue_trypop(mod_sofia_globals.general_event_queue, &pop);
} while (pop);
}
profile clone线程:实际接收消息的线程,并对消息进行处理。
可以看到几个点:
1、底层的wait事件的回调函数是tport_wakeup_pri
2、leg接收消息的回调函数是nua_stack_process_request
3、nua代理的回调函数是sofia_event_callback
nua->nua_api_root = root;
su_task_copy(nua->nua_client, su_root_task(root));
su_clone_start(root,nua->nua_clone,nua,nua_stack_init,nua_stack_deinit);
=> arg.create=su_epoll_port_create
=> arg.parent = root
=> arg.magic = nua
=> su_pthread_port_clone_main
=> task->sut_port = su_epoll_port_create();
=> task->sut_root = su_salloc(su_port_home(task->sut_port), sizeof * task->sut_root);
=> nua_stack_init(task->sut_root, arg->magic);
=>nua->nua_root=task->sut_root
=>nua_handle_t *dnh=su_home_clone(nua->nua_home, sizeof(*dnh) + sizeof(*dnh->nh_prefs));
=>nua->nua_nta = nta_agent_create(root, NONE, NULL, NULL,..);
=>agent = su_home_new(sizeof(*agent);
=>incoming_queue_init(agent->sa_in..)
=>outgoing_queue_init(agent->sa_out..)
=>nta_agent_add_tport(agent, contact_url, ta_tags(ta)
=>agent->sa_tports = tport_tcreate(agent, nta_agent_class, agent->sa_root, TPTAG_IDLE(1800000), TAG_NEXT(tags));
=>tport_tbind(agent->sa_tports, tpn, tports, ta_tags(ta)
=>tport_bind_server(mr, mytpn, transports, (enum tport_via)public, ta_args(ta));
=>vtable = tport_vtable_by_name(ai->ai_canonname, public);
=>tport_primary_t *pri = tport_listen(mr, vtable, tpname, ainfo, tags);
=>pri = tport_alloc_primary(mr, vtable, tpn, ai, tags, &culprit);
=>vtable->vtp_init_primary(pri, tpn, ai, tags, return_culprit)
=>su_wait_create(wait, tp->tp_socket, tp->tp_events);
=>tport_t *tp = pri->pri_primary;
=>tp->index = su_root_register(mr->mr_root, wait, tport_wakeup_pri, tp, 0);
=>dnh->nh_ds->ds_leg = nta_leg_tcreate(nua->nua_nta, nua_stack_process_request, dnh, NTATAG_NO_DIALOG(1), TAG_END());
=>leg = su_home_clone(NULL, sizeof(*leg);
=>leg->leg_agent = agent;
=>leg->leg_callback = nua_stack_process_request
=>leg->leg_magic = dnh
=>agent->sa_default_leg = leg;
=> su_root_run(task->sut_root);
su_task_copy(nua->nua_server, su_clone_task(nua->nua_clone));
nua->nua_callback = sofia_event_callback;
nua->nua_magic = magic;