Skip to content

Commit

Permalink
Merge pull request #4094 from esl/c2s/features
Browse files Browse the repository at this point in the history
c2s/features optimisations
  • Loading branch information
arcusfelis authored Aug 14, 2023
2 parents 0db93ef + 73bda74 commit dec621e
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 65 deletions.
67 changes: 35 additions & 32 deletions src/c2s/mongoose_c2s.erl
Original file line number Diff line number Diff line change
Expand Up @@ -443,20 +443,19 @@ handle_sasl_success(State = #c2s_data{listener_opts = LOpts}, Creds) ->

-spec stream_start_features_before_auth(data()) -> fsm_res().
stream_start_features_before_auth(#c2s_data{host_type = HostType, lserver = LServer,
listener_opts = LOpts} = S) ->
send_header(S),
listener_opts = LOpts} = StateData) ->
send_header(StateData),
CredOpts = mongoose_credentials:make_opts(LOpts),
Creds = mongoose_credentials:new(LServer, HostType, CredOpts),
SASLState = cyrsasl:server_new(<<"jabber">>, LServer, HostType, <<>>, [], Creds),
StreamFeatures = mongoose_c2s_stanzas:stream_features_before_auth(HostType, LServer, LOpts, S),
send_element_from_server_jid(S, StreamFeatures),
{next_state, {wait_for_feature_before_auth, SASLState, ?AUTH_RETRIES}, S, state_timeout(LOpts)}.
StreamFeatures = mongoose_c2s_stanzas:stream_features_before_auth(StateData),
send_element_from_server_jid(StateData, StreamFeatures),
{next_state, {wait_for_feature_before_auth, SASLState, ?AUTH_RETRIES}, StateData, state_timeout(LOpts)}.

-spec stream_start_features_after_auth(data()) -> fsm_res().
stream_start_features_after_auth(#c2s_data{host_type = HostType, lserver = LServer,
listener_opts = LOpts} = StateData) ->
stream_start_features_after_auth(#c2s_data{listener_opts = LOpts} = StateData) ->
send_header(StateData),
StreamFeatures = mongoose_c2s_stanzas:stream_features_after_auth(HostType, LServer, LOpts),
StreamFeatures = mongoose_c2s_stanzas:stream_features_after_auth(StateData),
send_element_from_server_jid(StateData, StreamFeatures),
{next_state, {wait_for_feature_after_auth, ?BIND_RETRIES}, StateData, state_timeout(LOpts)}.

Expand Down Expand Up @@ -757,8 +756,7 @@ handle_flush(StateData = #c2s_data{host_type = HostType}, C2SState, Acc) ->

-spec maybe_send_element(data(), mongoose_c2s_hooks:result()) -> mongoose_acc:t().
maybe_send_element(StateData, {ok, Acc}) ->
Element = mongoose_acc:element(Acc),
do_send_element(StateData, Element, Acc);
send(StateData, Acc);
maybe_send_element(_, {stop, Acc}) ->
Acc.

Expand Down Expand Up @@ -808,13 +806,6 @@ handle_state_result(StateData0, C2SState, MaybeAcc,
[maybe_send_xml(StateData2, MaybeAcc, Send) || Send <- MaybeSocketSend ],
{next_state, NextFsmState, StateData2, MaybeActions}.

-spec maybe_send_xml(data(), mongoose_acc:t(), exml:element()) -> mongoose_acc:t().
maybe_send_xml(StateData = #c2s_data{host_type = HostType, lserver = LServer}, undefined, ToSend) ->
Acc = mongoose_acc:new(#{host_type => HostType, lserver => LServer, location => ?LOCATION}),
do_send_element(StateData, ToSend, Acc);
maybe_send_xml(StateData, Acc, ToSend) ->
do_send_element(StateData, ToSend, Acc).

%% @doc This function is executed when c2s receives a stanza from the TCP connection.
-spec element_to_origin_accum(data(), exml:element()) -> mongoose_acc:t().
element_to_origin_accum(StateData = #c2s_data{sid = SID, jid = Jid}, El) ->
Expand Down Expand Up @@ -850,17 +841,6 @@ c2s_stream_error(StateData, Error) ->
send_xml(StateData, ?XML_STREAM_TRAILER),
{stop, {shutdown, stream_error}, StateData}.

-spec send_element_from_server_jid(data(), exml:element()) -> any().
send_element_from_server_jid(StateData, El) ->
Acc = mongoose_acc:new(
#{host_type => StateData#c2s_data.host_type,
lserver => StateData#c2s_data.lserver,
location => ?LOCATION,
from_jid => jid:make_noprep(<<>>, StateData#c2s_data.lserver, <<>>),
to_jid => StateData#c2s_data.jid,
element => El}),
do_send_element(StateData, El, Acc).

-spec bounce_messages(data()) -> ok.
bounce_messages(StateData) ->
receive
Expand Down Expand Up @@ -947,12 +927,35 @@ sm_unset_reason(normal) ->
sm_unset_reason(_) ->
error.

%% @doc This is the termination point - from here stanza is sent to the user
-spec do_send_element(data(), exml:element(), mongoose_acc:t()) -> mongoose_acc:t().
do_send_element(StateData = #c2s_data{host_type = undefined}, El, Acc) ->
%% @doc These are the termination points - from here stanza is sent to the user
-spec send(data(), mongoose_acc:t()) -> mongoose_acc:t().
send(StateData, Acc) ->
El = mongoose_acc:element(Acc),
do_send_element(StateData, Acc, El).

-spec send_element_from_server_jid(data(), exml:element()) -> any().
send_element_from_server_jid(StateData, El) ->
Acc = mongoose_acc:new(
#{host_type => StateData#c2s_data.host_type,
lserver => StateData#c2s_data.lserver,
location => ?LOCATION,
from_jid => jid:make_noprep(<<>>, StateData#c2s_data.lserver, <<>>),
to_jid => StateData#c2s_data.jid,
element => El}),
do_send_element(StateData, Acc, El).

-spec maybe_send_xml(data(), mongoose_acc:t(), exml:element()) -> mongoose_acc:t().
maybe_send_xml(StateData = #c2s_data{host_type = HostType, lserver = LServer}, undefined, ToSend) ->
Acc = mongoose_acc:new(#{host_type => HostType, lserver => LServer, location => ?LOCATION}),
do_send_element(StateData, Acc, ToSend);
maybe_send_xml(StateData, Acc, ToSend) ->
do_send_element(StateData, Acc, ToSend).

-spec do_send_element(data(), mongoose_acc:t(), exml:element()) -> mongoose_acc:t().
do_send_element(StateData = #c2s_data{host_type = undefined}, Acc, El) ->
send_xml(StateData, El),
Acc;
do_send_element(StateData = #c2s_data{host_type = HostType}, #xmlel{} = El, Acc) ->
do_send_element(StateData = #c2s_data{host_type = HostType}, Acc, #xmlel{} = El) ->
Res = send_xml(StateData, El),
Acc1 = mongoose_acc:set(c2s, send_result, Res, Acc),
mongoose_hooks:xmpp_send_element(HostType, Acc1, El).
Expand Down
67 changes: 38 additions & 29 deletions src/c2s/mongoose_c2s_stanzas.erl
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

-export([
stream_header/4,
stream_features_before_auth/4,
stream_features_before_auth/1,
tls_proceed/0,
stream_features_after_auth/3,
stream_features_after_auth/1,
sasl_success_stanza/1,
sasl_failure_stanza/1,
sasl_challenge_stanza/1,
Expand Down Expand Up @@ -36,12 +36,14 @@ stream_header(Server, Version, Lang, StreamId) ->
stream_features(Features) ->
#xmlel{name = <<"stream:features">>, children = Features}.

-spec stream_features_before_auth(
mongooseim:host_type(), jid:lserver(), mongoose_listener:options(), mongoose_c2s:data()) ->
exml:element().
stream_features_before_auth(HostType, LServer, LOpts, StateData) ->
IsSSL = mongoose_c2s_socket:is_ssl(mongoose_c2s:get_socket(StateData)),
Features = determine_features(HostType, LServer, LOpts, IsSSL, StateData),
-spec stream_features_before_auth(mongoose_c2s:data()) -> exml:element().
stream_features_before_auth(StateData) ->
HostType = mongoose_c2s:get_host_type(StateData),
LServer = mongoose_c2s:get_lserver(StateData),
Socket = mongoose_c2s:get_socket(StateData),
LOpts = mongoose_c2s:get_listener_opts(StateData),
IsSSL = mongoose_c2s_socket:is_ssl(Socket),
Features = determine_features(StateData, HostType, LServer, LOpts, IsSSL),
stream_features(Features).

%% From RFC 6120, section 5.3.1:
Expand All @@ -54,14 +56,16 @@ stream_features_before_auth(HostType, LServer, LOpts, StateData) ->
%% receiving entity will likely depend on whether TLS has been negotiated).
%%
%% http://xmpp.org/rfcs/rfc6120.html#tls-rules-mtn
determine_features(_, _, #{tls := #{mode := starttls_required}}, false, _StateData) ->
determine_features(_, _, _, #{tls := #{mode := starttls_required}}, false) ->
[starttls_stanza(required)];
determine_features(HostType, LServer, _, true, StateData) ->
determine_features(StateData, HostType, LServer, _, true) ->
InitialFeatures = maybe_sasl_mechanisms(StateData),
mongoose_hooks:c2s_stream_features(HostType, LServer, InitialFeatures);
determine_features(HostType, LServer, _, _, StateData) ->
StreamFeaturesParams = #{c2s_data => StateData, lserver => LServer},
mongoose_hooks:c2s_stream_features(HostType, StreamFeaturesParams, InitialFeatures);
determine_features(StateData, HostType, LServer, _, _) ->
InitialFeatures = [starttls_stanza(optional) | maybe_sasl_mechanisms(StateData)],
mongoose_hooks:c2s_stream_features(HostType, LServer, InitialFeatures).
StreamFeaturesParams = #{c2s_data => StateData, lserver => LServer},
mongoose_hooks:c2s_stream_features(HostType, StreamFeaturesParams, InitialFeatures).

-spec maybe_sasl_mechanisms(mongoose_c2s:data()) -> [exml:element()].
maybe_sasl_mechanisms(StateData) ->
Expand All @@ -88,24 +92,29 @@ tls_proceed() ->
#xmlel{name = <<"proceed">>,
attrs = [{<<"xmlns">>, ?NS_TLS}]}.

-spec stream_features_after_auth(mongooseim:host_type(), jid:lserver(), mongoose_listener:options()) ->
exml:element().
stream_features_after_auth(HostType, LServer, #{backwards_compatible_session := false}) ->
Features = [#xmlel{name = <<"bind">>,
attrs = [{<<"xmlns">>, ?NS_BIND}]}
| hook_enabled_features(HostType, LServer)],
stream_features(Features);
stream_features_after_auth(HostType, LServer, #{backwards_compatible_session := true}) ->
Features = [#xmlel{name = <<"session">>,
attrs = [{<<"xmlns">>, ?NS_SESSION}]},
#xmlel{name = <<"bind">>,
attrs = [{<<"xmlns">>, ?NS_BIND}]}
| hook_enabled_features(HostType, LServer)],
stream_features(Features).
-spec stream_features_after_auth(mongoose_c2s:data()) -> exml:element().
stream_features_after_auth(StateData) ->
case mongoose_c2s:get_listener_opts(StateData) of
#{backwards_compatible_session := false} ->
Features = [#xmlel{name = <<"bind">>,
attrs = [{<<"xmlns">>, ?NS_BIND}]}
| hook_enabled_features(StateData)],
stream_features(Features);
#{backwards_compatible_session := true} ->
Features = [#xmlel{name = <<"session">>,
attrs = [{<<"xmlns">>, ?NS_SESSION}]},
#xmlel{name = <<"bind">>,
attrs = [{<<"xmlns">>, ?NS_BIND}]}
| hook_enabled_features(StateData)],
stream_features(Features)
end.

hook_enabled_features(HostType, LServer) ->
hook_enabled_features(StateData) ->
HostType = mongoose_c2s:get_host_type(StateData),
LServer = mongoose_c2s:get_lserver(StateData),
InitialFeatures = mongoose_hooks:roster_get_versioning_feature(HostType),
mongoose_hooks:c2s_stream_features(HostType, LServer, InitialFeatures).
StreamFeaturesParams = #{c2s_data => StateData, lserver => LServer},
mongoose_hooks:c2s_stream_features(HostType, StreamFeaturesParams, InitialFeatures).

-spec sasl_success_stanza(binary()) -> exml:element().
sasl_success_stanza(ServerOut) ->
Expand Down
7 changes: 3 additions & 4 deletions src/hooks/mongoose_hooks.erl
Original file line number Diff line number Diff line change
Expand Up @@ -475,13 +475,12 @@ filter_pep_recipient(C2SData, Feature, To) ->
HostType = mongoose_c2s:get_host_type(C2SData),
run_hook_for_host_type(filter_pep_recipient, HostType, true, Params).

-spec c2s_stream_features(HostType, LServer, InitialFeatures) -> Result when
-spec c2s_stream_features(HostType, Params, InitialFeatures) -> Result when
HostType :: mongooseim:host_type(),
LServer :: jid:lserver(),
Params :: #{c2s_data := mongoose_c2s:data(), lserver := jid:lserver()},
InitialFeatures :: [exml:element()],
Result :: [exml:element()].
c2s_stream_features(HostType, LServer, InitialFeatures) ->
Params = #{lserver => LServer},
c2s_stream_features(HostType, Params, InitialFeatures) ->
run_hook_for_host_type(c2s_stream_features, HostType, InitialFeatures, Params).

-spec check_bl_c2s(IP) -> Result when
Expand Down

0 comments on commit dec621e

Please sign in to comment.