]> granicus.if.org Git - ejabberd/commitdiff
Preserve PID for offline sessions
authorHolger Weiss <holger@zedat.fu-berlin.de>
Fri, 22 Jul 2016 23:08:05 +0000 (01:08 +0200)
committerHolger Weiss <holger@zedat.fu-berlin.de>
Fri, 22 Jul 2016 23:08:05 +0000 (01:08 +0200)
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.

include/ejabberd_sm.hrl
src/ejabberd_sm.erl
src/mod_admin_extra.erl
src/mod_configure.erl

index 38298d66aa3ad1c940699e55a4494b7023006027..f86ab1c15fab39a72fcae812d722c1828e1c2ab6 100644 (file)
@@ -1,9 +1,9 @@
 -ifndef(EJABBERD_SM_HRL).
 -define(EJABBERD_SM_HRL, true).
 
--record(session, {sid, usr, us, priority, info}).
+-record(session, {sid, usr, us, priority, info = []}).
 -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 info() :: [{conn, atom()} | {ip, ip()} | {node, atom()}
                  | {oor, boolean()} | {auth_module, atom()}
index 8d94bc6aa23345bfb2ceca171cfc7dff258a6ff4..16e0f9114fb577abb1a826403ba48811425d8616 100644 (file)
@@ -270,25 +270,28 @@ get_session_pid(User, Server, Resource) ->
 
 -spec set_offline_info(sid(), binary(), binary(), binary(), info()) -> ok.
 
-set_offline_info({Time, _Pid}, User, Server, Resource, Info) ->
-    SID = {Time, undefined},
+set_offline_info(SID, User, Server, Resource, Info) ->
     LUser = jid:nodeprep(User),
     LServer = jid:nameprep(Server),
     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(),
                        binary()) -> none | info().
 
 get_offline_info(Time, User, Server, Resource) ->
-    SID = {Time, undefined},
     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 = SID, info = Info}] ->
-           Info;
+       [#session{sid = {Time, _}, info = Info}] ->
+           case proplists:get_bool(offline, Info) of
+               true ->
+                   Info;
+               false ->
+                   none
+           end;
        _ ->
            none
     end.
@@ -425,11 +428,12 @@ set_session(SID, User, Server, Resource, Priority, Info) ->
 -spec online([#session{}]) -> [#session{}].
 
 online(Sessions) ->
-    lists:filter(fun(#session{sid = {_, undefined}}) ->
-                        false;
-                   (_) ->
-                        true
-                end, Sessions).
+    lists:filter(fun is_online/1, Sessions).
+
+-spec is_online(#session{}) -> boolean().
+
+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_existing_resources(LUser, LServer, LResource) ->
-    SIDs = get_resource_sessions(LUser, LServer, LResource),
-    if SIDs == [] -> ok;
+    Mod = get_sm_backend(LServer),
+    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 ->
+          SIDs = [SID || #session{sid = SID} <- OnlineSs],
           MaxSID = lists:max(SIDs),
-          lists:foreach(fun ({_, undefined} = S) ->
-                                Mod = get_sm_backend(LServer),
-                                Mod:delete_session(LUser, LServer, LResource,
-                                                   S);
-                            ({_, Pid} = S) when S /= MaxSID ->
+          lists:foreach(fun ({_, Pid} = S) when S /= MaxSID ->
                                 Pid ! replaced;
                             (_) -> ok
                         end,
index 8f6724281030306f1f6ca8a943bce08282ee0aff..2ad1cc28e364e33c8a696596f1f61641654f5669 100644 (file)
@@ -863,12 +863,15 @@ connected_users_vhost(Host) ->
 
 %% Code copied from ejabberd_sm.erl and customized
 dirty_get_sessions_list2() ->
-    mnesia:dirty_select(
-      session,
-      [{#session{usr = '$1', sid = {'$2', '$3'}, priority = '$4', info = '$5',
-                _ = '_'},
-       [{is_pid, '$3'}],
-       [['$1', {{'$2', '$3'}}, '$4', '$5']]}]).
+    Ss = mnesia:dirty_select(
+          session,
+          [{#session{usr = '$1', sid = '$2', priority = '$3', info = '$4',
+                     _ = '_'},
+            [],
+            [['$1', '$2', '$3', '$4']]}]),
+    lists:filter(fun([_USR, _SID, _Priority, Info]) ->
+                        not proplists:get_bool(offline, Info)
+                end, Ss).
 
 %% Make string more print-friendly
 stringize(String) ->
@@ -903,8 +906,8 @@ user_sessions_info(User, Host) ->
                   {'EXIT', _Reason} ->
                       [];
                   Ss ->
-                      lists:filter(fun(#session{sid = {_, Pid}}) ->
-                                           is_pid(Pid)
+                      lists:filter(fun(#session{info = Info}) ->
+                                           not proplists:get_bool(offline, Info)
                                    end, Ss)
               end,
     lists:map(
index 97c94484276b6a59632d90e0cd8231b85474a72a..d0e0166a49c56cfd07bd6ba159b5b8790cf11689 100644 (file)
@@ -1917,21 +1917,29 @@ set_form(From, Host, ?NS_ADMINL(<<"end-user-session">>),
     Xmlelement = ?SERRT_POLICY_VIOLATION(Lang, <<"has been kicked">>),
     case JID#jid.lresource of
       <<>> ->
-         SIDs = mnesia:dirty_select(session,
-                                    [{#session{sid = {'$1', '$2'},
-                                               usr = {LUser, LServer, '_'},
-                                               _ = '_'},
-                                      [{is_pid, '$2'}],
-                                      [{{'$1', '$2'}}]}]),
-         [Pid ! {kick, kicked_by_admin, Xmlelement} || {_, Pid} <- SIDs];
+         SIs = mnesia:dirty_select(session,
+                                   [{#session{usr = {LUser, LServer, '_'},
+                                              sid = '$1',
+                                              info = '$2',
+                                              _ = '_'},
+                                     [], [{{'$1', '$2'}}]}]),
+         Pids = [P || {{_, P}, Info} <- SIs,
+                      not proplists:get_bool(offline, Info)],
+         lists:foreach(fun(Pid) ->
+                               Pid ! {kick, kicked_by_admin, Xmlelement}
+                       end, Pids);
       R ->
-         [{_, Pid}] = mnesia:dirty_select(session,
-                                          [{#session{sid = {'$1', '$2'},
-                                                     usr = {LUser, LServer, R},
-                                                     _ = '_'},
-                                            [{is_pid, '$2'}],
-                                            [{{'$1', '$2'}}]}]),
-         Pid ! {kick, kicked_by_admin, Xmlelement}
+         [{{_, Pid}, Info}] = mnesia:dirty_select(
+                                session,
+                                [{#session{usr = {LUser, LServer, R},
+                                           sid = '$1',
+                                           info = '$2',
+                                           _ = '_'},
+                                  [], [{{'$1', '$2'}}]}]),
+         case proplists:get_bool(offline, Info) of
+           true -> ok;
+           false -> Pid ! {kick, kicked_by_admin, Xmlelement}
+         end
     end,
     {result, []};
 set_form(From, Host,