diff options
Diffstat (limited to 'src/ejabberd_sm.erl')
-rw-r--r-- | src/ejabberd_sm.erl | 153 |
1 files changed, 69 insertions, 84 deletions
diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index d60daca63..13ffa1af0 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -25,8 +25,6 @@ -module(ejabberd_sm). --behaviour(ejabberd_config). - -author('alexey@process-one.net'). -ifndef(GEN_SERVER). @@ -65,6 +63,7 @@ get_session_pid/3, get_session_sid/3, get_session_sids/2, + get_session_sids/3, get_user_info/2, get_user_info/3, set_user_info/5, @@ -83,15 +82,14 @@ ]). -export([init/1, handle_call/3, handle_cast/2, - handle_info/2, terminate/2, code_change/3, opt_type/1]). + handle_info/2, terminate/2, code_change/3]). -include("logger.hrl"). - -include("xmpp.hrl"). - -include("ejabberd_commands.hrl"). -include("ejabberd_sm.hrl"). -include("ejabberd_stacktrace.hrl"). +-include("translate.hrl"). -callback init() -> ok | {error, any()}. -callback set_session(#session{}) -> ok | {error, any()}. @@ -117,21 +115,24 @@ start_link() -> ?GEN_SERVER:start_link({local, ?MODULE}, ?MODULE, [], []). --spec stop() -> ok. +-spec stop() -> ok | {error, atom()}. stop() -> - supervisor:terminate_child(ejabberd_sup, ?MODULE), - supervisor:delete_child(ejabberd_sup, ?MODULE), - ok. + case supervisor:terminate_child(ejabberd_sup, ?MODULE) of + ok -> supervisor:delete_child(ejabberd_sup, ?MODULE); + Err -> Err + end. -spec route(jid(), term()) -> ok. %% @doc route arbitrary term to c2s process(es) route(To, Term) -> - case catch do_route(To, Term) of - {'EXIT', Reason} -> - ?ERROR_MSG("route ~p to ~p failed: ~p", - [Term, To, Reason]); - _ -> - ok + try do_route(To, Term), ok + catch ?EX_RULE(E, R, St) -> + StackTrace = ?EX_STACK(St), + ?ERROR_MSG("Failed to route term to ~s:~n" + "** Term = ~p~n" + "** ~s", + [jid:encode(To), Term, + misc:format_exception(2, E, R, StackTrace)]) end. -spec route(stanza()) -> ok. @@ -139,14 +140,10 @@ route(Packet) -> #jid{lserver = LServer} = xmpp:get_to(Packet), case ejabberd_hooks:run_fold(sm_receive_packet, LServer, Packet, []) of drop -> - ?DEBUG("hook dropped stanza:~n~s", [xmpp:pp(Packet)]); + ?DEBUG("Hook dropped stanza:~n~s", [xmpp:pp(Packet)]); Packet1 -> - try do_route(Packet1), ok - catch ?EX_RULE(E, R, St) -> - ?ERROR_MSG("failed to route packet:~n~s~nReason = ~p", - [xmpp:pp(Packet1), - {E, {R, ?EX_STACK(St)}}]) - end + do_route(Packet1), + ok end. -spec open_session(sid(), binary(), binary(), binary(), prio(), info()) -> ok. @@ -201,19 +198,19 @@ bounce_offline_message(Acc) -> -spec bounce_sm_packet({bounce | term(), stanza()}) -> any(). bounce_sm_packet({bounce, Packet} = Acc) -> Lang = xmpp:get_lang(Packet), - Txt = <<"User session not found">>, + Txt = ?T("User session not found"), Err = xmpp:err_service_unavailable(Txt, Lang), ejabberd_router:route_error(Packet, Err), {stop, Acc}; bounce_sm_packet({_, Packet} = Acc) -> - ?DEBUG("dropping packet to unavailable resource:~n~s", + ?DEBUG("Dropping packet to unavailable resource:~n~s", [xmpp:pp(Packet)]), Acc. -spec disconnect_removed_user(binary(), binary()) -> ok. disconnect_removed_user(User, Server) -> - route(jid:make(User, Server), {exit, <<"User removed">>}). + route(jid:make(User, Server), {exit, ?T("User removed")}). get_user_resources(User, Server) -> LUser = jid:nodeprep(User), @@ -401,6 +398,16 @@ get_session_sids(User, Server) -> Sessions = get_sessions(Mod, LUser, LServer), [SID || #session{sid = SID} <- Sessions]. +-spec get_session_sids(binary(), binary(), binary()) -> [sid()]. + +get_session_sids(User, Server, Resource) -> + LUser = jid:nodeprep(User), + LServer = jid:nameprep(Server), + LResource = jid:resourceprep(Resource), + Mod = get_sm_backend(LServer), + Sessions = get_sessions(Mod, LUser, LServer, LResource), + [SID || #session{sid = SID} <- Sessions]. + -spec dirty_get_sessions_list() -> [ljid()]. dirty_get_sessions_list() -> @@ -443,10 +450,10 @@ get_vh_session_number(Server) -> %% Why the hell do we have so many similar kicks? c2s_handle_info(#{lang := Lang} = State, replaced) -> State1 = State#{replaced => true}, - Err = xmpp:serr_conflict(<<"Replaced by new connection">>, Lang), + Err = xmpp:serr_conflict(?T("Replaced by new connection"), Lang), {stop, ejabberd_c2s:send(State1, Err)}; c2s_handle_info(#{lang := Lang} = State, kick) -> - Err = xmpp:serr_policy_violation(<<"has been kicked">>, Lang), + Err = xmpp:serr_policy_violation(?T("has been kicked"), Lang), c2s_handle_info(State, {kick, kicked_by_admin, Err}); c2s_handle_info(State, {kick, _Reason, Err}) -> {stop, ejabberd_c2s:send(State, Err)}; @@ -477,7 +484,7 @@ init([]) -> ejabberd_hooks:add(host_up, ?MODULE, host_up, 50), ejabberd_hooks:add(host_down, ?MODULE, host_down, 60), ejabberd_hooks:add(config_reloaded, ?MODULE, config_reloaded, 50), - lists:foreach(fun host_up/1, ejabberd_config:get_myhosts()), + lists:foreach(fun host_up/1, ejabberd_option:hosts()), ejabberd_commands:register_commands(get_commands_spec()), {ok, #state{}}; {error, Why} -> @@ -490,14 +497,20 @@ handle_call(_Request, _From, State) -> handle_cast(_Msg, State) -> {noreply, State}. handle_info({route, Packet}, State) -> - route(Packet), + try route(Packet) + catch ?EX_RULE(E, R, St) -> + StackTrace = ?EX_STACK(St), + ?ERROR_MSG("Failed to route packet:~n~s~n** ~s", + [xmpp:pp(Packet), + misc:format_exception(2, E, R, StackTrace)]) + end, {noreply, State}; handle_info(Info, State) -> - ?WARNING_MSG("unexpected info: ~p", [Info]), + ?WARNING_MSG("Unexpected info: ~p", [Info]), {noreply, State}. terminate(_Reason, _State) -> - lists:foreach(fun host_down/1, ejabberd_config:get_myhosts()), + lists:foreach(fun host_down/1, ejabberd_option:hosts()), ejabberd_hooks:delete(host_up, ?MODULE, host_up, 50), ejabberd_hooks:delete(host_down, ?MODULE, host_down, 60), ejabberd_hooks:delete(config_reloaded, ?MODULE, config_reloaded, 50), @@ -635,23 +648,23 @@ do_route(#jid{lresource = <<"">>} = To, Term) -> do_route(jid:replace_resource(To, R), Term) end, get_user_resources(To#jid.user, To#jid.server)); do_route(To, Term) -> - ?DEBUG("broadcasting ~p to ~s", [Term, jid:encode(To)]), + ?DEBUG("Broadcasting ~p to ~s", [Term, jid:encode(To)]), {U, S, R} = jid:tolower(To), Mod = get_sm_backend(S), case get_sessions(Mod, U, S, R) of [] -> - ?DEBUG("dropping broadcast to unavailable resourse: ~p", [Term]); + ?DEBUG("Dropping broadcast to unavailable resourse: ~p", [Term]); Ss -> Session = lists:max(Ss), Pid = element(2, Session#session.sid), - ?DEBUG("sending to process ~p: ~p", [Pid, Term]), + ?DEBUG("Sending to process ~p: ~p", [Pid, Term]), ejabberd_c2s:route(Pid, Term) end. -spec do_route(stanza()) -> any(). do_route(#presence{to = To, type = T} = Packet) when T == subscribe; T == subscribed; T == unsubscribe; T == unsubscribed -> - ?DEBUG("processing subscription:~n~s", [xmpp:pp(Packet)]), + ?DEBUG("Processing subscription:~n~s", [xmpp:pp(Packet)]), #jid{luser = LUser, lserver = LServer} = To, case is_privacy_allow(Packet) andalso ejabberd_hooks:run_fold( @@ -664,7 +677,7 @@ do_route(#presence{to = To, type = T} = Packet) priority = Prio}) when is_integer(Prio) -> Pid = element(2, SID), Packet1 = Packet#presence{to = jid:replace_resource(To, R)}, - ?DEBUG("sending to process ~p:~n~s", + ?DEBUG("Sending to process ~p:~n~s", [Pid, xmpp:pp(Packet1)]), ejabberd_c2s:route(Pid, {route, Packet1}); (_) -> @@ -674,14 +687,14 @@ do_route(#presence{to = To, type = T} = Packet) ok end; do_route(#presence{to = #jid{lresource = <<"">>} = To} = Packet) -> - ?DEBUG("processing presence to bare JID:~n~s", [xmpp:pp(Packet)]), + ?DEBUG("Processing presence to bare JID:~n~s", [xmpp:pp(Packet)]), {LUser, LServer, _} = jid:tolower(To), lists:foreach( fun({_, R}) -> do_route(Packet#presence{to = jid:replace_resource(To, R)}) end, get_user_present_resources(LUser, LServer)); do_route(#message{to = #jid{lresource = <<"">>} = To, type = T} = Packet) -> - ?DEBUG("processing message to bare JID:~n~s", [xmpp:pp(Packet)]), + ?DEBUG("Processing message to bare JID:~n~s", [xmpp:pp(Packet)]), if T == chat; T == headline; T == normal -> route_message(Packet); true -> @@ -690,14 +703,14 @@ do_route(#message{to = #jid{lresource = <<"">>} = To, type = T} = Packet) -> end; do_route(#iq{to = #jid{lresource = <<"">>} = To, type = T} = Packet) -> if T == set; T == get -> - ?DEBUG("processing IQ to bare JID:~n~s", [xmpp:pp(Packet)]), + ?DEBUG("Processing IQ to bare JID:~n~s", [xmpp:pp(Packet)]), gen_iq_handler:handle(?MODULE, Packet); true -> ejabberd_hooks:run_fold(bounce_sm_packet, To#jid.lserver, {pass, Packet}, []) end; do_route(Packet) -> - ?DEBUG("processing packet to full JID:~n~s", [xmpp:pp(Packet)]), + ?DEBUG("Processing packet to full JID:~n~s", [xmpp:pp(Packet)]), To = xmpp:get_to(Packet), {LUser, LServer, LResource} = jid:tolower(To), Mod = get_sm_backend(LServer), @@ -719,7 +732,7 @@ do_route(Packet) -> Ss -> Session = lists:max(Ss), Pid = element(2, Session#session.sid), - ?DEBUG("sending to process ~p:~n~s", [Pid, xmpp:pp(Packet)]), + ?DEBUG("Sending to process ~p:~n~s", [Pid, xmpp:pp(Packet)]), ejabberd_c2s:route(Pid, {route, Packet}) end. @@ -754,7 +767,7 @@ route_message(#message{to = To, type = Type} = Packet) -> Ss -> Session = lists:max(Ss), Pid = element(2, Session#session.sid), - ?DEBUG("sending to process ~p~n", [Pid]), + ?DEBUG("Sending to process ~p~n", [Pid]), LMaxRes = jid:resourceprep(MaxRes), Packet1 = maybe_mark_as_copy(Packet, LResource, @@ -860,12 +873,11 @@ check_max_sessions(LUser, LServer) -> %% Defaults to infinity -spec get_max_user_sessions(binary(), binary()) -> infinity | non_neg_integer(). get_max_user_sessions(LUser, Host) -> - case acl:match_rule(Host, max_user_sessions, - jid:make(LUser, Host)) - of - Max when is_integer(Max) -> Max; - infinity -> infinity; - _ -> ?MAX_USER_SESSIONS + case ejabberd_shaper:match(Host, max_user_sessions, + jid:make(LUser, Host)) of + Max when is_integer(Max) -> Max; + infinity -> infinity; + _ -> ?MAX_USER_SESSIONS end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -882,15 +894,13 @@ force_update_presence({LUser, LServer}) -> -spec get_sm_backend(binary()) -> module(). get_sm_backend(Host) -> - DBType = ejabberd_config:get_option( - {sm_db_type, Host}, - ejabberd_config:default_ram_db(Host, ?MODULE)), - list_to_atom("ejabberd_sm_" ++ atom_to_list(DBType)). + DBType = ejabberd_option:sm_db_type(Host), + list_to_existing_atom("ejabberd_sm_" ++ atom_to_list(DBType)). -spec get_sm_backends() -> [module()]. get_sm_backends() -> - lists:usort([get_sm_backend(Host) || Host <- ejabberd_config:get_myhosts()]). + lists:usort([get_sm_backend(Host) || Host <- ejabberd_option:hosts()]). -spec get_vh_by_backend(module()) -> [binary()]. @@ -898,7 +908,7 @@ get_vh_by_backend(Mod) -> lists:filter( fun(Host) -> get_sm_backend(Host) == Mod - end, ejabberd_config:get_myhosts()). + end, ejabberd_option:hosts()). %%-------------------------------------------------------------------- %%% Cache stuff @@ -914,18 +924,9 @@ init_cache() -> -spec cache_opts() -> [proplists:property()]. cache_opts() -> - MaxSize = ejabberd_config:get_option( - sm_cache_size, - ejabberd_config:cache_size(global)), - CacheMissed = ejabberd_config:get_option( - sm_cache_missed, - ejabberd_config:cache_missed(global)), - LifeTime = case ejabberd_config:get_option( - sm_cache_life_time, - ejabberd_config:cache_life_time(global)) of - infinity -> infinity; - I -> timer:seconds(I) - end, + MaxSize = ejabberd_option:sm_cache_size(), + CacheMissed = ejabberd_option:sm_cache_missed(), + LifeTime = ejabberd_option:sm_cache_life_time(), [{max_size, MaxSize}, {cache_missed, CacheMissed}, {life_time, LifeTime}]. -spec clean_cache(node()) -> non_neg_integer(). @@ -949,10 +950,7 @@ clean_cache() -> use_cache(Mod, LServer) -> case erlang:function_exported(Mod, use_cache, 1) of true -> Mod:use_cache(LServer); - false -> - ejabberd_config:get_option( - {sm_use_cache, LServer}, - ejabberd_config:use_cache(LServer)) + false -> ejabberd_option:sm_use_cache(LServer) end. -spec use_cache() -> boolean(). @@ -961,7 +959,7 @@ use_cache() -> fun(Host) -> Mod = get_sm_backend(Host), use_cache(Mod, Host) - end, ejabberd_config:get_myhosts()). + end, ejabberd_option:hosts()). -spec cache_nodes(module(), binary()) -> [node()]. cache_nodes(Mod, LServer) -> @@ -1041,16 +1039,3 @@ kick_user(User, Server, Resource) -> make_sid() -> {misc:unique_timestamp(), self()}. - --spec opt_type(atom()) -> fun((any()) -> any()) | [atom()]. -opt_type(sm_db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; -opt_type(O) when O == sm_use_cache; O == sm_cache_missed -> - fun(B) when is_boolean(B) -> B end; -opt_type(O) when O == sm_cache_size; O == sm_cache_life_time -> - fun(I) when is_integer(I), I>0 -> I; - (unlimited) -> infinity; - (infinity) -> infinity - end; -opt_type(_) -> - [sm_db_type, sm_use_cache, sm_cache_size, sm_cache_missed, - sm_cache_life_time]. |