summaryrefslogtreecommitdiff
path: root/lib/ssl/src/tls_sender.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl/src/tls_sender.erl')
-rw-r--r--lib/ssl/src/tls_sender.erl153
1 files changed, 93 insertions, 60 deletions
diff --git a/lib/ssl/src/tls_sender.erl b/lib/ssl/src/tls_sender.erl
index 68e4eeed4e..b53a801b90 100644
--- a/lib/ssl/src/tls_sender.erl
+++ b/lib/ssl/src/tls_sender.erl
@@ -68,7 +68,8 @@
key_update_at, %% TLS 1.3
bytes_sent, %% TLS 1.3
dist_handle,
- log_level
+ log_level,
+ hibernate_after
}).
-record(data,
@@ -230,7 +231,8 @@ init({call, From}, {Pid, #{current_write := WriteState,
negotiated_version := Version,
renegotiate_at := RenegotiateAt,
key_update_at := KeyUpdateAt,
- log_level := LogLevel}},
+ log_level := LogLevel,
+ hibernate_after := HibernateAfter}},
#data{connection_states = ConnectionStates, static = Static0} = StateData0) ->
StateData =
StateData0#data{connection_states = ConnectionStates#{current_write => WriteState},
@@ -245,10 +247,11 @@ init({call, From}, {Pid, #{current_write := WriteState,
renegotiate_at = RenegotiateAt,
key_update_at = KeyUpdateAt,
bytes_sent = 0,
- log_level = LogLevel}},
+ log_level = LogLevel,
+ hibernate_after = HibernateAfter}},
{next_state, handshake, StateData, [{reply, From, ok}]};
init(info = Type, Msg, StateData) ->
- handle_common(Type, Msg, StateData);
+ handle_common(?FUNCTION_NAME, Type, Msg, StateData);
init(_, _, _) ->
%% Just in case anything else sneaks through
{keep_state_and_data, [postpone]}.
@@ -281,14 +284,14 @@ connection({call, From}, downgrade, #data{connection_states =
#{current_write := Write}} = StateData) ->
{next_state, death_row, StateData, [{reply,From, {ok, Write}}]};
connection({call, From}, {set_opts, Opts}, StateData) ->
- handle_set_opts(From, Opts, StateData);
+ handle_set_opts(?FUNCTION_NAME, From, Opts, StateData);
connection({call, From}, dist_get_tls_socket,
#data{static = #static{transport_cb = Transport,
socket = Socket,
connection_pid = Pid,
trackers = Trackers}} = StateData) ->
TLSSocket = tls_gen_connection:socket([Pid, self()], Transport, Socket, Trackers),
- {next_state, ?FUNCTION_NAME, StateData, [{reply, From, {ok, TLSSocket}}]};
+ hibernate_after(?FUNCTION_NAME, StateData, [{reply, From, {ok, TLSSocket}}]);
connection({call, From}, {dist_handshake_complete, _Node, DHandle},
#data{static = #static{connection_pid = Pid} = Static} = StateData) ->
false = erlang:dist_ctrl_set_opt(DHandle, get_size, true),
@@ -296,15 +299,20 @@ connection({call, From}, {dist_handshake_complete, _Node, DHandle},
ok = ssl_gen_statem:dist_handshake_complete(Pid, DHandle),
%% From now on we execute on normal priority
process_flag(priority, normal),
- {keep_state, StateData#data{static = Static#static{dist_handle = DHandle}},
- [{reply,From,ok}|
- case dist_data(DHandle) of
- [] ->
- [];
- Data ->
- [{next_event, internal,
- {application_packets,{self(),undefined},Data}}]
- end]};
+
+ case dist_data(DHandle) of
+ [] ->
+ hibernate_after(?FUNCTION_NAME,
+ StateData#data{
+ static = Static#static{dist_handle = DHandle}},
+ [{reply,From,ok}]);
+ Data ->
+ {keep_state,
+ StateData#data{static = Static#static{dist_handle = DHandle}},
+ [{reply,From,ok},
+ {next_event, internal,
+ {application_packets, {self(),undefined}, Data}}]}
+ end;
connection(internal, {application_packets, From, Data}, StateData) ->
send_application_data(Data, From, ?FUNCTION_NAME, StateData);
connection(internal, {post_handshake_data, From, HSData}, StateData) ->
@@ -314,20 +322,22 @@ connection(cast, #alert{} = Alert, StateData0) ->
{next_state, ?FUNCTION_NAME, StateData};
connection(cast, {new_write, WritesState, Version},
#data{connection_states = ConnectionStates, static = Static} = StateData) ->
- {next_state, connection,
- StateData#data{connection_states =
- ConnectionStates#{current_write => WritesState},
- static = Static#static{negotiated_version = Version}}};
+ hibernate_after(connection,
+ StateData#data{connection_states =
+ ConnectionStates#{current_write => WritesState},
+ static =
+ Static#static{negotiated_version = Version}}, []);
%%
-connection(info, dist_data, #data{static = #static{dist_handle = DHandle}}) ->
- {keep_state_and_data,
+connection(info, dist_data,
+ #data{static = #static{dist_handle = DHandle}} = StateData) ->
case dist_data(DHandle) of
[] ->
- [];
+ hibernate_after(?FUNCTION_NAME, StateData, []);
Data ->
- [{next_event, internal,
- {application_packets,{self(),undefined},Data}}]
- end};
+ {keep_state_and_data,
+ [{next_event, internal,
+ {application_packets, {self(),undefined}, Data}}]}
+ end;
connection(info, tick, StateData) ->
consume_ticks(),
Data = [<<0:32>>], % encode_packet(4, <<>>)
@@ -342,8 +352,10 @@ connection(info, {send, From, Ref, Data}, _StateData) ->
{keep_state_and_data,
[{next_event, {call, {self(), undefined}},
{application_data, erlang:iolist_to_iovec(Data)}}]};
+connection(timeout, hibernate, _StateData) ->
+ {keep_state_and_data, [hibernate]};
connection(Type, Msg, StateData) ->
- handle_common(Type, Msg, StateData).
+ handle_common(?FUNCTION_NAME, Type, Msg, StateData).
%%--------------------------------------------------------------------
-spec handshake(gen_statem:event_type(),
@@ -352,7 +364,7 @@ connection(Type, Msg, StateData) ->
gen_statem:event_handler_result(atom()).
%%--------------------------------------------------------------------
handshake({call, From}, {set_opts, Opts}, StateData) ->
- handle_set_opts(From, Opts, StateData);
+ handle_set_opts(?FUNCTION_NAME, From, Opts, StateData);
handshake({call, _}, _, _) ->
%% Postpone all calls to the connection state
{keep_state_and_data, [postpone]};
@@ -376,7 +388,7 @@ handshake(info, {send, _, _, _}, _) ->
%% Testing only, OTP distribution test suites...
{keep_state_and_data, [postpone]};
handshake(Type, Msg, StateData) ->
- handle_common(Type, Msg, StateData).
+ handle_common(?FUNCTION_NAME, Type, Msg, StateData).
%%--------------------------------------------------------------------
-spec death_row(gen_statem:event_type(),
@@ -384,14 +396,18 @@ handshake(Type, Msg, StateData) ->
StateData :: term()) ->
gen_statem:event_handler_result(atom()).
%%--------------------------------------------------------------------
-death_row(state_timeout, Reason, _State) ->
+death_row(state_timeout, Reason, _StateData) ->
{stop, {shutdown, Reason}};
-death_row(info = Type, Msg, State) ->
- handle_common(Type, Msg, State);
-death_row(_Type, _Msg, _State) ->
+death_row(info = Type, Msg, StateData) ->
+ handle_common(?FUNCTION_NAME, Type, Msg, StateData);
+death_row(_Type, _Msg, _StateData) ->
%% Waste all other events
keep_state_and_data.
+%% State entry function that starts shutdown state_timeout
+death_row_shutdown(Reason, StateData) ->
+ {next_state, death_row, StateData, [{state_timeout, 5000, Reason}]}.
+
%%--------------------------------------------------------------------
-spec terminate(Reason :: term(), State :: term(), Data :: term()) ->
any().
@@ -413,36 +429,47 @@ code_change(_OldVsn, State, Data, _Extra) ->
%%%===================================================================
%%% Internal functions
%%%===================================================================
-
-handle_set_opts(From, Opts, #data{static = #static{socket_options = SockOpts} = Static} = StateData) ->
- {keep_state, StateData#data{static = Static#static{socket_options = set_opts(SockOpts, Opts)}},
- [{reply, From, ok}]}.
-
-handle_common({call, From}, {set_opts, Opts},
+handle_set_opts(StateName, From, Opts,
+ #data{static = #static{socket_options = SockOpts} = Static}
+ = StateData) ->
+ hibernate_after(StateName,
+ StateData#data{
+ static =
+ Static#static{
+ socket_options = set_opts(SockOpts, Opts)}},
+ [{reply, From, ok}]).
+
+handle_common(StateName, {call, From}, {set_opts, Opts},
#data{static = #static{socket_options = SockOpts} = Static} = StateData) ->
- {keep_state, StateData#data{static = Static#static{socket_options = set_opts(SockOpts, Opts)}},
- [{reply, From, ok}]};
-handle_common(info, {'EXIT', _Sup, shutdown},
+ hibernate_after(StateName,
+ StateData#data{
+ static =
+ Static#static{
+ socket_options = set_opts(SockOpts, Opts)}},
+ [{reply, From, ok}]);
+handle_common(_StateName, info, {'EXIT', _Sup, shutdown = Reason},
#data{static = #static{erl_dist = true}} = StateData) ->
%% When the connection is on its way down operations
- %% begin to fail. We wait for 5 seconds to receive
- %% possible exit signals for one of our links to the other
- %% involved distribution parties, in which case we want to use
- %% their exit reason for the connection teardown.
- {next_state, death_row, StateData, [{state_timeout, 5000, shutdown}]};
-handle_common(info, {'EXIT', _Dist, Reason},
+ %% begin to fail. We wait to receive possible exit signals
+ %% for one of our links to the other involved distribution parties,
+ %% in which case we want to use their exit reason
+ %% for the connection teardown.
+ death_row_shutdown(Reason, StateData);
+handle_common(_StateName, info, {'EXIT', _Dist, Reason},
#data{static = #static{erl_dist = true}} = StateData) ->
{stop, {shutdown, Reason}, StateData};
-handle_common(info, {'EXIT', _Sup, shutdown}, StateData) ->
+handle_common(_StateName, info, {'EXIT', _Sup, shutdown}, StateData) ->
{stop, shutdown, StateData};
-handle_common(info, Msg, #data{static = #static{log_level = Level}}) ->
- ssl_logger:log(info, Level, #{event => "TLS sender received unexpected info",
+handle_common(StateName, info, Msg,
+ #data{static = #static{log_level = Level}} = StateData) ->
+ ssl_logger:log(info, Level, #{event => "TLS sender received unexpected info",
reason => [{message, Msg}]}, ?LOCATION),
- keep_state_and_data;
-handle_common(Type, Msg, #data{static = #static{log_level = Level}}) ->
- ssl_logger:log(error, Level, #{event => "TLS sender received unexpected event",
+ hibernate_after(StateName, StateData, []);
+handle_common(StateName, Type, Msg,
+ #data{static = #static{log_level = Level}} = StateData) ->
+ ssl_logger:log(error, Level, #{event => "TLS sender received unexpected event",
reason => [{type, Type}, {message, Msg}]}, ?LOCATION),
- keep_state_and_data.
+ hibernate_after(StateName, StateData, []).
send_tls_alert(#alert{} = Alert,
#data{static = #static{negotiated_version = Version,
@@ -471,7 +498,6 @@ send_application_data(Data, From, StateName,
key_update ->
KeyUpdate = tls_handshake_1_3:key_update(update_requested),
{keep_state_and_data, [{next_event, internal, {post_handshake_data, From, KeyUpdate}},
- {next_event, internal, {key_update, From}},
{next_event, internal, {application_packets, From, Data}}]};
renegotiate ->
tls_dtls_connection:internal_renegotiation(Pid, ConnectionStates0),
@@ -491,15 +517,15 @@ send_application_data(Data, From, StateName,
ok when DistHandle =/= undefined ->
ssl_logger:debug(LogLevel, outbound, 'record', Msgs),
StateData1 = update_bytes_sent(Version, StateData, Data),
- {next_state, StateName, StateData1, []};
+ hibernate_after(StateName, StateData1, []);
Reason when DistHandle =/= undefined ->
- {next_state, death_row, StateData, [{state_timeout, 5000, Reason}]};
+ death_row_shutdown(Reason, StateData);
ok ->
ssl_logger:debug(LogLevel, outbound, 'record', Msgs),
StateData1 = update_bytes_sent(Version, StateData, Data),
- {next_state, StateName, StateData1, [{reply, From, ok}]};
+ hibernate_after(StateName, StateData1, [{reply, From, ok}]);
Result ->
- {next_state, StateName, StateData, [{reply, From, Result}]}
+ hibernate_after(StateName, StateData, [{reply, From, Result}])
end
end.
@@ -522,7 +548,7 @@ send_post_handshake_data(Handshake, From, StateName,
StateData = maybe_update_cipher_key(StateData1, Handshake),
{next_state, StateName, StateData, []};
Reason when DistHandle =/= undefined ->
- {next_state, death_row, StateData1, [{state_timeout, 5000, Reason}]};
+ death_row_shutdown(Reason, StateData1);
ok ->
ssl_logger:debug(LogLevel, outbound, 'record', Encoded),
StateData = maybe_update_cipher_key(StateData1, Handshake),
@@ -679,3 +705,10 @@ consume_ticks() ->
after 0 ->
ok
end.
+
+hibernate_after(connection = StateName,
+ #data{static=#static{hibernate_after = HibernateAfter}} = State,
+ Actions) ->
+ {next_state, StateName, State, [{timeout, HibernateAfter, hibernate} | Actions]};
+hibernate_after(StateName, State, Actions) ->
+ {next_state, StateName, State, Actions}.