File 3821-ssh-New-connection-start-procedure.patch of Package erlang
From f32fc320cbffa31554b5468d7b491e63bfc05d68 Mon Sep 17 00:00:00 2001
From: Hans Nilsson <hans@erlang.org>
Date: Thu, 3 Dec 2020 09:55:53 +0100
Subject: [PATCH 1/2] ssh: New connection start procedure
---
lib/ssh/src/ssh.erl | 72 ++----
lib/ssh/src/ssh_acceptor.erl | 62 ++---
lib/ssh/src/ssh_connection_handler.erl | 330 +++++++++++--------------
lib/ssh/src/sshc_sup.erl | 9 +-
lib/ssh/src/sshd_sup.erl | 22 +-
lib/ssh/test/ssh_sup_SUITE.erl | 13 +-
6 files changed, 222 insertions(+), 286 deletions(-)
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 023f6d884d..9abb0fdebb 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -140,16 +140,15 @@ connect(Socket, UserOptions, NegotiationTimeout) when is_list(UserOptions) ->
case ssh_options:handle_options(client, UserOptions) of
{error, Error} ->
{error, Error};
- Options ->
- case valid_socket_to_use(Socket, ?GET_OPT(transport,Options)) of
- ok ->
- connect_socket(Socket,
- ?PUT_INTERNAL_OPT({connected_socket,Socket}, Options),
- NegotiationTimeout);
- {error,SockError} ->
- {error,SockError}
- end
- end.
+
+ Options = #{} ->
+ case valid_socket_to_use(Socket, ?GET_OPT(transport,Options)) of
+ ok ->
+ ssh_connection_handler:start_connection(client, Socket, Options, NegotiationTimeout);
+ {error,SockError} ->
+ {error,SockError}
+ end
+ end.
-spec connect(Host, Port, Options, NegotiationTimeout) -> {ok,connection_ref()} | {error,term()} when
@@ -162,44 +161,25 @@ connect(Host0, Port, UserOptions, NegotiationTimeout) when is_integer(Port),
Port>0,
is_list(UserOptions) ->
case ssh_options:handle_options(client, UserOptions) of
- {error, _Reason} = Error ->
- Error;
+ {error, Reason} ->
+ {error, Reason};
+
Options ->
- {_, Transport, _} = TransportOpts = ?GET_OPT(transport, Options),
- ConnectionTimeout = ?GET_OPT(connect_timeout, Options),
- SocketOpts = [{active,false} | ?GET_OPT(socket_options,Options)],
- Host = mangle_connect_address(Host0, SocketOpts),
- try Transport:connect(Host, Port, SocketOpts, ConnectionTimeout) of
- {ok, Socket} ->
- connect_socket(Socket,
- ?PUT_INTERNAL_OPT({host,Host}, Options),
- NegotiationTimeout);
- {error, Reason} ->
- {error, Reason}
- catch
- exit:{function_clause, _F} ->
- {error, {options, {transport, TransportOpts}}};
- exit:badarg ->
- {error, {options, {socket_options, SocketOpts}}}
- end
+ SockOpts = ?GET_OPT(socket_options, Options),
+ Host = mangle_connect_address(Host0, SockOpts),
+ {_, Callback, _} = ?GET_OPT(transport, Options),
+ SocketOpts = [{active,false} | SockOpts],
+ ConnectionTimeout = ?GET_OPT(connect_timeout, Options),
+ try Callback:connect(Host, Port, SocketOpts, ConnectionTimeout) of
+ {ok, Socket} ->
+ ssh_connection_handler:start_connection(client, Socket, Options, NegotiationTimeout);
+ {error, Reason} ->
+ {error, Reason}
+ catch
+ _:Error -> {error, Error}
+ end
end.
-
-connect_socket(Socket, Options0, NegotiationTimeout) ->
- {ok, {Host,Port}} = inet:sockname(Socket),
- Profile = ?GET_OPT(profile, Options0),
-
- {ok, {SystemSup, SubSysSup}} = sshc_sup:start_system_subsystem(Host, Port, Profile, Options0),
-
- ConnectionSup = ssh_system_sup:connection_supervisor(SystemSup),
- Opts = ?PUT_INTERNAL_OPT([{user_pid,self()},
- {supervisors, [{system_sup, SystemSup},
- {subsystem_sup, SubSysSup},
- {connection_sup, ConnectionSup}]}
- ], Options0),
- ssh_connection_handler:start_connection(client, Socket, Opts, NegotiationTimeout).
-
-
%%--------------------------------------------------------------------
-spec close(ConnectionRef) -> ok | {error,term()} when
ConnectionRef :: connection_ref() .
@@ -841,6 +821,8 @@ is_host1(T) when is_tuple(T), size(T)==16 -> lists:all(fun(I) -> 0=<I andalso I=
is_host1(loopback) -> true.
%%%----------------------------------------------------------------
+mangle_connect_address(A, #{socket_options := SockOpts}) ->
+ mangle_connect_address(A, SockOpts);
mangle_connect_address(A, SockOpts) ->
mangle_connect_address1(A, proplists:get_value(inet6,SockOpts,false)).
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index 7874f93fa2..773d8025cb 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -167,20 +167,20 @@ request_ownership(LSock, SockOwner) ->
%%%----------------------------------------------------------------
acceptor_loop(Callback, Port, Address, Opts, ListenSocket, AcceptTimeout) ->
- case (catch Callback:accept(ListenSocket, AcceptTimeout)) of
- {ok, Socket} ->
- handle_connection(Callback, Address, Port, Opts, Socket),
- ?MODULE:acceptor_loop(Callback, Port, Address, Opts,
- ListenSocket, AcceptTimeout);
- {error, Reason} ->
- handle_error(Reason),
- ?MODULE:acceptor_loop(Callback, Port, Address, Opts,
- ListenSocket, AcceptTimeout);
- {'EXIT', Reason} ->
- handle_error(Reason),
- ?MODULE:acceptor_loop(Callback, Port, Address, Opts,
- ListenSocket, AcceptTimeout)
- end.
+ case Callback:accept(ListenSocket, AcceptTimeout) of
+ {ok,Socket} ->
+ case handle_connection(Callback, Address, Port, Opts, Socket) of
+ {error,Error} ->
+ catch Callback:close(Socket),
+ handle_error(Error);
+ _ ->
+ ok
+ end;
+ {error,Error} ->
+ handle_error(Error)
+ end,
+ ?MODULE:acceptor_loop(Callback, Port, Address, Opts,
+ ListenSocket, AcceptTimeout).
%%%----------------------------------------------------------------
handle_connection(Callback, Address, Port, Options, Socket) ->
@@ -190,16 +190,8 @@ handle_connection(Callback, Address, Port, Options, Socket) ->
MaxSessions = ?GET_OPT(max_sessions, Options),
case number_of_connections(SystemSup) < MaxSessions of
true ->
- {ok, SubSysSup} =
- ssh_system_sup:start_subsystem(SystemSup, server, Address, Port, Profile, Options),
- ConnectionSup = ssh_subsystem_sup:connection_supervisor(SubSysSup),
NegTimeout = ?GET_OPT(negotiation_timeout, Options),
- ssh_connection_handler:start_connection(server, Socket,
- ?PUT_INTERNAL_OPT(
- {supervisors, [{system_sup, SystemSup},
- {subsystem_sup, SubSysSup},
- {connection_sup, ConnectionSup}]},
- Options), NegTimeout);
+ ssh_connection_handler:start_connection(server, {Address,Port}, Socket, Options, NegTimeout);
false ->
Callback:close(Socket),
IPstr = if is_tuple(Address) -> inet:ntoa(Address);
@@ -218,29 +210,23 @@ handle_connection(Callback, Address, Port, Options, Socket) ->
%%%----------------------------------------------------------------
handle_error(timeout) ->
ok;
-
handle_error(enfile) ->
%% Out of sockets...
timer:sleep(?SLEEP_TIME);
-
handle_error(emfile) ->
%% Too many open files -> Out of sockets...
timer:sleep(?SLEEP_TIME);
-
handle_error(closed) ->
error_logger:info_report("The ssh accept socket was closed by "
- "a third party. "
- "This will not have an impact on ssh "
- "that will open a new accept socket and "
- "go on as nothing happened. It does however "
- "indicate that some other software is behaving "
- "badly."),
- exit(normal);
-
-handle_error(Reason) ->
- String = lists:flatten(io_lib:format("Accept error: ~p", [Reason])),
- error_logger:error_report(String),
- exit({accept_failed, String}).
+ "a third party. "
+ "This will not have an impact on ssh "
+ "that will open a new accept socket and "
+ "go on as nothing happened. It does however "
+ "indicate that some other software is behaving "
+ "badly.");
+handle_error(Error) ->
+ String = lists:flatten(io_lib:format("Accept error: ~p", [Error])),
+ error_logger:error_report(String).
%%%################################################################
%%%#
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index a198a95937..070039b309 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -41,12 +41,13 @@
%%% Start and stop
-export([start_link/3,
+ start_connection/4, start_connection/5,
+ socket_control/3,
stop/1
]).
%%% Internal application API
--export([start_connection/4,
- available_hkey_algorithms/2,
+-export([available_hkey_algorithms/2,
open_channel/6,
start_channel/5,
handle_direct_tcpip/6,
@@ -75,8 +76,7 @@
format_status/2, code_change/4]).
%%% Exports not intended to be used :). They are used for spawning and tests
--export([init_connection_handler/3, % proc_lib:spawn needs this
- init_ssh_record/3, % Export of this internal function
+-export([init_ssh_record/3, % Export of this internal function
% intended for low-level protocol test suites
renegotiate/1, alg/1 % Export intended for test cases
]).
@@ -97,18 +97,54 @@
%%====================================================================
%% Start / stop
%%====================================================================
+
+%%--------------------------------------------------------------------
+start_connection(Role, Socket, Options, NegotiationTimeout) ->
+ {ok, {Host,Port}} = inet:sockname(Socket),
+ start_connection(Role, {Host,Port}, Socket, Options, NegotiationTimeout).
+
+start_connection(Role, {Host,Port}, Socket, Options0, NegotiationTimeout) ->
+ try
+ Options1 = ?PUT_INTERNAL_OPT([{user_pid, self()}
+ ], Options0),
+ Profile = ?GET_OPT(profile, Options1),
+ {ok, {SystemSup, SubSysSup}} =
+ case Role of
+ client -> sshc_sup:start_system_subsystem(Host, Port, Profile, Options1);
+ server -> sshd_sup:start_system_subsystem(Host, Port, Profile, Options1)
+ end,
+ ConnectionSup = ssh_system_sup:connection_supervisor(SystemSup),
+ Options = ?PUT_INTERNAL_OPT([{supervisors, [{system_sup, SystemSup},
+ {subsystem_sup, SubSysSup},
+ {connection_sup, ConnectionSup}]}
+ ], Options1),
+ case ssh_connection_sup:start_child(ConnectionSup, [Role, Socket, Options]) of
+ {ok, Pid} ->
+ case socket_control(Socket, Pid, Options) of
+ ok ->
+ handshake(Pid, erlang:monitor(process,Pid), NegotiationTimeout);
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end
+ catch
+ exit:{noproc,{gen_server,call,_}} -> {error, ssh_not_started};
+ error:Error -> {error, Error};
+ Class:Error -> {error, {Class,Error}}
+ end.
+
%%--------------------------------------------------------------------
-spec start_link(role(),
gen_tcp:socket(),
internal_options()
- ) -> {ok, pid()}.
-%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-start_link(Role, Socket, Options) ->
- {ok, proc_lib:spawn_opt(?MODULE,
- init_connection_handler,
- [Role, Socket, Options],
- [link, {message_queue_data,off_heap}]
- )}.
+ ) -> {ok, pid()} | ignore | {error, term()} .
+
+start_link(Role, Socket, Options) when Role==client ; Role==server ->
+ gen_statem:start_link(?MODULE, [Role, Socket, Options],
+ [{spawn_opt, [{message_queue_data,off_heap}]}
+ ]).
%%--------------------------------------------------------------------
@@ -127,46 +163,6 @@ stop(ConnectionHandler)->
%% Internal application API
%%====================================================================
-%%--------------------------------------------------------------------
--spec start_connection(role(),
- gen_tcp:socket(),
- internal_options(),
- timeout()
- ) -> {ok, connection_ref()} | {error, term()}.
-%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-start_connection(Role, Socket, Options, Timeout) ->
- try
- case Role of
- client ->
- ChildPid = start_the_connection_child(self(), Role, Socket, Options),
- handshake(ChildPid, erlang:monitor(process,ChildPid), Timeout);
- server ->
- case ?GET_OPT(parallel_login, Options) of
- true ->
- HandshakerPid =
- spawn_link(fun() ->
- process_flag(trap_exit, true),
- receive
- {do_handshake, Pid} ->
- handshake(Pid, erlang:monitor(process,Pid), Timeout)
- after Timeout ->
- {error, timeout2}
- end
- end),
- ChildPid = start_the_connection_child(HandshakerPid, Role, Socket, Options),
- HandshakerPid ! {do_handshake, ChildPid};
- false ->
- ChildPid = start_the_connection_child(self(), Role, Socket, Options),
- handshake(ChildPid, erlang:monitor(process,ChildPid), Timeout)
- end
- end
- catch
- exit:{noproc, _} ->
- {error, ssh_not_started};
- _:Error ->
- {error, Error}
- end.
-
%%--------------------------------------------------------------------
%%% Some other module has decided to disconnect.
@@ -446,92 +445,54 @@ alg(ConnectionHandler) ->
%%====================================================================
%% Intitialisation
%%====================================================================
-%%--------------------------------------------------------------------
--spec init_connection_handler(role(),
- gen_tcp:socket(),
- internal_options()
- ) -> no_return().
-%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-init_connection_handler(Role, Socket, Opts) ->
- case init([Role, Socket, Opts]) of
- {ok, StartState, D} when Role == server ->
- process_flag(trap_exit, true),
- gen_statem:enter_loop(?MODULE,
- [], %%[{debug,[trace,log,statistics,debug]} ], %% []
- StartState,
- D);
-
- {ok, StartState, D0=#data{connection_state=C}} when Role == client ->
- process_flag(trap_exit, true),
- Sups = ?GET_INTERNAL_OPT(supervisors, Opts),
- D = D0#data{connection_state =
- C#connection{system_supervisor = proplists:get_value(system_sup, Sups),
- sub_system_supervisor = proplists:get_value(subsystem_sup, Sups),
- connection_supervisor = proplists:get_value(connection_sup, Sups)
- }},
- gen_statem:enter_loop(?MODULE,
- [], %%[{debug,[trace,log,statistics,debug]} ], %% []
- StartState,
- D);
-
- {stop, Error} ->
- D = try
- %% Only servers have supervisorts defined in Opts
- Sups = ?GET_INTERNAL_OPT(supervisors, Opts),
- #connection{system_supervisor = proplists:get_value(system_sup, Sups),
- sub_system_supervisor = proplists:get_value(subsystem_sup, Sups),
- connection_supervisor = proplists:get_value(connection_sup, Sups)
- }
- of
- C ->
- #data{connection_state=C}
- catch
- _:_ ->
- #data{connection_state=#connection{}}
- end,
- gen_statem:enter_loop(?MODULE,
- [],
- {init_error,Error},
- D#data{socket=Socket})
- end.
-
-
-init([Role,Socket,Opts]) ->
+init([Role, Socket, Opts]) when Role==client ; Role==server ->
case inet:peername(Socket) of
{ok, PeerAddr} ->
- {Protocol, Callback, CloseTag} = ?GET_OPT(transport, Opts),
- C = #connection{channel_cache = ssh_client_channel:cache_create(),
- channel_id_seed = 0,
- requests = [],
- options = Opts},
- D0 = #data{starter = ?GET_INTERNAL_OPT(user_pid, Opts),
- connection_state = C,
- socket = Socket,
- transport_protocol = Protocol,
- transport_cb = Callback,
- transport_close_tag = CloseTag,
- ssh_params = init_ssh_record(Role, Socket, PeerAddr, Opts)
- },
- D = case Role of
- client ->
- D0;
- server ->
- Sups = ?GET_INTERNAL_OPT(supervisors, Opts),
- D0#data{connection_state =
- C#connection{cli_spec = ?GET_OPT(ssh_cli, Opts, {ssh_cli,[?GET_OPT(shell, Opts)]}),
- exec = ?GET_OPT(exec, Opts),
- system_supervisor = proplists:get_value(system_sup, Sups),
- sub_system_supervisor = proplists:get_value(subsystem_sup, Sups),
- connection_supervisor = proplists:get_value(connection_sup, Sups)
- }}
- end,
- {ok, {hello,Role}, D};
-
+ try
+ {Protocol, Callback, CloseTag} = ?GET_OPT(transport, Opts),
+ D = #data{starter = ?GET_INTERNAL_OPT(user_pid, Opts),
+ socket = Socket,
+ transport_protocol = Protocol,
+ transport_cb = Callback,
+ transport_close_tag = CloseTag,
+ ssh_params = init_ssh_record(Role, Socket, PeerAddr, Opts),
+ connection_state = init_connection_record(Role, Opts)
+ },
+ process_flag(trap_exit, true),
+ {ok, {hello,Role}, D}
+ catch
+ _:Error ->
+ {stop, Error}
+ end;
+
{error,Error} ->
{stop, Error}
end.
+%%%----------------------------------------------------------------
+%%% Connection start and initalization helpers
+
+init_connection_record(Role, Opts) ->
+ Sups = ?GET_INTERNAL_OPT(supervisors, Opts),
+ C = #connection{channel_cache = ssh_client_channel:cache_create(),
+ channel_id_seed = 0,
+ requests = [],
+ options = Opts,
+ system_supervisor = proplists:get_value(system_sup, Sups),
+ sub_system_supervisor = proplists:get_value(subsystem_sup, Sups),
+ connection_supervisor = proplists:get_value(connection_sup, Sups)
+ },
+ case Role of
+ server ->
+ C#connection{cli_spec =
+ ?GET_OPT(ssh_cli, Opts, {ssh_cli,[?GET_OPT(shell, Opts)]}),
+ exec =
+ ?GET_OPT(exec, Opts)};
+ client ->
+ C
+ end.
+
init_ssh_record(Role, Socket, Opts) ->
@@ -592,6 +553,42 @@ init_ssh_record(Role, Socket, PeerAddr, Opts) ->
end.
+socket_control(Socket, Pid, Options) ->
+ {_, Callback, _} = ?GET_OPT(transport, Options),
+ case Callback:controlling_process(Socket, Pid) of
+ ok ->
+ gen_statem:cast(Pid, socket_control);
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+
+handshake(Pid, Ref, Timeout) ->
+ receive
+ ssh_connected ->
+ erlang:demonitor(Ref),
+ {ok, Pid};
+ {Pid, not_connected, Reason} ->
+ {error, Reason};
+ {Pid, user_password} ->
+ Pass = io:get_password(),
+ Pid ! Pass,
+ handshake(Pid, Ref, Timeout);
+ {Pid, question} ->
+ Answer = io:get_line(""),
+ Pid ! Answer,
+ handshake(Pid, Ref, Timeout);
+ {'DOWN', _, process, Pid, {shutdown, Reason}} ->
+ {error, Reason};
+ {'DOWN', _, process, Pid, Reason} ->
+ {error, Reason};
+ {'EXIT',_,Reason} ->
+ stop(Pid),
+ {error, {exit,Reason}}
+ after Timeout ->
+ ssh_connection_handler:stop(Pid),
+ {error, timeout}
+ end.
%%====================================================================
%% gen_statem callbacks
@@ -1805,9 +1799,15 @@ terminate(Reason, StateName, D0) ->
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-format_status(normal, [_, _StateName, D]) ->
+format_status(A, B) ->
+ try format_status0(A, B)
+ catch
+ _:_ -> "????"
+ end.
+
+format_status0(normal, [_PDict, _StateName, D]) ->
[{data, [{"State", D}]}];
-format_status(terminate, [_, _StateName, D]) ->
+format_status0(terminate, [_, _StateName, D]) ->
[{data, [{"State", clean(D)}]}].
@@ -1882,15 +1882,6 @@ code_change(_OldVsn, StateName, State, _Extra) ->
%%--------------------------------------------------------------------
%% Starting
-start_the_connection_child(UserPid, Role, Socket, Options0) ->
- Sups = ?GET_INTERNAL_OPT(supervisors, Options0),
- ConnectionSup = proplists:get_value(connection_sup, Sups),
- Options = ?PUT_INTERNAL_OPT({user_pid,UserPid}, Options0),
- InitArgs = [Role, Socket, Options],
- {ok, Pid} = ssh_connection_sup:start_child(ConnectionSup, InitArgs),
- ok = socket_control(Socket, Pid, Options), % transfer the Socket ownership in a controlled way.
- Pid.
-
%%--------------------------------------------------------------------
%% Stopping
@@ -1898,20 +1889,15 @@ stop_subsystem(#data{ssh_params =
#ssh{role = Role},
connection_state =
#connection{system_supervisor = SysSup,
- sub_system_supervisor = SubSysSup,
- options = Opts}
+ sub_system_supervisor = SubSysSup}
}) when is_pid(SysSup) andalso is_pid(SubSysSup) ->
C = self(),
spawn(fun() ->
wait_until_dead(C, 10000),
- case {Role, ?GET_INTERNAL_OPT(connected_socket,Opts,non_socket_started)} of
- {server, non_socket_started} ->
+ case Role of
+ server ->
ssh_system_sup:stop_subsystem(SysSup, SubSysSup);
- {client, non_socket_started} ->
- ssh_system_sup:stop_system(Role, SysSup);
- {server, _Socket} ->
- ssh_system_sup:stop_system(Role, SysSup);
- {client, _Socket} ->
+ client ->
ssh_system_sup:stop_subsystem(SysSup, SubSysSup),
wait_until_dead(SubSysSup, 1000),
sshc_sup:stop_system(SysSup)
@@ -2496,44 +2482,6 @@ start_channel_request_timer(Channel, From, Time) ->
erlang:send_after(Time, self(), {timeout, {Channel, From}}).
%%%----------------------------------------------------------------
-%%% Connection start and initialization helpers
-
-socket_control(Socket, Pid, Options) ->
- {_, Callback, _} = ?GET_OPT(transport, Options),
- case Callback:controlling_process(Socket, Pid) of
- ok ->
- gen_statem:cast(Pid, socket_control);
- {error, Reason} ->
- {error, Reason}
- end.
-
-handshake(Pid, Ref, Timeout) ->
- receive
- ssh_connected ->
- erlang:demonitor(Ref),
- {ok, Pid};
- {Pid, not_connected, Reason} ->
- {error, Reason};
- {Pid, user_password} ->
- Pass = io:get_password(),
- Pid ! Pass,
- handshake(Pid, Ref, Timeout);
- {Pid, question} ->
- Answer = io:get_line(""),
- Pid ! Answer,
- handshake(Pid, Ref, Timeout);
- {'DOWN', _, process, Pid, {shutdown, Reason}} ->
- {error, Reason};
- {'DOWN', _, process, Pid, Reason} ->
- {error, Reason};
- {'EXIT',_,Reason} ->
- stop(Pid),
- {error, {exit,Reason}}
- after Timeout ->
- stop(Pid),
- {error, timeout}
- end.
-
update_inet_buffers(Socket) ->
try
{ok, BufSzs0} = inet:getopts(Socket, [sndbuf,recbuf]),
@@ -2557,7 +2508,7 @@ ssh_dbg_flags(connection_events) -> [c];
ssh_dbg_flags(terminate) -> [c];
ssh_dbg_flags(disconnect) -> [c].
-ssh_dbg_on(connections) -> dbg:tp(?MODULE, init_connection_handler, 3, x),
+ssh_dbg_on(connections) -> dbg:tp(?MODULE, init, 1, x),
ssh_dbg_on(terminate);
ssh_dbg_on(connection_events) -> dbg:tp(?MODULE, handle_event, 4, x);
ssh_dbg_on(connection_handshake) -> dbg:tpl(?MODULE, handshake, 3, x);
@@ -2577,11 +2528,11 @@ ssh_dbg_off(renegotiation) -> dbg:ctpl(?MODULE, init_renegotiate_timers, 3),
dbg:ctpg(?MODULE, renegotiate, 1);
ssh_dbg_off(connection_events) -> dbg:ctpg(?MODULE, handle_event, 4);
ssh_dbg_off(connection_handshake) -> dbg:ctpl(?MODULE, handshake, 3);
-ssh_dbg_off(connections) -> dbg:ctpg(?MODULE, init_connection_handler, 3),
+ssh_dbg_off(connections) -> dbg:ctpg(?MODULE, init, 1),
ssh_dbg_off(terminate).
-ssh_dbg_format(connections, {call, {?MODULE,init_connection_handler, [Role, Sock, Opts]}}) ->
+ssh_dbg_format(connections, {call, {?MODULE,init, [[Role, Sock, Opts]]}}) ->
DefaultOpts = ssh_options:handle_options(Role,[]),
ExcludedKeys = [internal_options, user_options],
NonDefaultOpts =
diff --git a/lib/ssh/src/sshc_sup.erl b/lib/ssh/src/sshc_sup.erl
index e582733de8..bbf3d16440 100644
--- a/lib/ssh/src/sshc_sup.erl
+++ b/lib/ssh/src/sshc_sup.erl
@@ -20,13 +20,15 @@
%%
%%----------------------------------------------------------------------
-%% Purpose: The ssh client subsystem supervisor
+%% Purpose: The ssh client top supervisor
%%----------------------------------------------------------------------
-module(sshc_sup).
-behaviour(supervisor).
+-include("ssh.hrl").
+
-export([start_link/0,
start_child/4,
start_system_subsystem/4,
@@ -43,7 +45,7 @@
%%% API
%%%=========================================================================
start_link() ->
- supervisor:start_link({local,?MODULE}, ?MODULE, []).
+ supervisor:start_link({local,?SSHC_SUP}, ?MODULE, []).
start_child(Address, Port, Profile, Options) ->
case ssh_system_sup:system_supervisor(Address, Port, Profile) of
@@ -82,7 +84,8 @@ init(_) ->
start => {ssh_controller, start_link, [client, client_controller]},
restart => permanent,
type => worker
- }],
+ }
+ ],
{ok, {SupFlags,ChildSpecs}}.
%%%=========================================================================
diff --git a/lib/ssh/src/sshd_sup.erl b/lib/ssh/src/sshd_sup.erl
index b716b66ec7..bda156223e 100644
--- a/lib/ssh/src/sshd_sup.erl
+++ b/lib/ssh/src/sshd_sup.erl
@@ -17,10 +17,10 @@
%%
%% %CopyrightEnd%
%%
+
%%
%%----------------------------------------------------------------------
-%% Purpose: The top supervisor for ssh servers hangs under
-%% ssh_sup.
+%% Purpose: The ssh daemon top supervisor
%%----------------------------------------------------------------------
-module(sshd_sup).
@@ -30,10 +30,11 @@
-include("ssh.hrl").
-export([start_link/0,
- start_child/4,
+ start_child/4,
+ start_system_subsystem/4,
stop_child/1,
stop_child/3
-]).
+ ]).
%% Supervisor callback
-export([init/1]).
@@ -44,8 +45,6 @@
%%% API
%%%=========================================================================
start_link() ->
- %% No children are start now. We wait until the user calls ssh:daemon
- %% and uses start_child/4 to create the children
supervisor:start_link({local,?SSHD_SUP}, ?MODULE, []).
start_child(Address, Port, Profile, Options) ->
@@ -62,6 +61,11 @@ start_child(Address, Port, Profile, Options) ->
{ok,Pid}
end.
+start_system_subsystem(Host, Port, Profile, Options) ->
+ ssh_controller:start_system_subsystem(daemon_controller, ?MODULE, Host, Port, Profile, Options,
+ child_spec(Host, Port, Profile, Options)
+ ).
+
stop_child(ChildId) when is_tuple(ChildId) ->
supervisor:terminate_child(?SSHD_SUP, ChildId);
stop_child(ChildPid) when is_pid(ChildPid)->
@@ -80,7 +84,11 @@ init(_) ->
intensity => 10,
period => 3600
},
- ChildSpecs = [
+ ChildSpecs = [#{id => daemon_controller,
+ start => {ssh_controller, start_link, [server, daemon_controller]},
+ restart => permanent,
+ type => worker
+ }
],
{ok, {SupFlags,ChildSpecs}}.
diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl
index 8ad405b1d7..fa9dbe1c7d 100644
--- a/lib/ssh/test/ssh_sup_SUITE.erl
+++ b/lib/ssh/test/ssh_sup_SUITE.erl
@@ -115,7 +115,7 @@ default_tree(Config) when is_list(Config) ->
{value, {sshd_sup, _,supervisor,[sshd_sup]}} =
lists:keysearch(sshd_sup, 1, TopSupChildren),
?wait_match([{client_controller,_,worker,_}], supervisor:which_children(sshc_sup)),
- ?wait_match([], supervisor:which_children(sshd_sup)).
+ ?wait_match([{daemon_controller,_,worker,_}], supervisor:which_children(sshd_sup)).
%%-------------------------------------------------------------------------
sshc_subtree(Config) when is_list(Config) ->
@@ -164,14 +164,16 @@ sshd_subtree(Config) when is_list(Config) ->
ct:log("Expect HostIP=~p, Port=~p, Daemon=~p",[HostIP,Port,Daemon]),
?wait_match([{{server,ssh_system_sup, ListenIP, Port, ?DEFAULT_PROFILE},
Daemon, supervisor,
- [ssh_system_sup]}],
+ [ssh_system_sup]},
+ {daemon_controller,_,worker,_}
+ ],
supervisor:which_children(sshd_sup),
[ListenIP,Daemon]),
true = ssh_test_lib:match_ip(HostIP, ListenIP),
check_sshd_system_tree(Daemon, HostIP, Port, Config),
ssh:stop_daemon(HostIP, Port),
ct:sleep(?WAIT_FOR_SHUTDOWN),
- ?wait_match([], supervisor:which_children(sshd_sup)).
+ ?wait_match([{daemon_controller,_,worker,_}], supervisor:which_children(sshd_sup)).
%%-------------------------------------------------------------------------
sshd_subtree_profile(Config) when is_list(Config) ->
@@ -186,14 +188,15 @@ sshd_subtree_profile(Config) when is_list(Config) ->
ct:log("Expect HostIP=~p, Port=~p, Profile=~p, Daemon=~p",[HostIP,Port,Profile,Daemon]),
?wait_match([{{server,ssh_system_sup, ListenIP,Port,Profile},
Daemon, supervisor,
- [ssh_system_sup]}],
+ [ssh_system_sup]},
+ {daemon_controller,_,worker,_}],
supervisor:which_children(sshd_sup),
[ListenIP,Daemon]),
true = ssh_test_lib:match_ip(HostIP, ListenIP),
check_sshd_system_tree(Daemon, HostIP, Port, Config),
ssh:stop_daemon(HostIP, Port, Profile),
ct:sleep(?WAIT_FOR_SHUTDOWN),
- ?wait_match([], supervisor:which_children(sshd_sup)).
+ ?wait_match([{daemon_controller,_,worker,_}], supervisor:which_children(sshd_sup)).
%%-------------------------------------------------------------------------
killed_acceptor_restarts(Config) ->
--
2.26.2