Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ssl: Use supervisor:which_child/2 to improve start up #9231

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/ssl/src/dtls_connection_sup.erl
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ init(_) ->
period => 3600
},
ChildSpecs = [#{id => undefined,
start => {ssl_gen_statem, start_link, []},
start => {ssl_gen_statem, dtls_start_link, []},
restart => temporary,
shutdown => 4000,
modules => [ssl_gen_statem, dtls_connection],
Expand Down
2 changes: 1 addition & 1 deletion lib/ssl/src/ssl.app.src
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,6 @@
{applications, [crypto, public_key, kernel, stdlib]},
{env, []},
{mod, {ssl_app, []}},
{runtime_dependencies, ["stdlib-6.0","public_key-1.16.4","kernel-9.0",
{runtime_dependencies, ["stdlib-@OTP-19345@","public_key-1.16.4","kernel-9.0",
"erts-15.0","crypto-5.0", "inets-5.10.7",
"runtime_tools-1.15.1"]}]}.
14 changes: 3 additions & 11 deletions lib/ssl/src/ssl.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2174,7 +2174,7 @@ connect(TCPSocket, TLSOptions, Timeout)
try
tls_gen_connection = connection_cb(TLSOptions),
{ok, Config} = ssl_config:handle_options(TCPSocket, TLSOptions, client, undefined),
tls_socket:upgrade(TCPSocket, Config, Timeout)
tls_socket:upgrade(client, TCPSocket, Config, Timeout)
catch
error:{badmatch, _} ->
{error, {dtls_upgrade, notsup}};
Expand Down Expand Up @@ -2448,17 +2448,9 @@ handshake(Socket, SslOptions, Timeout)
when is_list(SslOptions), ?IS_TIMEOUT(Timeout) ->
try
tls_gen_connection = connection_cb(SslOptions),
{ok, #config{transport_info = CbInfo, ssl = SslOpts, emulated = EmOpts}} =
{ok, Config} =
ssl_config:handle_options(Socket, SslOptions, server, undefined),
Transport = element(1, CbInfo),
ok = tls_socket:setopts(Transport, Socket, tls_socket:internal_inet_values()),
{ok, Port} = tls_socket:port(Transport, Socket),
{ok, SessionIdHandle} = tls_socket:session_id_tracker(ssl_unknown_listener, SslOpts),
tls_gen_connection:start_fsm(server, "localhost", Port, Socket,
{SslOpts,
tls_socket:emulated_socket_options(EmOpts, #socket_options{}),
[{session_id_tracker, SessionIdHandle}]},
self(), CbInfo, Timeout)
tls_socket:upgrade(server, Socket, Config, Timeout)
catch
error:{badmatch, _} ->
{error, {dtls_upgrade, notsup}};
Expand Down
18 changes: 10 additions & 8 deletions lib/ssl/src/ssl_gen_statem.erl
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
-include("tls_connection.hrl").

%% Initial Erlang process setup
-export([start_link/7,
start_link/8,
-export([tls_start_link/7,
dtls_start_link/7,
init/1]).

%% TLS connection setup
Expand Down Expand Up @@ -108,26 +108,26 @@
%%% Initial Erlang process setup
%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
-spec start_link(client| server, pid(), ssl:host(), inet:port_number(), port(), tuple(), pid(), tuple()) ->
-spec tls_start_link(client | server, ssl:host(), inet:port_number(), port(), tuple(), pid(), tuple()) ->
{ok, pid()} | ignore | {error, ssl:reason()}.
%%
%% Description: Creates a process which calls Module:init/1 to
%% choose appropriat gen_statem and initialize.
%%--------------------------------------------------------------------
start_link(Role, Sender, Host, Port, Socket, {SslOpts, _, _} = Options, User, CbInfo) ->
tls_start_link(Role, Host, Port, Socket, {SslOpts, _, _} = Options, User, CbInfo) ->
ReceiverOpts = maps:get(receiver_spawn_opts, SslOpts, []),
Opts = [link | proplists:delete(link, ReceiverOpts)],
Pid = proc_lib:spawn_opt(?MODULE, init, [[Role, Sender, Host, Port, Socket, Options, User, CbInfo]], Opts),
Pid = proc_lib:spawn_opt(?MODULE, init, [[Role, self(), Host, Port, Socket, Options, User, CbInfo]], Opts),
{ok, Pid}.

%%--------------------------------------------------------------------
-spec start_link(atom(), ssl:host(), inet:port_number(), port(), tuple(), pid(), tuple()) ->
-spec dtls_start_link(client | server, ssl:host(), inet:port_number(), port(), tuple(), pid(), tuple()) ->
{ok, pid()} | ignore | {error, ssl:reason()}.
%%
%% Description: Creates a gen_statem process which calls Module:init/1 to
%% initialize.
%%--------------------------------------------------------------------
start_link(Role, Host, Port, Socket, {SslOpts, _, _} = Options, User, CbInfo) ->
dtls_start_link(Role, Host, Port, Socket, {SslOpts, _, _} = Options, User, CbInfo) ->
ReceiverOpts = maps:get(receiver_spawn_opts, SslOpts, []),
Opts = [link | proplists:delete(link, ReceiverOpts)],
Pid = proc_lib:spawn_opt(?MODULE, init, [[Role, Host, Port, Socket, Options, User, CbInfo]], Opts),
Expand All @@ -138,9 +138,11 @@ start_link(Role, Host, Port, Socket, {SslOpts, _, _} = Options, User, CbInfo) ->
-spec init(list()) -> no_return().
%% Description: Initialization
%%--------------------------------------------------------------------
init([Role, Sender |[Host, Port, _Socket, {TLSOpts, _, _}, _User, _CbInfo] = InitArgs]) ->
init([Role, Sup | [Host, Port, _Socket, {TLSOpts, _, _}, _User, _CbInfo] = InitArgs]) ->
process_flag(trap_exit, true),

{ok, {_, Sender,_,_}} = supervisor:which_child(Sup, sender),

case maps:get(erl_dist, TLSOpts, false) of
true ->
process_flag(priority, max);
Expand Down
2 changes: 1 addition & 1 deletion lib/ssl/src/ssl_trace.erl
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ trace_profiles() ->
{dtls_server_connection,
[{initial_hello, 3}]},
{tls_gen_connection,
[{start_connection_tree, 5}, {socket_control, 2}]}
[{start_connection_tree, 3}]}
]},
{csp, %% OCSP
fun(M, F, A) -> dbg:tpl(M, F, A, x) end,
Expand Down
18 changes: 6 additions & 12 deletions lib/ssl/src/tls_dyn_connection_sup.erl
Original file line number Diff line number Diff line change
Expand Up @@ -32,33 +32,27 @@
-behaviour(supervisor).

%% API
-export([start_link/0]).
-export([start_child/3]).
-export([start_link/2]).

%% Supervisor callback
-export([init/1]).

%%%=========================================================================
%%% API
%%%=========================================================================
start_link() ->
supervisor:start_link(?MODULE, []).
start_link(SenderArgs, ReciverArgs) ->
supervisor:start_link(?MODULE, [SenderArgs, ReciverArgs]).

start_child(Sup, sender, Args) ->
supervisor:start_child(Sup, sender(Args));
start_child(Sup, receiver, Args) ->
supervisor:start_child(Sup, receiver(Args)).

%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
init(_) ->
init([SenderArgs, ReciverArgs]) ->
SupFlags = #{strategy => one_for_all,
auto_shutdown => any_significant,
intensity => 0,
period => 3600
},
ChildSpecs = [],
ChildSpecs = [sender(SenderArgs), receiver(ReciverArgs)],
{ok, {SupFlags, ChildSpecs}}.

sender(Args) ->
Expand All @@ -74,7 +68,7 @@ receiver(Args) ->
restart => temporary,
type => worker,
significant => true,
start => {ssl_gen_statem, start_link, Args},
start => {ssl_gen_statem, tls_start_link, Args},
modules => [ssl_gen_statem,
tls_client_connection,
tls_server_connection,
Expand Down
85 changes: 32 additions & 53 deletions lib/ssl/src/tls_gen_connection.erl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
-include("tls_record_1_3.hrl").

%% Setup
-export([start_fsm/8,
-export([start_fsm/6,
start_fsm/7,
pids/1,
initialize_tls_sender/1]).

Expand Down Expand Up @@ -72,20 +73,33 @@
%%====================================================================
%% Setup
%%====================================================================
start_fsm(Role, Host, Port, Socket, {SSLOpts, _, _Trackers} = Opts,
start_fsm(Host, Port, Socket, {SSLOpts, _, _Trackers} = Opts,
User, CbInfo, Timeout) ->
ErlDist = maps:get(erl_dist, SSLOpts, false),
SenderSpawnOpts = maps:get(sender_spawn_opts, SSLOpts, []),
SenderOptions = handle_sender_options(ErlDist, SenderSpawnOpts),
Starter = start_connection_tree(User, ErlDist, SenderOptions,
Role, [Host, Port, Socket, Opts, User, CbInfo]),
receive
{Starter, {ok, SockReceiver}} ->
receive {SockReceiver, user_socket, UserSocket} ->
socket_control(UserSocket, Timeout)
end;
{Starter, Error} ->
Error
{ok, DynSup} = start_connection_tree(ErlDist, SenderOptions,
[client, Host, Port, Socket, Opts, User, CbInfo]),
{ok, {_, Receiver,_,_}} = supervisor:which_child(DynSup, receiver),
receive {Receiver, user_socket, UserSocket} ->
case ssl_gen_statem:socket_control(UserSocket) of
{ok, SslSocket} ->
ssl_gen_statem:handshake(SslSocket, Timeout);
Error ->
Error
end
end.

start_fsm(Port, Socket, {SSLOpts, _, _Trackers} = Opts,
User, CbInfo, _Timeout) ->
ErlDist = maps:get(erl_dist, SSLOpts, false),
SenderSpawnOpts = maps:get(sender_spawn_opts, SSLOpts, []),
SenderOptions = handle_sender_options(ErlDist, SenderSpawnOpts),
{ok, DynSup} = start_connection_tree(ErlDist, SenderOptions,
[server, "localhost", Port, Socket, Opts, User, CbInfo]),
{ok, {_, Receiver,_,_}} = supervisor:which_child(DynSup, receiver),
receive {Receiver, user_socket, UserSocket} ->
ssl_gen_statem:socket_control(UserSocket)
end.

handle_sender_options(ErlDist, SpawnOpts) ->
Expand All @@ -96,48 +110,13 @@ handle_sender_options(ErlDist, SpawnOpts) ->
[[{spawn_opt, SpawnOpts}]]
end.

start_connection_tree(User, IsErlDist, SenderOpts, Role, ReceiverOpts) ->
StartConnectionTree =
fun() ->
try start_dyn_connection_sup(IsErlDist) of
{ok, DynSup} ->
case tls_dyn_connection_sup:start_child(DynSup, sender, SenderOpts) of
{ok, Sender} ->
Args = [Role, Sender | ReceiverOpts],
case tls_dyn_connection_sup:start_child(DynSup, receiver, Args) of
{ok, Receiver} ->
User ! {self(), {ok, Receiver}};
{error, _} = Error ->
User ! {self(), Error},
exit(DynSup, shutdown)
end;
{error, _} = Error ->
User ! {self(), Error},
exit(DynSup, shutdown)
end;
{error, _Error} = Error ->
User ! {self(), Error}
catch exit:{noproc, _} ->
User ! {self(), {error, ssl_not_started}};
_:Reason:ST -> %% Don't hang signal internal error
?SSL_LOG(notice, internal_error, [{error, Reason}, {stacktrace, ST}]),
User ! {self(), {error, internal_error}}
end
end,
spawn(StartConnectionTree).

start_dyn_connection_sup(true) ->
tls_connection_sup:start_child_dist([]);
start_dyn_connection_sup(false) ->
tls_connection_sup:start_child([]).

socket_control(SslSocket, Timeout) ->
case ssl_gen_statem:socket_control(SslSocket) of
{ok, SslSocket} ->
ssl_gen_statem:handshake(SslSocket, Timeout);
Error ->
Error
end.
start_connection_tree(IsErlDist, SenderOpts, ReceiverOpts) ->
case IsErlDist of
false ->
tls_connection_sup:start_child([SenderOpts, ReceiverOpts]);
true ->
tls_connection_sup:start_child_dist([SenderOpts, ReceiverOpts])
end.

pids(#state{protocol_specific = #{sender := Sender}}) ->
[self(), Sender].
Expand Down
78 changes: 39 additions & 39 deletions lib/ssl/src/tls_socket.erl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
accept/3,
socket/6,
connect/4,
upgrade/3,
upgrade/4,
setopts/3,
getopts/3,
getstat/3,
Expand All @@ -51,7 +51,6 @@
start_link/3,
terminate/2,
inherit_tracker/3,
session_id_tracker/2,
emulated_socket_options/2,
get_emulated_opts/1,
set_emulated_opts/2,
Expand Down Expand Up @@ -112,25 +111,27 @@ accept(ListenSocket, #config{transport_info = {Transport,_,_,_,_} = CbInfo,
{error, Reason}
end.

upgrade(Socket, #config{transport_info = {Transport,_,_,_,_}= CbInfo,
ssl = SslOptions,
emulated = EmOpts}, Timeout) ->
ok = setopts(Transport, Socket, tls_socket:internal_inet_values()),
upgrade(client, Socket, #config{transport_info = CbInfo,
ssl = SslOptions,
emulated = EmOpts}, Timeout) ->
Transport = element(1, CbInfo),
ok = setopts(Transport, Socket, internal_inet_values()),
case peername(Transport, Socket) of
{ok, {Host, Port}} ->
try tls_gen_connection:start_fsm(client, Host, Port, Socket,
{SslOptions,
emulated_socket_options(EmOpts, #socket_options{}), undefined},
self(), CbInfo, Timeout) of
Result ->
Result
catch
exit:{noproc, _} ->
{error, ssl_not_started}
end;
start_tls_client_connection(Host, Port, Socket, SslOptions, EmOpts, CbInfo, Timeout);
{error, Error} ->
{error, Error}
end.
end;
upgrade(server, Socket, #config{transport_info = CbInfo,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how come the previous variant of upgrade function worked for server role? did it work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The server upgrade worked, but not using the upgrade function, the server upgrade was implemented directly in ssl.erl calling several functions in tls_socket. It made it harder to understand what was happening and it was asymmetrical to how the client is implemented. When the logic is the same the code should have the same pattern. And also we should keep the related logic in the relevant modules (as we have discussed earlier) We can continue to work on when it makes sense to have client and server separate modules, but it does not make sense in all situations, I think for some modules it makes more sense with a parameter.

ssl = SslOpts,
emulated = EmOpts}, Timeout) ->
Transport = element(1, CbInfo),
ok = setopts(Transport, Socket, internal_inet_values()),
{ok, Port} = port(Transport, Socket),
{ok, SessionIdHandle} = session_id_tracker(ssl_unknown_listener, SslOpts),
Trackers = [{session_id_tracker, SessionIdHandle}],
{ok, SSocket} = start_tls_server_connection(SslOpts, Port, Socket, EmOpts, Trackers, CbInfo),
ssl_gen_statem:handshake(SSocket, Timeout).

connect(Host, Port,
#config{transport_info = CbInfo, inet_user = UserOpts, ssl = SslOpts,
Expand All @@ -139,16 +140,7 @@ connect(Host, Port,
{Transport, _, _, _, _} = CbInfo,
try Transport:connect(Host, Port, SocketOpts, Timeout) of
{ok, Socket} ->
try tls_gen_connection:start_fsm(client, Host, Port, Socket,
{SslOpts,
emulated_socket_options(EmOpts, #socket_options{}), undefined},
self(), CbInfo, Timeout) of
Result ->
Result
catch
exit:{noproc, _} ->
{error, ssl_not_started}
end;
start_tls_client_connection(Host, Port, Socket, SslOpts, EmOpts, CbInfo, Timeout);
{error, Reason} ->
{error, Reason}
catch
Expand Down Expand Up @@ -420,19 +412,27 @@ call(Pid, Msg) ->
gen_server:call(Pid, Msg, infinity).

start_tls_server_connection(SslOpts, Port, Socket, EmOpts, Trackers, CbInfo) ->
try
{ok, DynSup} = tls_connection_sup:start_child([]),
SenderOpts = maps:get(sender_spawn_opts, SslOpts, []),
{ok, Sender} = tls_dyn_connection_sup:start_child(DynSup, sender, [[{spawn_opt, SenderOpts}]]),
ConnArgs = [server, Sender, "localhost", Port, Socket,
{SslOpts, emulated_socket_options(EmOpts, #socket_options{}), Trackers}, self(), CbInfo],
{ok, Pid} = tls_dyn_connection_sup:start_child(DynSup, receiver, ConnArgs),
receive {Pid, user_socket, UserSocket} ->
ssl_gen_statem:socket_control(UserSocket)
end
try tls_gen_connection:start_fsm(Port, Socket,
{SslOpts,
emulated_socket_options(EmOpts, #socket_options{}), Trackers},
self(), CbInfo, infinity) of
Result ->
Result
catch
exit:{noproc, _} ->
{error, ssl_not_started}
end.

start_tls_client_connection(Host, Port, Socket, SslOpts, EmOpts, CbInfo, Timeout) ->
try tls_gen_connection:start_fsm(Host, Port, Socket,
{SslOpts,
emulated_socket_options(EmOpts, #socket_options{}), undefined},
self(), CbInfo, Timeout) of
Result ->
Result
catch
error:{badmatch, {error, _} = Error} ->
Error
exit:{noproc, _} ->
{error, ssl_not_started}
end.

split_options(Opts) ->
Expand Down
Loading