25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-11-28 16:34:13 +01:00

Preserve PID for offline sessions

Don't set the PID to 'undefined' when a session goes offline, as this
looses the information which node created the session table entry.

Fixes #1196.
This commit is contained in:
Holger Weiss 2016-07-23 01:08:05 +02:00
parent 4332dddbc4
commit 814b80c644
4 changed files with 59 additions and 42 deletions

View File

@ -1,9 +1,9 @@
-ifndef(EJABBERD_SM_HRL). -ifndef(EJABBERD_SM_HRL).
-define(EJABBERD_SM_HRL, true). -define(EJABBERD_SM_HRL, true).
-record(session, {sid, usr, us, priority, info}). -record(session, {sid, usr, us, priority, info = []}).
-record(session_counter, {vhost, count}). -record(session_counter, {vhost, count}).
-type sid() :: {erlang:timestamp(), pid()} | {erlang:timestamp(), undefined}. -type sid() :: {erlang:timestamp(), pid()}.
-type ip() :: {inet:ip_address(), inet:port_number()} | undefined. -type ip() :: {inet:ip_address(), inet:port_number()} | undefined.
-type info() :: [{conn, atom()} | {ip, ip()} | {node, atom()} -type info() :: [{conn, atom()} | {ip, ip()} | {node, atom()}
| {oor, boolean()} | {auth_module, atom()} | {oor, boolean()} | {auth_module, atom()}

View File

@ -270,25 +270,28 @@ get_session_pid(User, Server, Resource) ->
-spec set_offline_info(sid(), binary(), binary(), binary(), info()) -> ok. -spec set_offline_info(sid(), binary(), binary(), binary(), info()) -> ok.
set_offline_info({Time, _Pid}, User, Server, Resource, Info) -> set_offline_info(SID, User, Server, Resource, Info) ->
SID = {Time, undefined},
LUser = jid:nodeprep(User), LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server), LServer = jid:nameprep(Server),
LResource = jid:resourceprep(Resource), LResource = jid:resourceprep(Resource),
set_session(SID, LUser, LServer, LResource, undefined, Info). set_session(SID, LUser, LServer, LResource, undefined, [offline | Info]).
-spec get_offline_info(erlang:timestamp(), binary(), binary(), -spec get_offline_info(erlang:timestamp(), binary(), binary(),
binary()) -> none | info(). binary()) -> none | info().
get_offline_info(Time, User, Server, Resource) -> get_offline_info(Time, User, Server, Resource) ->
SID = {Time, undefined},
LUser = jid:nodeprep(User), LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server), LServer = jid:nameprep(Server),
LResource = jid:resourceprep(Resource), LResource = jid:resourceprep(Resource),
Mod = get_sm_backend(LServer), Mod = get_sm_backend(LServer),
case Mod:get_sessions(LUser, LServer, LResource) of case Mod:get_sessions(LUser, LServer, LResource) of
[#session{sid = SID, info = Info}] -> [#session{sid = {Time, _}, info = Info}] ->
Info; case proplists:get_bool(offline, Info) of
true ->
Info;
false ->
none
end;
_ -> _ ->
none none
end. end.
@ -425,11 +428,12 @@ set_session(SID, User, Server, Resource, Priority, Info) ->
-spec online([#session{}]) -> [#session{}]. -spec online([#session{}]) -> [#session{}].
online(Sessions) -> online(Sessions) ->
lists:filter(fun(#session{sid = {_, undefined}}) -> lists:filter(fun is_online/1, Sessions).
false;
(_) -> -spec is_online(#session{}) -> boolean().
true
end, Sessions). is_online(#session{info = Info}) ->
not proplists:get_bool(offline, Info).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -678,15 +682,17 @@ check_for_sessions_to_replace(User, Server, Resource) ->
check_max_sessions(LUser, LServer). check_max_sessions(LUser, LServer).
check_existing_resources(LUser, LServer, LResource) -> check_existing_resources(LUser, LServer, LResource) ->
SIDs = get_resource_sessions(LUser, LServer, LResource), Mod = get_sm_backend(LServer),
if SIDs == [] -> ok; Ss = Mod:get_sessions(LUser, LServer, LResource),
{OnlineSs, OfflineSs} = lists:partition(fun is_online/1, Ss),
lists:foreach(fun(#session{sid = S}) ->
Mod:delete_session(LUser, LServer, LResource, S)
end, OfflineSs),
if OnlineSs == [] -> ok;
true -> true ->
SIDs = [SID || #session{sid = SID} <- OnlineSs],
MaxSID = lists:max(SIDs), MaxSID = lists:max(SIDs),
lists:foreach(fun ({_, undefined} = S) -> lists:foreach(fun ({_, Pid} = S) when S /= MaxSID ->
Mod = get_sm_backend(LServer),
Mod:delete_session(LUser, LServer, LResource,
S);
({_, Pid} = S) when S /= MaxSID ->
Pid ! replaced; Pid ! replaced;
(_) -> ok (_) -> ok
end, end,

View File

@ -863,12 +863,15 @@ connected_users_vhost(Host) ->
%% Code copied from ejabberd_sm.erl and customized %% Code copied from ejabberd_sm.erl and customized
dirty_get_sessions_list2() -> dirty_get_sessions_list2() ->
mnesia:dirty_select( Ss = mnesia:dirty_select(
session, session,
[{#session{usr = '$1', sid = {'$2', '$3'}, priority = '$4', info = '$5', [{#session{usr = '$1', sid = '$2', priority = '$3', info = '$4',
_ = '_'}, _ = '_'},
[{is_pid, '$3'}], [],
[['$1', {{'$2', '$3'}}, '$4', '$5']]}]). [['$1', '$2', '$3', '$4']]}]),
lists:filter(fun([_USR, _SID, _Priority, Info]) ->
not proplists:get_bool(offline, Info)
end, Ss).
%% Make string more print-friendly %% Make string more print-friendly
stringize(String) -> stringize(String) ->
@ -903,8 +906,8 @@ user_sessions_info(User, Host) ->
{'EXIT', _Reason} -> {'EXIT', _Reason} ->
[]; [];
Ss -> Ss ->
lists:filter(fun(#session{sid = {_, Pid}}) -> lists:filter(fun(#session{info = Info}) ->
is_pid(Pid) not proplists:get_bool(offline, Info)
end, Ss) end, Ss)
end, end,
lists:map( lists:map(

View File

@ -1917,21 +1917,29 @@ set_form(From, Host, ?NS_ADMINL(<<"end-user-session">>),
Xmlelement = ?SERRT_POLICY_VIOLATION(Lang, <<"has been kicked">>), Xmlelement = ?SERRT_POLICY_VIOLATION(Lang, <<"has been kicked">>),
case JID#jid.lresource of case JID#jid.lresource of
<<>> -> <<>> ->
SIDs = mnesia:dirty_select(session, SIs = mnesia:dirty_select(session,
[{#session{sid = {'$1', '$2'}, [{#session{usr = {LUser, LServer, '_'},
usr = {LUser, LServer, '_'}, sid = '$1',
_ = '_'}, info = '$2',
[{is_pid, '$2'}], _ = '_'},
[{{'$1', '$2'}}]}]), [], [{{'$1', '$2'}}]}]),
[Pid ! {kick, kicked_by_admin, Xmlelement} || {_, Pid} <- SIDs]; Pids = [P || {{_, P}, Info} <- SIs,
not proplists:get_bool(offline, Info)],
lists:foreach(fun(Pid) ->
Pid ! {kick, kicked_by_admin, Xmlelement}
end, Pids);
R -> R ->
[{_, Pid}] = mnesia:dirty_select(session, [{{_, Pid}, Info}] = mnesia:dirty_select(
[{#session{sid = {'$1', '$2'}, session,
usr = {LUser, LServer, R}, [{#session{usr = {LUser, LServer, R},
_ = '_'}, sid = '$1',
[{is_pid, '$2'}], info = '$2',
[{{'$1', '$2'}}]}]), _ = '_'},
Pid ! {kick, kicked_by_admin, Xmlelement} [], [{{'$1', '$2'}}]}]),
case proplists:get_bool(offline, Info) of
true -> ok;
false -> Pid ! {kick, kicked_by_admin, Xmlelement}
end
end, end,
{result, []}; {result, []};
set_form(From, Host, set_form(From, Host,