概述
ejabberd_router是ejabberd项目消息传递的重要路由模块,属于路由总线,消息通过socket传递到达ejabberd_receiver模块解析处理后,传递给ejabberd_c2s逻辑处理模块,调用ejabberd_router:route/3进行路由分发,然后再区分不同情况,选择合适的二级路由中转,最后调用ejabberd_sm:route/3分发到目的用户
详述
路由章节其实并不局限于ejabberd_router模块,涉及到多个模块,以下将根据消息路由流程,逐步查看相关模块
ejabberd_c2s逻辑模块
1 Sever=>Client handle_info/4(处理来自ejabberd_sm:route/3的消息)
handle_info/4处理ejabberd_sm模块定义类型broadcast_data()
-type broadcast_data() ::
{rebind, pid(), binary()} | %%% ejabberd_c2s
{item, ljid(), mod_roster:subscription()} | %%% mod_roster/mod_shared_roster
{exit, binary()} | %%% mod_roster/mod_shared_roster
{privacy_list, mod_privacy:userlist(), binary()} | %%% mod_privacy
{blocking, unblock_all | {block | unblock, [ljid()]}}. %%% mod_blocking
handle_info({route, _From, _To, {broadcast, Data}},
StateName, StateData) ->
?DEBUG("broadcast~n~p~n", [Data]),
case Data of
%%%更新发送花名册
%%%订阅from_返回最后出席信息(未更新)
%%%取消from_返回unavailable出席信息==>(具体查看roster_change/3)
{item, IJID, ISubscription} ->
fsm_next_state(StateName,
roster_change(IJID, ISubscription, StateData));
%%%发送错误信息
{exit, Reason} ->
Lang = StateData#state.lang,
send_element(StateData, xmpp:serr_conflict(Reason, Lang)),
{stop, normal, StateData};
%%%更新发送黑名单
{privacy_list, PrivList, PrivListName} ->
case ejabberd_hooks:run_fold(privacy_updated_list,
StateData#state.server,
false,
[StateData#state.privacy_list,
PrivList]) of
false ->
fsm_next_state(StateName, StateData);
NewPL ->
PrivPushIQ =
#iq{type = set,
from = jid:remove_resource(StateData#state.jid),
to = StateData#state.jid,
id = <<"push", (randoms:get_string())/binary>>,
sub_els = [#privacy_query{
lists = [#privacy_list{
name = PrivListName}]}]},
NewState = send_stanza(StateData, PrivPushIQ),
fsm_next_state(StateName,
NewState#state{privacy_list = NewPL})
end;
%%%通讯阻止
{blocking, What} ->
NewState = route_blocking(What, StateData),
fsm_next_state(StateName, NewState);
_ ->
fsm_next_state(StateName, StateData)
end;
handle_info/4处理常规消息
handle_info({route, From, To, Packet}, StateName, StateData) when ?is_stanza(Packet) ->
%%%Pass==false,无需做后续处理(消息发送完成或已发送报错信息),若Pass==true,路由信息
{
Pass, NewState} =
case Packet of
%%%出席信息
#presence{type = T} ->
State = ejabberd_hooks:run_fold(c2s_presence_in,
StateData#state.server,
StateData,
[{
From, To, Packet}]),
case T of
%%%#State.pres_f 出席from(“某用户订阅了我的出席”)
%%%#State.pres_t 出席to(“我订阅了某用户出席”)
%%%#State.pres_a 出席(all)
%%%probe出席调查
probe ->
LFrom = jid:tolower(From),
LBFrom = jid:remove_resource(LFrom),
NewStateData =
case (?SETS):is_element(LFrom, State#state.pres_a)
orelse (?SETS):is_element(LBFrom, State#state.pres_a) of
true -> State;
false ->
case (?SETS):is_element(LFrom, State#state.pres_f) of
true ->
A = (?SETS):add_element(LFrom, State#state.pres_a),
State#state{pres_a = A};
false ->
case (?SETS):is_element(LBFrom, State#state.pres_f) of
true ->
A = (?SETS):add_element(LBFrom, State#state.pres_a),
State#state{pres_a = A};
false ->
State
end
end
end,
%%%直接回复probe请求-包含最后出席信息和时间戳(若源节点(from)为自身,则不做处理)
process_presence_probe(From, To, NewStateData),
{
false, NewStateData};
error ->
NewA = ?SETS:del_element(jid:tolower(From), State#state.pres_a),
{
true, State#state{pres_a = NewA}};
subscribe ->
SRes = is_privacy_allow(State, From, To, Packet, in),
{
SRes, State};
subscribed ->
SRes = is_privacy_allow(State, From, To, Packet, in),
{
SRes, State};
unsubscribe ->
SRes = is_privacy_allow(State, From, To, Packet, in),
{
SRes, State};
unsubscribed ->
SRes = is_privacy_allow(State, From, To, Packet, in),
{
SRes, State};
_ ->
case privacy_check_packet(State, From, To, Packet, in) of
allow ->
LFrom = jid:tolower(From),
LBFrom = jid:remove_resource(LFrom),
case (?SETS):is_element(LFrom, State#state.pres_a)
orelse (?SETS):is_element(LBFrom, State#state.pres_a) of
true ->
{
true, State};
false ->
case (?SETS):is_element(LFrom, State#state.pres_f) of
true ->
A = (?SETS):add_element(LFrom, State#state.pres_a),
{
true, State#state{pres_a = A}};
false ->
case (?SETS):is_element(LBFrom,
State#state.pres_f) of
true ->
A