aboutsummaryrefslogtreecommitdiff
path: root/src/ejabberd_sm.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/ejabberd_sm.erl')
-rw-r--r--src/ejabberd_sm.erl252
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].