diff options
Diffstat (limited to 'src/ejabberd_sm.erl')
-rw-r--r-- | src/ejabberd_sm.erl | 252 |
1 files changed, 126 insertions, 126 deletions
diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 678452951..218e657f3 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -5,7 +5,7 @@ %%% Created : 24 Nov 2002 by Alexey Shchepin <alexey@process-one.net> %%% %%% -%%% ejabberd, Copyright (C) 2002-2015 ProcessOne +%%% ejabberd, Copyright (C) 2002-2016 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -25,6 +25,8 @@ -module(ejabberd_sm). +-behaviour(ejabberd_config). + -author('alexey@process-one.net'). -behaviour(gen_server). @@ -33,6 +35,7 @@ -export([start/0, start_link/0, route/3, + process_iq/3, open_session/5, open_session/6, close_session/4, @@ -48,6 +51,7 @@ dirty_get_my_sessions_list/0, get_vh_session_list/1, get_vh_session_number/1, + get_vh_by_backend/1, register_iq_handler/4, register_iq_handler/5, unregister_iq_handler/2, @@ -61,12 +65,12 @@ get_user_ip/3, get_max_user_sessions/2, get_all_pids/0, - is_existing_resource/3 + is_existing_resource/3, + get_commands_spec/0 ]). -%% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, - handle_info/2, terminate/2, code_change/3]). + handle_info/2, terminate/2, code_change/3, opt_type/1]). -include("ejabberd.hrl"). -include("logger.hrl"). @@ -94,10 +98,6 @@ %%==================================================================== %% API %%==================================================================== -%%-------------------------------------------------------------------- -%% Function: start_link() -> {ok,Pid} | ignore | {error,Error} -%% Description: Starts the server -%%-------------------------------------------------------------------- -export_type([sid/0]). start() -> @@ -106,8 +106,7 @@ start() -> supervisor:start_child(ejabberd_sup, ChildSpec). start_link() -> - gen_server:start_link({local, ?MODULE}, ?MODULE, [], - []). + gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). -spec route(jid(), jid(), xmlel() | broadcast()) -> ok. @@ -124,7 +123,7 @@ route(From, To, Packet) -> open_session(SID, User, Server, Resource, Priority, Info) -> set_session(SID, User, Server, Resource, Priority, Info), check_for_sessions_to_replace(User, Server, Resource), - JID = jlib:make_jid(User, Server, Resource), + JID = jid:make(User, Server, Resource), ejabberd_hooks:run(sm_register_connection_hook, JID#jid.lserver, [SID, JID, Info]). @@ -136,18 +135,21 @@ open_session(SID, User, Server, Resource, Info) -> -spec close_session(sid(), binary(), binary(), binary()) -> ok. close_session(SID, User, Server, Resource) -> - Mod = get_sm_backend(), - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - LResource = jlib:resourceprep(Resource), + LUser = jid:nodeprep(User), + LServer = jid:nameprep(Server), + LResource = jid:resourceprep(Resource), + Mod = get_sm_backend(LServer), Info = case Mod:delete_session(LUser, LServer, LResource, SID) of {ok, #session{info = I}} -> I; {error, notfound} -> [] end, - JID = jlib:make_jid(User, Server, Resource), + JID = jid:make(User, Server, Resource), ejabberd_hooks:run(sm_remove_connection_hook, JID#jid.lserver, [SID, JID, Info]). +-spec check_in_subscription(any(), binary(), binary(), + any(), any(), any()) -> any(). + check_in_subscription(Acc, User, Server, _JID, _Type, _Reason) -> case ejabberd_auth:is_user_exists(User, Server) of true -> Acc; @@ -165,21 +167,21 @@ bounce_offline_message(From, To, Packet) -> -spec disconnect_removed_user(binary(), binary()) -> ok. disconnect_removed_user(User, Server) -> - ejabberd_sm:route(jlib:make_jid(<<"">>, <<"">>, <<"">>), - jlib:make_jid(User, Server, <<"">>), + ejabberd_sm:route(jid:make(<<"">>, <<"">>, <<"">>), + jid:make(User, Server, <<"">>), {broadcast, {exit, <<"User removed">>}}). get_user_resources(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - Mod = get_sm_backend(), + LUser = jid:nodeprep(User), + LServer = jid:nameprep(Server), + Mod = get_sm_backend(LServer), Ss = Mod:get_sessions(LUser, LServer), [element(3, S#session.usr) || S <- clean_session_list(Ss)]. -spec get_user_present_resources(binary(), binary()) -> [tuple()]. get_user_present_resources(LUser, LServer) -> - Mod = get_sm_backend(), + Mod = get_sm_backend(LServer), Ss = Mod:get_sessions(LUser, LServer), [{S#session.priority, element(3, S#session.usr)} || S <- clean_session_list(Ss), is_integer(S#session.priority)]. @@ -187,10 +189,10 @@ get_user_present_resources(LUser, LServer) -> -spec get_user_ip(binary(), binary(), binary()) -> ip(). get_user_ip(User, Server, Resource) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - LResource = jlib:resourceprep(Resource), - Mod = get_sm_backend(), + LUser = jid:nodeprep(User), + LServer = jid:nameprep(Server), + LResource = jid:resourceprep(Resource), + Mod = get_sm_backend(LServer), case Mod:get_sessions(LUser, LServer, LResource) of [] -> undefined; @@ -202,10 +204,10 @@ get_user_ip(User, Server, Resource) -> -spec get_user_info(binary(), binary(), binary()) -> info() | offline. get_user_info(User, Server, Resource) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - LResource = jlib:resourceprep(Resource), - Mod = get_sm_backend(), + LUser = jid:nodeprep(User), + LServer = jid:nameprep(Server), + LResource = jid:resourceprep(Resource), + Mod = get_sm_backend(LServer), case Mod:get_sessions(LUser, LServer, LResource) of [] -> offline; @@ -225,7 +227,7 @@ set_presence(SID, User, Server, Resource, Priority, set_session(SID, User, Server, Resource, Priority, Info), ejabberd_hooks:run(set_presence_hook, - jlib:nameprep(Server), + jid:nameprep(Server), [User, Server, Resource, Presence]). -spec unset_presence(sid(), binary(), binary(), @@ -236,7 +238,7 @@ unset_presence(SID, User, Server, Resource, Status, set_session(SID, User, Server, Resource, undefined, Info), ejabberd_hooks:run(unset_presence_hook, - jlib:nameprep(Server), + jid:nameprep(Server), [User, Server, Resource, Status]). -spec close_session_unset_presence(sid(), binary(), binary(), @@ -246,16 +248,16 @@ close_session_unset_presence(SID, User, Server, Resource, Status) -> close_session(SID, User, Server, Resource), ejabberd_hooks:run(unset_presence_hook, - jlib:nameprep(Server), + jid:nameprep(Server), [User, Server, Resource, Status]). -spec get_session_pid(binary(), binary(), binary()) -> none | pid(). get_session_pid(User, Server, Resource) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - LResource = jlib:resourceprep(Resource), - Mod = get_sm_backend(), + LUser = jid:nodeprep(User), + LServer = jid:nameprep(Server), + LResource = jid:resourceprep(Resource), + Mod = get_sm_backend(LServer), case Mod:get_sessions(LUser, LServer, LResource) of [#session{sid = {_, Pid}}] -> Pid; _ -> none @@ -264,40 +266,49 @@ get_session_pid(User, Server, Resource) -> -spec dirty_get_sessions_list() -> [ljid()]. dirty_get_sessions_list() -> - Mod = get_sm_backend(), - [S#session.usr || S <- Mod:get_sessions()]. + lists:flatmap( + fun(Mod) -> + [S#session.usr || S <- Mod:get_sessions()] + end, get_sm_backends()). + +-spec dirty_get_my_sessions_list() -> [#session{}]. dirty_get_my_sessions_list() -> - Mod = get_sm_backend(), - [S || S <- Mod:get_sessions(), node(element(2, S#session.sid)) == node()]. + lists:flatmap( + fun(Mod) -> + [S || S <- Mod:get_sessions(), + node(element(2, S#session.sid)) == node()] + end, get_sm_backends()). -spec get_vh_session_list(binary()) -> [ljid()]. get_vh_session_list(Server) -> - LServer = jlib:nameprep(Server), - Mod = get_sm_backend(), + LServer = jid:nameprep(Server), + Mod = get_sm_backend(LServer), [S#session.usr || S <- Mod:get_sessions(LServer)]. -spec get_all_pids() -> [pid()]. get_all_pids() -> - Mod = get_sm_backend(), - [element(2, S#session.sid) || S <- Mod:get_sessions()]. + lists:flatmap( + fun(Mod) -> + [element(2, S#session.sid) || S <- Mod:get_sessions()] + end, get_sm_backends()). + +-spec get_vh_session_number(binary()) -> non_neg_integer(). get_vh_session_number(Server) -> - LServer = jlib:nameprep(Server), - Mod = get_sm_backend(), + LServer = jid:nameprep(Server), + Mod = get_sm_backend(LServer), length(Mod:get_sessions(LServer)). register_iq_handler(Host, XMLNS, Module, Fun) -> - ejabberd_sm ! - {register_iq_handler, Host, XMLNS, Module, Fun}. + ejabberd_sm ! {register_iq_handler, Host, XMLNS, Module, Fun}. -spec register_iq_handler(binary(), binary(), atom(), atom(), list()) -> any(). register_iq_handler(Host, XMLNS, Module, Fun, Opts) -> - ejabberd_sm ! - {register_iq_handler, Host, XMLNS, Module, Fun, Opts}. + ejabberd_sm ! {register_iq_handler, Host, XMLNS, Module, Fun, Opts}. -spec unregister_iq_handler(binary(), binary()) -> any(). @@ -309,16 +320,8 @@ unregister_iq_handler(Host, XMLNS) -> %% gen_server callbacks %%==================================================================== -%%-------------------------------------------------------------------- -%% Function: init(Args) -> {ok, State} | -%% {ok, State, Timeout} | -%% ignore | -%% {stop, Reason} -%% Description: Initiates the server -%%-------------------------------------------------------------------- init([]) -> - Mod = get_sm_backend(), - Mod:init(), + lists:foreach(fun(Mod) -> Mod:init() end, get_sm_backends()), ets:new(sm_iqtable, [named_table]), lists:foreach( fun(Host) -> @@ -329,35 +332,14 @@ init([]) -> ejabberd_hooks:add(remove_user, Host, ejabberd_sm, disconnect_removed_user, 100) end, ?MYHOSTS), - ejabberd_commands:register_commands(commands()), + ejabberd_commands:register_commands(get_commands_spec()), {ok, #state{}}. -%%-------------------------------------------------------------------- -%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} | -%% {reply, Reply, State, Timeout} | -%% {noreply, State} | -%% {noreply, State, Timeout} | -%% {stop, Reason, Reply, State} | -%% {stop, Reason, State} -%% Description: Handling call messages -%%-------------------------------------------------------------------- handle_call(_Request, _From, State) -> Reply = ok, {reply, Reply, State}. -%%-------------------------------------------------------------------- -%% Function: handle_cast(Msg, State) -> {noreply, State} | -%% {noreply, State, Timeout} | -%% {stop, Reason, State} -%% Description: Handling cast messages -%%-------------------------------------------------------------------- handle_cast(_Msg, State) -> {noreply, State}. -%%-------------------------------------------------------------------- -%% Function: handle_info(Info, State) -> {noreply, State} | -%% {noreply, State, Timeout} | -%% {stop, Reason, State} -%% Description: Handling all non call/cast messages -%%-------------------------------------------------------------------- handle_info({route, From, To, Packet}, State) -> case catch do_route(From, To, Packet) of {'EXIT', Reason} -> @@ -387,34 +369,26 @@ handle_info({unregister_iq_handler, Host, XMLNS}, {noreply, State}; handle_info(_Info, State) -> {noreply, State}. -%%-------------------------------------------------------------------- -%% Function: terminate(Reason, State) -> void() -%% Description: This function is called by a gen_server when it is about to -%% terminate. It should be the opposite of Module:init/1 and do any necessary -%% cleaning up. When it returns, the gen_server terminates with Reason. -%% The return value is ignored. -%%-------------------------------------------------------------------- terminate(_Reason, _State) -> - ejabberd_commands:unregister_commands(commands()), + ejabberd_commands:unregister_commands(get_commands_spec()), ok. -%%-------------------------------------------------------------------- -%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState} -%% Description: Convert process state when code is changed -%%-------------------------------------------------------------------- code_change(_OldVsn, State, _Extra) -> {ok, State}. %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- +-spec set_session(sid(), binary(), binary(), binary(), + prio(), info()) -> ok. + set_session(SID, User, Server, Resource, Priority, Info) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - LResource = jlib:resourceprep(Resource), + LUser = jid:nodeprep(User), + LServer = jid:nameprep(Server), + LResource = jid:resourceprep(Resource), US = {LUser, LServer}, USR = {LUser, LServer, LResource}, - Mod = get_sm_backend(), + Mod = get_sm_backend(LServer), Mod:set_session(#session{sid = SID, usr = USR, us = US, priority = Priority, info = Info}). @@ -425,13 +399,13 @@ do_route(From, To, {broadcast, _} = Packet) -> <<"">> -> lists:foreach(fun(R) -> do_route(From, - jlib:jid_replace_resource(To, R), + jid:replace_resource(To, R), Packet) end, get_user_resources(To#jid.user, To#jid.server)); _ -> - {U, S, R} = jlib:jid_tolower(To), - Mod = get_sm_backend(), + {U, S, R} = jid:tolower(To), + Mod = get_sm_backend(S), case Mod:get_sessions(U, S, R) of [] -> ?DEBUG("packet dropped~n", []); @@ -453,10 +427,10 @@ do_route(From, To, #xmlel{} = Packet) -> <<"">> -> case Name of <<"presence">> -> - {Pass, _Subsc} = case xml:get_attr_s(<<"type">>, Attrs) + {Pass, _Subsc} = case fxml:get_attr_s(<<"type">>, Attrs) of <<"subscribe">> -> - Reason = xml:get_path_s(Packet, + Reason = fxml:get_path_s(Packet, [{elem, <<"status">>}, cdata]), @@ -509,7 +483,7 @@ do_route(From, To, #xmlel{} = Packet) -> PResources = get_user_present_resources(LUser, LServer), lists:foreach(fun ({_, R}) -> do_route(From, - jlib:jid_replace_resource(To, + jid:replace_resource(To, R), Packet) end, @@ -517,7 +491,7 @@ do_route(From, To, #xmlel{} = Packet) -> true -> ok end; <<"message">> -> - case xml:get_attr_s(<<"type">>, Attrs) of + case fxml:get_attr_s(<<"type">>, Attrs) of <<"chat">> -> route_message(From, To, Packet, chat); <<"headline">> -> route_message(From, To, Packet, headline); <<"error">> -> ok; @@ -532,13 +506,15 @@ do_route(From, To, #xmlel{} = Packet) -> _ -> ok end; _ -> - Mod = get_sm_backend(), + Mod = get_sm_backend(LServer), case Mod:get_sessions(LUser, LServer, LResource) of [] -> case Name of <<"message">> -> - case xml:get_attr_s(<<"type">>, Attrs) of + case fxml:get_attr_s(<<"type">>, Attrs) of <<"chat">> -> route_message(From, To, Packet, chat); + <<"normal">> -> route_message(From, To, Packet, normal); + <<"">> -> route_message(From, To, Packet, normal); <<"error">> -> ok; _ -> Err = jlib:make_error_reply(Packet, @@ -546,7 +522,7 @@ do_route(From, To, #xmlel{} = Packet) -> ejabberd_router:route(To, From, Err) end; <<"iq">> -> - case xml:get_attr_s(<<"type">>, Attrs) of + case fxml:get_attr_s(<<"type">>, Attrs) of <<"error">> -> ok; <<"result">> -> ok; _ -> @@ -596,8 +572,8 @@ route_message(From, To, Packet, Type) -> when is_integer(Priority), Priority >= 0 -> lists:foreach(fun ({P, R}) when P == Priority; (P >= 0) and (Type == headline) -> - LResource = jlib:resourceprep(R), - Mod = get_sm_backend(), + LResource = jid:resourceprep(R), + Mod = get_sm_backend(LServer), case Mod:get_sessions(LUser, LServer, LResource) of [] -> @@ -652,9 +628,9 @@ clean_session_list([S1, S2 | Rest], Res) -> %% On new session, check if some existing connections need to be replace check_for_sessions_to_replace(User, Server, Resource) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - LResource = jlib:resourceprep(Resource), + LUser = jid:nodeprep(User), + LServer = jid:nameprep(Server), + LResource = jid:resourceprep(Resource), check_existing_resources(LUser, LServer, LResource), check_max_sessions(LUser, LServer). @@ -676,14 +652,14 @@ is_existing_resource(LUser, LServer, LResource) -> [] /= get_resource_sessions(LUser, LServer, LResource). get_resource_sessions(User, Server, Resource) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - LResource = jlib:resourceprep(Resource), - Mod = get_sm_backend(), + LUser = jid:nodeprep(User), + LServer = jid:nameprep(Server), + LResource = jid:resourceprep(Resource), + Mod = get_sm_backend(LServer), [S#session.sid || S <- Mod:get_sessions(LUser, LServer, LResource)]. check_max_sessions(LUser, LServer) -> - Mod = get_sm_backend(), + Mod = get_sm_backend(LServer), SIDs = [S#session.sid || S <- Mod:get_sessions(LUser, LServer)], MaxSessions = get_max_user_sessions(LUser, LServer), if length(SIDs) =< MaxSessions -> ok; @@ -696,7 +672,7 @@ check_max_sessions(LUser, LServer) -> %% Defaults to infinity get_max_user_sessions(LUser, Host) -> case acl:match_rule(Host, max_user_sessions, - jlib:make_jid(LUser, Host, <<"">>)) + jid:make(LUser, Host, <<"">>)) of Max when is_integer(Max) -> Max; infinity -> infinity; @@ -735,17 +711,17 @@ process_iq(From, To, Packet) -> -spec force_update_presence({binary(), binary()}) -> any(). force_update_presence({LUser, LServer}) -> - Mod = get_sm_backend(), + Mod = get_sm_backend(LServer), Ss = Mod:get_sessions(LUser, LServer), lists:foreach(fun (#session{sid = {_, Pid}}) -> - Pid ! {force_update_presence, LUser} + Pid ! {force_update_presence, LUser, LServer} end, Ss). --spec get_sm_backend() -> module(). +-spec get_sm_backend(binary()) -> module(). -get_sm_backend() -> - DBType = ejabberd_config:get_option(sm_db_type, +get_sm_backend(Host) -> + DBType = ejabberd_config:get_option({sm_db_type, Host}, fun(mnesia) -> mnesia; (internal) -> mnesia; (odbc) -> odbc; @@ -753,25 +729,41 @@ get_sm_backend() -> end, mnesia), list_to_atom("ejabberd_sm_" ++ atom_to_list(DBType)). +-spec get_sm_backends() -> [module()]. + +get_sm_backends() -> + lists:usort([get_sm_backend(Host) || Host <- ?MYHOSTS]). + +-spec get_vh_by_backend(module()) -> [binary()]. + +get_vh_by_backend(Mod) -> + lists:filter( + fun(Host) -> + get_sm_backend(Host) == Mod + end, ?MYHOSTS). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% ejabberd commands -commands() -> +get_commands_spec() -> [#ejabberd_commands{name = connected_users, tags = [session], desc = "List all established sessions", + policy = admin, module = ?MODULE, function = connected_users, args = [], result = {connected_users, {list, {sessions, string}}}}, #ejabberd_commands{name = connected_users_number, tags = [session, stats], desc = "Get the number of established sessions", + policy = admin, module = ?MODULE, function = connected_users_number, args = [], result = {num_sessions, integer}}, #ejabberd_commands{name = user_resources, tags = [session], desc = "List user's connected resources", + policy = user, module = ?MODULE, function = user_resources, - args = [{user, binary}, {host, binary}], + args = [], result = {resources, {list, {resource, string}}}}, #ejabberd_commands{name = kick_user, tags = [session], @@ -803,3 +795,11 @@ kick_user(User, Server) -> PID ! kick end, Resources), length(Resources). + +opt_type(sm_db_type) -> + fun (mnesia) -> mnesia; + (internal) -> mnesia; + (odbc) -> odbc; + (redis) -> redis + end; +opt_type(_) -> [sm_db_type]. |