From 9c7e91a1e9c62c594417144f5ea8a382765383f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Tue, 21 Nov 2023 13:55:40 +0100 Subject: [PATCH] Update xmpp and make opening bind2 session close other sessions with same tag --- mix.exs | 2 +- rebar.config | 2 +- src/ejabberd_c2s.erl | 7 ++++++- src/ejabberd_sm.erl | 44 ++++++++++++++++++++++++++++++++--------- src/mod_stream_mgmt.erl | 6 +++--- 5 files changed, 46 insertions(+), 15 deletions(-) diff --git a/mix.exs b/mix.exs index ea769a51f..0f6b059f6 100644 --- a/mix.exs +++ b/mix.exs @@ -114,7 +114,7 @@ defmodule Ejabberd.MixProject do {:p1_utils, "~> 1.0"}, {:pkix, "~> 1.0"}, {:stringprep, ">= 1.0.26"}, - {:xmpp, git: "https://github.com/processone/xmpp.git", ref: "add2a3dd773afa2dcf5cd5db66fb6ad90669a9d9", override: true}, + {:xmpp, git: "https://github.com/processone/xmpp.git", ref: "dcb701e6800d827f8806c0d049aaf103cd724e2b", override: true}, {:yconf, "~> 1.0"}] ++ cond_deps() end diff --git a/rebar.config b/rebar.config index 18ed4cb93..cbbf1d927 100644 --- a/rebar.config +++ b/rebar.config @@ -77,7 +77,7 @@ {stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.29"}}}, {if_var_true, stun, {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.2.10"}}}}, - {xmpp, ".*", {git, "https://github.com/processone/xmpp", "add2a3dd773afa2dcf5cd5db66fb6ad90669a9d9"}}, + {xmpp, ".*", {git, "https://github.com/processone/xmpp", "dcb701e6800d827f8806c0d049aaf103cd724e2b"}}, {yconf, ".*", {git, "https://github.com/processone/yconf", {tag, "1.0.15"}}} ]}. diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 5a032205d..32ac79305 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -215,7 +215,12 @@ open_session(#{user := U, server := S, resource := R, Pres -> get_priority_from_presence(Pres) end, Info = [{ip, IP}, {conn, Conn}, {auth_module, AuthModule}], - ejabberd_sm:open_session(SID, U, S, R, Prio, Info), + case State of + #{bind2_tag := Tag} -> + ejabberd_sm:open_session(SID, U, S, R, Prio, Info, Tag); + _ -> + ejabberd_sm:open_session(SID, U, S, R, Prio, Info) + end, xmpp_stream_in:establish(State2). %%%=================================================================== diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index c9317b81c..7222a91f5 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -39,6 +39,7 @@ route/2, open_session/5, open_session/6, + open_session/7, close_session/4, check_in_subscription/2, bounce_offline_message/1, @@ -147,15 +148,21 @@ route(Packet) -> ok end. --spec open_session(sid(), binary(), binary(), binary(), prio(), info()) -> ok. -open_session(SID, User, Server, Resource, Priority, Info) -> +-spec open_session(sid(), binary(), binary(), binary(), prio(), info(), binary() | undefined) -> ok. + +open_session(SID, User, Server, Resource, Priority, Info, Bind2Tag) -> set_session(SID, User, Server, Resource, Priority, Info), - check_for_sessions_to_replace(User, Server, Resource), + check_for_sessions_to_replace(User, Server, Resource, Bind2Tag), JID = jid:make(User, Server, Resource), ejabberd_hooks:run(sm_register_connection_hook, JID#jid.lserver, [SID, JID, Info]). +-spec open_session(sid(), binary(), binary(), binary(), prio(), info()) -> ok. + +open_session(SID, User, Server, Resource, Priority, Info) -> + open_session(SID, User, Server, Resource, Priority, Info, undefined). + -spec open_session(sid(), binary(), binary(), binary(), info()) -> ok. open_session(SID, User, Server, Resource, Info) -> @@ -452,6 +459,13 @@ c2s_handle_info(#{lang := Lang} = State, replaced) -> State1 = State#{replaced => true}, Err = xmpp:serr_conflict(?T("Replaced by new connection"), Lang), {stop, ejabberd_c2s:send(State1, Err)}; +c2s_handle_info(#{lang := Lang, bind2_tag := Tag} = State, + {replaced_with_bind_tag, Bind2Tag}) when Tag == Bind2Tag -> + State1 = State#{replaced => true}, + Err = xmpp:serr_conflict(?T("Replaced by new connection"), Lang), + {stop, ejabberd_c2s:send(State1, Err)}; +c2s_handle_info(State, {replaced_with_bind_tag, _}) -> + State; c2s_handle_info(#{lang := Lang} = State, kick) -> Err = xmpp:serr_policy_violation(?T("has been kicked"), Lang), {stop, ejabberd_c2s:send(State, Err)}; @@ -826,16 +840,17 @@ clean_session_list([S1, S2 | Rest], Res) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% On new session, check if some existing connections need to be replace --spec check_for_sessions_to_replace(binary(), binary(), binary()) -> ok | replaced. -check_for_sessions_to_replace(User, Server, Resource) -> +-spec check_for_sessions_to_replace(binary(), binary(), binary(), binary() | undefined) + -> ok | replaced. +check_for_sessions_to_replace(User, Server, Resource, Bind2Tag) -> LUser = jid:nodeprep(User), LServer = jid:nameprep(Server), LResource = jid:resourceprep(Resource), - check_existing_resources(LUser, LServer, LResource), + check_existing_resources(LUser, LServer, LResource, Bind2Tag), check_max_sessions(LUser, LServer). --spec check_existing_resources(binary(), binary(), binary()) -> ok. -check_existing_resources(LUser, LServer, LResource) -> +-spec check_existing_resources(binary(), binary(), binary(), binary() | undefined) -> ok. +check_existing_resources(LUser, LServer, LResource, undefined) -> Mod = get_sm_backend(LServer), Ss = get_sessions(Mod, LUser, LServer, LResource), if Ss == [] -> ok; @@ -847,7 +862,18 @@ check_existing_resources(LUser, LServer, LResource) -> (_) -> ok end, SIDs) - end. + end; +check_existing_resources(LUser, LServer, _LResource, Bind2Tag) -> + Mod = get_sm_backend(LServer), + Ss = get_sessions(Mod, LUser, LServer), + Len = size(Bind2Tag), + lists:foreach( + fun(#session{sid = {_, Pid}, usr = {_, _, <>}}) + when Pid /= self(), Tag == Bind2Tag -> + ejabberd_c2s:route(Pid, {replaced_with_bind_tag, Bind2Tag}); + (_) -> + ok + end, Ss). -spec is_existing_resource(binary(), binary(), binary()) -> boolean(). diff --git a/src/mod_stream_mgmt.erl b/src/mod_stream_mgmt.erl index 4b59245a4..ab0889864 100644 --- a/src/mod_stream_mgmt.erl +++ b/src/mod_stream_mgmt.erl @@ -467,9 +467,9 @@ has_resume_data(#{lang := Lang} = State, {ok, InheritedState} -> State1 = check_h_attribute(InheritedState, H), #{mgmt_xmlns := AttrXmlns, mgmt_stanzas_in := AttrH} = State1, - {ok, InheritedState, #sm_resumed{xmlns = AttrXmlns, - h = AttrH, - previd = PrevID}}; + {ok, State1, #sm_resumed{xmlns = AttrXmlns, + h = AttrH, + previd = PrevID}}; {error, Err, InH} -> {error, #sm_failed{reason = 'item-not-found', text = xmpp:mk_text(format_error(Err), Lang),