From d625e24029221cea30ef7078010f16da526ce257 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Tue, 20 Feb 2018 11:38:00 +0300 Subject: [PATCH] Introduce 'negotiation_timeout' The option can be used to specify a period (in seconds) for a stream negotiation to complete. If the timer fires, the stream is considered as failed and the underlying connection gets closed. This is a global option (you cannot set it per domain) and the default is 30 seconds. --- src/ejabberd_c2s.erl | 4 +++- src/ejabberd_config.erl | 8 +++++++- src/ejabberd_s2s_in.erl | 4 +++- src/ejabberd_s2s_out.erl | 4 +++- src/ejabberd_service.erl | 6 ++++-- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 1e81f4d1a..a523083c8 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -519,6 +519,7 @@ init([State, Opts]) -> TLSRequired = proplists:get_bool(starttls_required, Opts), TLSVerify = proplists:get_bool(tls_verify, Opts), Zlib = proplists:get_bool(zlib, Opts), + Timeout = ejabberd_config:negotiation_timeout(), State1 = State#{tls_options => TLSOpts2, tls_required => TLSRequired, tls_enabled => TLSEnabled, @@ -530,7 +531,8 @@ init([State, Opts]) -> lserver => ?MYNAME, access => Access, shaper => Shaper}, - ejabberd_hooks:run_fold(c2s_init, {ok, State1}, [Opts]). + State2 = xmpp_stream_in:set_timeout(State1, Timeout), + ejabberd_hooks:run_fold(c2s_init, {ok, State2}, [Opts]). handle_call(get_presence, From, #{jid := JID} = State) -> Pres = case maps:get(pres_last, State, error) of diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index beb44ddc0..09d433ef6 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -37,7 +37,7 @@ default_db/1, default_db/2, default_ram_db/1, default_ram_db/2, default_queue_type/1, queue_dir/0, fsm_limit_opts/1, use_cache/1, cache_size/1, cache_missed/1, cache_life_time/1, - codec_options/1, get_plain_terms_file/2]). + codec_options/1, get_plain_terms_file/2, negotiation_timeout/0]). -export([start/2]). @@ -1415,6 +1415,8 @@ opt_type(cache_life_time) -> (infinity) -> infinity; (unlimited) -> infinity end; +opt_type(negotiation_timeout) -> + fun(T) when T > 0 -> T end; opt_type(shared_key) -> fun iolist_to_binary/1; opt_type(node_start) -> @@ -1479,3 +1481,7 @@ codec_options(Host) -> true -> []; false -> [ignore_els] end. + +-spec negotiation_timeout() -> pos_integer(). +negotiation_timeout() -> + timer:seconds(get_option(negotiation_timeout, 30)). diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 5345727a2..31a936c8c 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -259,6 +259,7 @@ init([State, Opts]) -> false -> [compression_none | TLSOpts1]; true -> TLSOpts1 end, + Timeout = ejabberd_config:negotiation_timeout(), State1 = State#{tls_options => TLSOpts2, auth_domains => sets:new(), xmlns => ?NS_SERVER, @@ -268,7 +269,8 @@ init([State, Opts]) -> server_host => ?MYNAME, established => false, shaper => Shaper}, - ejabberd_hooks:run_fold(s2s_in_init, {ok, State1}, [Opts]). + State2 = xmpp_stream_in:set_timeout(State1, Timeout), + ejabberd_hooks:run_fold(s2s_in_init, {ok, State2}, [Opts]). handle_call(Request, From, #{server_host := LServer} = State) -> ejabberd_hooks:run_fold(s2s_in_handle_call, LServer, State, [Request, From]). diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 9abc0d017..f82d017ea 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -270,15 +270,17 @@ init([#{server := LServer, remote_server := RServer} = State, Opts]) -> {_, N} -> N; false -> unlimited end, + Timeout = ejabberd_config:negotiation_timeout(), State1 = State#{on_route => queue, queue => p1_queue:new(QueueType, QueueLimit), xmlns => ?NS_SERVER, lang => ?MYLANG, server_host => ServerHost, shaper => none}, + State2 = xmpp_stream_out:set_timeout(State1, Timeout), ?INFO_MSG("Outbound s2s connection started: ~s -> ~s", [LServer, RServer]), - ejabberd_hooks:run_fold(s2s_out_init, ServerHost, {ok, State1}, [Opts]). + ejabberd_hooks:run_fold(s2s_out_init, ServerHost, {ok, State2}, [Opts]). handle_call(Request, From, #{server_host := ServerHost} = State) -> ejabberd_hooks:run_fold(s2s_out_handle_call, ServerHost, State, [Request, From]). diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index de4ab1fd2..816d643eb 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -101,8 +101,10 @@ init([State, Opts]) -> true -> TLSOpts1 end, GlobalRoutes = proplists:get_value(global_routes, Opts, true), + Timeout = ejabberd_config:negotiation_timeout(), State1 = xmpp_stream_in:change_shaper(State, Shaper), - State2 = State1#{access => Access, + State2 = xmpp_stream_in:set_timeout(State1, Timeout), + State3 = State2#{access => Access, xmlns => ?NS_COMPONENT, lang => ?MYLANG, server => ?MYNAME, @@ -111,7 +113,7 @@ init([State, Opts]) -> tls_options => TLSOpts, global_routes => GlobalRoutes, check_from => CheckFrom}, - ejabberd_hooks:run_fold(component_init, {ok, State2}, [Opts]). + ejabberd_hooks:run_fold(component_init, {ok, State3}, [Opts]). handle_stream_start(_StreamStart, #{remote_server := RemoteServer,