diff options
author | Holger Weiss <holger@zedat.fu-berlin.de> | 2016-05-24 22:20:58 +0200 |
---|---|---|
committer | Holger Weiss <holger@zedat.fu-berlin.de> | 2016-05-24 22:20:58 +0200 |
commit | 30e814dd4bf414314ff611452362582419f3f05d (patch) | |
tree | 3cbae488f706f69c68cf143350abfdef78957fc8 /src | |
parent | mod_mam_mnesia: Clarify error message (diff) |
XEP-0198: Add 'h' attribute to <failed/> element
If a resume request is rejected because the session timed out, indicate
the number of handled stanzas as per version 1.5 of XEP-0198.
Diffstat (limited to 'src')
-rw-r--r-- | src/ejabberd_c2s.erl | 51 | ||||
-rw-r--r-- | src/ejabberd_sm.erl | 78 |
2 files changed, 99 insertions, 30 deletions
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 5e30d5ffc..188368318 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -166,27 +166,32 @@ (Xmlns == ?NS_STREAM_MGMT_2) or (Xmlns == ?NS_STREAM_MGMT_3)). --define(MGMT_FAILED(Condition, Xmlns), +-define(MGMT_FAILED(Condition, Attrs), #xmlel{name = <<"failed">>, - attrs = [{<<"xmlns">>, Xmlns}], + attrs = Attrs, children = [#xmlel{name = Condition, attrs = [{<<"xmlns">>, ?NS_STANZAS}], children = []}]}). -define(MGMT_BAD_REQUEST(Xmlns), - ?MGMT_FAILED(<<"bad-request">>, Xmlns)). - --define(MGMT_ITEM_NOT_FOUND(Xmlns), - ?MGMT_FAILED(<<"item-not-found">>, Xmlns)). + ?MGMT_FAILED(<<"bad-request">>, [{<<"xmlns">>, Xmlns}])). -define(MGMT_SERVICE_UNAVAILABLE(Xmlns), - ?MGMT_FAILED(<<"service-unavailable">>, Xmlns)). + ?MGMT_FAILED(<<"service-unavailable">>, [{<<"xmlns">>, Xmlns}])). -define(MGMT_UNEXPECTED_REQUEST(Xmlns), - ?MGMT_FAILED(<<"unexpected-request">>, Xmlns)). + ?MGMT_FAILED(<<"unexpected-request">>, [{<<"xmlns">>, Xmlns}])). -define(MGMT_UNSUPPORTED_VERSION(Xmlns), - ?MGMT_FAILED(<<"unsupported-version">>, Xmlns)). + ?MGMT_FAILED(<<"unsupported-version">>, [{<<"xmlns">>, Xmlns}])). + +-define(MGMT_ITEM_NOT_FOUND(Xmlns), + ?MGMT_FAILED(<<"item-not-found">>, [{<<"xmlns">>, Xmlns}])). + +-define(MGMT_ITEM_NOT_FOUND_H(Xmlns, NumStanzasIn), + ?MGMT_FAILED(<<"item-not-found">>, + [{<<"xmlns">>, Xmlns}, + {<<"h">>, jlib:integer_to_binary(NumStanzasIn)}])). %%%---------------------------------------------------------------------- %%% API @@ -1280,7 +1285,7 @@ wait_for_resume({xmlstreamelement, _El} = Event, StateData) -> wait_for_resume(timeout, StateData) -> ?DEBUG("Timed out waiting for resumption of stream for ~s", [jid:to_string(StateData#state.jid)]), - {stop, normal, StateData}; + {stop, normal, StateData#state{mgmt_state = timeout}}; wait_for_resume(Event, StateData) -> ?DEBUG("Ignoring event while waiting for resumption: ~p", [Event]), fsm_next_state(wait_for_resume, StateData). @@ -1791,6 +1796,18 @@ terminate(_Reason, StateName, StateData) -> presence_broadcast(StateData, From, StateData#state.pres_a, Packet) end, + case StateData#state.mgmt_state of + timeout -> + Info = [{num_stanzas_in, + StateData#state.mgmt_stanzas_in}], + ejabberd_sm:set_offline_info(StateData#state.sid, + StateData#state.user, + StateData#state.server, + StateData#state.resource, + Info); + _ -> + ok + end, handle_unacked_stanzas(StateData) end, bounce_messages(); @@ -2726,6 +2743,8 @@ handle_resume(StateData, Attrs) -> case inherit_session_state(StateData, PrevID) of {ok, InheritedState} -> {ok, InheritedState, H}; + {error, Err, InH} -> + {error, ?MGMT_ITEM_NOT_FOUND_H(Xmlns, InH), Err}; {error, Err} -> {error, ?MGMT_ITEM_NOT_FOUND(Xmlns), Err} end; @@ -2965,7 +2984,17 @@ inherit_session_state(#state{user = U, server = S} = StateData, ResumeID) -> {term, {R, Time}} -> case ejabberd_sm:get_session_pid(U, S, R) of none -> - {error, <<"Previous session PID not found">>}; + case ejabberd_sm:get_offline_info(Time, U, S, R) of + none -> + {error, <<"Previous session PID not found">>}; + Info -> + case proplists:get_value(num_stanzas_in, Info) of + undefined -> + {error, <<"Previous session timed out">>}; + H -> + {error, <<"Previous session timed out">>, H} + end + end; OldPID -> OldSID = {Time, OldPID}, case catch resume_session(OldSID) of diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 5ee652cce..8d94bc6aa 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -47,6 +47,8 @@ set_presence/7, unset_presence/6, close_session_unset_presence/5, + set_offline_info/5, + get_offline_info/4, dirty_get_sessions_list/0, dirty_get_my_sessions_list/0, get_vh_session_list/1, @@ -178,14 +180,14 @@ get_user_resources(User, Server) -> LUser = jid:nodeprep(User), LServer = jid:nameprep(Server), Mod = get_sm_backend(LServer), - Ss = Mod:get_sessions(LUser, LServer), + Ss = online(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(LServer), - Ss = Mod:get_sessions(LUser, LServer), + Ss = online(Mod:get_sessions(LUser, LServer)), [{S#session.priority, element(3, S#session.usr)} || S <- clean_session_list(Ss), is_integer(S#session.priority)]. @@ -196,7 +198,7 @@ get_user_ip(User, Server, Resource) -> LServer = jid:nameprep(Server), LResource = jid:resourceprep(Resource), Mod = get_sm_backend(LServer), - case Mod:get_sessions(LUser, LServer, LResource) of + case online(Mod:get_sessions(LUser, LServer, LResource)) of [] -> undefined; Ss -> @@ -211,7 +213,7 @@ get_user_info(User, Server, Resource) -> LServer = jid:nameprep(Server), LResource = jid:resourceprep(Resource), Mod = get_sm_backend(LServer), - case Mod:get_sessions(LUser, LServer, LResource) of + case online(Mod:get_sessions(LUser, LServer, LResource)) of [] -> offline; Ss -> @@ -261,17 +263,42 @@ get_session_pid(User, Server, Resource) -> LServer = jid:nameprep(Server), LResource = jid:resourceprep(Resource), Mod = get_sm_backend(LServer), - case Mod:get_sessions(LUser, LServer, LResource) of + case online(Mod:get_sessions(LUser, LServer, LResource)) of [#session{sid = {_, Pid}}] -> Pid; _ -> none end. +-spec set_offline_info(sid(), binary(), binary(), binary(), info()) -> ok. + +set_offline_info({Time, _Pid}, User, Server, Resource, Info) -> + SID = {Time, undefined}, + LUser = jid:nodeprep(User), + LServer = jid:nameprep(Server), + LResource = jid:resourceprep(Resource), + set_session(SID, LUser, LServer, LResource, undefined, 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; + _ -> + none + end. + -spec dirty_get_sessions_list() -> [ljid()]. dirty_get_sessions_list() -> lists:flatmap( fun(Mod) -> - [S#session.usr || S <- Mod:get_sessions()] + [S#session.usr || S <- online(Mod:get_sessions())] end, get_sm_backends()). -spec dirty_get_my_sessions_list() -> [#session{}]. @@ -279,7 +306,7 @@ dirty_get_sessions_list() -> dirty_get_my_sessions_list() -> lists:flatmap( fun(Mod) -> - [S || S <- Mod:get_sessions(), + [S || S <- online(Mod:get_sessions()), node(element(2, S#session.sid)) == node()] end, get_sm_backends()). @@ -288,14 +315,14 @@ dirty_get_my_sessions_list() -> get_vh_session_list(Server) -> LServer = jid:nameprep(Server), Mod = get_sm_backend(LServer), - [S#session.usr || S <- Mod:get_sessions(LServer)]. + [S#session.usr || S <- online(Mod:get_sessions(LServer))]. -spec get_all_pids() -> [pid()]. get_all_pids() -> lists:flatmap( fun(Mod) -> - [element(2, S#session.sid) || S <- Mod:get_sessions()] + [element(2, S#session.sid) || S <- online(Mod:get_sessions())] end, get_sm_backends()). -spec get_vh_session_number(binary()) -> non_neg_integer(). @@ -303,7 +330,7 @@ get_all_pids() -> get_vh_session_number(Server) -> LServer = jid:nameprep(Server), Mod = get_sm_backend(LServer), - length(Mod:get_sessions(LServer)). + length(online(Mod:get_sessions(LServer))). register_iq_handler(Host, XMLNS, Module, Fun) -> ejabberd_sm ! {register_iq_handler, Host, XMLNS, Module, Fun}. @@ -395,6 +422,15 @@ set_session(SID, User, Server, Resource, Priority, Info) -> Mod:set_session(#session{sid = SID, usr = USR, us = US, priority = Priority, info = Info}). +-spec online([#session{}]) -> [#session{}]. + +online(Sessions) -> + lists:filter(fun(#session{sid = {_, undefined}}) -> + false; + (_) -> + true + end, Sessions). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% do_route(From, To, {broadcast, _} = Packet) -> @@ -409,7 +445,7 @@ do_route(From, To, {broadcast, _} = Packet) -> _ -> {U, S, R} = jid:tolower(To), Mod = get_sm_backend(S), - case Mod:get_sessions(U, S, R) of + case online(Mod:get_sessions(U, S, R)) of [] -> ?DEBUG("packet dropped~n", []); Ss -> @@ -511,8 +547,8 @@ do_route(From, To, #xmlel{} = Packet) -> _ -> ok end; _ -> - Mod = get_sm_backend(LServer), - case Mod:get_sessions(LUser, LServer, LResource) of + Mod = get_sm_backend(LServer), + case online(Mod:get_sessions(LUser, LServer, LResource)) of [] -> case Name of <<"message">> -> @@ -584,8 +620,8 @@ route_message(From, To, Packet, Type) -> (P >= 0) and (Type == headline) -> LResource = jid:resourceprep(R), Mod = get_sm_backend(LServer), - case Mod:get_sessions(LUser, LServer, - LResource) of + case online(Mod:get_sessions(LUser, LServer, + LResource)) of [] -> ok; % Race condition Ss -> @@ -646,7 +682,11 @@ check_existing_resources(LUser, LServer, LResource) -> if SIDs == [] -> ok; true -> MaxSID = lists:max(SIDs), - lists:foreach(fun ({_, Pid} = S) when S /= MaxSID -> + lists:foreach(fun ({_, undefined} = S) -> + Mod = get_sm_backend(LServer), + Mod:delete_session(LUser, LServer, LResource, + S); + ({_, Pid} = S) when S /= MaxSID -> Pid ! replaced; (_) -> ok end, @@ -663,11 +703,11 @@ get_resource_sessions(User, Server, Resource) -> LServer = jid:nameprep(Server), LResource = jid:resourceprep(Resource), Mod = get_sm_backend(LServer), - [S#session.sid || S <- Mod:get_sessions(LUser, LServer, LResource)]. + [S#session.sid || S <- online(Mod:get_sessions(LUser, LServer, LResource))]. check_max_sessions(LUser, LServer) -> Mod = get_sm_backend(LServer), - SIDs = [S#session.sid || S <- Mod:get_sessions(LUser, LServer)], + SIDs = [S#session.sid || S <- online(Mod:get_sessions(LUser, LServer))], MaxSessions = get_max_user_sessions(LUser, LServer), if length(SIDs) =< MaxSessions -> ok; true -> {_, Pid} = lists:min(SIDs), Pid ! replaced @@ -721,7 +761,7 @@ process_iq(From, To, Packet) -> force_update_presence({LUser, LServer}) -> Mod = get_sm_backend(LServer), - Ss = Mod:get_sessions(LUser, LServer), + Ss = online(Mod:get_sessions(LUser, LServer)), lists:foreach(fun (#session{sid = {_, Pid}}) -> Pid ! {force_update_presence, LUser, LServer} end, |