summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Nilsson <hans@erlang.org>2019-09-05 12:03:36 +0200
committerGitHub <noreply@github.com>2019-09-05 12:03:36 +0200
commit41131a8c69399f37a4af5c92b53772a321cf17b0 (patch)
treeff23c08745be8ca8f9fa1e598f690f4e41433406
parentb74f67dc358c81bb701d21b464725e0b1714ae0c (diff)
parentae479fdd153860001f5644d76154ab38d59d0edc (diff)
downloaderlang-41131a8c69399f37a4af5c92b53772a321cf17b0.tar.gz
Merge pull request #2368 from HansN/hans/ssh/client_sup/OTP-16026
Supervisor tree for SSH client side
-rw-r--r--lib/ssh/src/Makefile4
-rw-r--r--lib/ssh/src/ssh.app.src2
-rw-r--r--lib/ssh/src/ssh.erl47
-rw-r--r--lib/ssh/src/ssh_channel_sup.erl (renamed from lib/ssh/src/ssh_server_channel_sup.erl)40
-rw-r--r--lib/ssh/src/ssh_connection.erl45
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl118
-rw-r--r--lib/ssh/src/ssh_info.erl2
-rw-r--r--lib/ssh/src/ssh_sftp.erl15
-rw-r--r--lib/ssh/src/ssh_subsystem_sup.erl29
-rw-r--r--lib/ssh/src/ssh_system_sup.erl27
-rw-r--r--lib/ssh/src/sshc_sup.erl46
-rw-r--r--lib/ssh/src/sshd_sup.erl2
-rw-r--r--lib/ssh/test/ssh_sup_SUITE.erl19
13 files changed, 248 insertions, 148 deletions
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index 9627b70eeb..46bf6332e5 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -55,6 +55,7 @@ MODULES= \
ssh_app \
ssh_auth\
ssh_bits \
+ ssh_channel_sup \
ssh_cli \
ssh_connection \
ssh_connection_handler \
@@ -66,7 +67,6 @@ MODULES= \
ssh_message \
ssh_no_io \
ssh_options \
- ssh_server_channel_sup \
ssh_sftp \
ssh_sftpd \
ssh_sftpd_file\
@@ -171,7 +171,7 @@ $(EBIN)/ssh_connection_handler.$(EMULATOR): ssh_connection_handler.erl ssh.hrl \
$(EBIN)/ssh_shell.$(EMULATOR): ssh_shell.erl ssh_connect.hrl
$(EBIN)/ssh_system_sup.$(EMULATOR): ssh_system_sup.erl ssh.hrl
$(EBIN)/ssh_subsystem_sup.$(EMULATOR): ssh_subsystem_sup.erl
-$(EBIN)/ssh_server_channel_sup.$(EMULATOR): ssh_server_channel_sup.erl
+$(EBIN)/ssh_channel_sup.$(EMULATOR): ssh_channel_sup.erl ssh.hrl
$(EBIN)/ssh_acceptor_sup.$(EMULATOR): ssh_acceptor_sup.erl ssh.hrl
$(EBIN)/ssh_acceptor.$(EMULATOR): ssh_acceptor.erl ssh.hrl
$(EBIN)/ssh_app.$(EMULATOR): ssh_app.erl
diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src
index 2193c14611..379cde23e3 100644
--- a/lib/ssh/src/ssh.app.src
+++ b/lib/ssh/src/ssh.app.src
@@ -11,6 +11,7 @@
ssh_auth,
ssh_message,
ssh_bits,
+ ssh_channel_sup,
ssh_cli,
ssh_client_channel,
ssh_client_key_api,
@@ -28,7 +29,6 @@
ssh_info,
ssh_no_io,
ssh_server_channel,
- ssh_server_channel_sup,
ssh_server_key_api,
ssh_sftp,
ssh_sftpd,
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 32f10c797d..bf4b0433d0 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -127,15 +127,13 @@ connect(Socket, UserOptions, NegotiationTimeout) when is_port(Socket),
{error, Error} ->
{error, Error};
Options ->
- case valid_socket_to_use(Socket, ?GET_OPT(transport,Options)) of
- ok ->
- {ok, {Host,_Port}} = inet:peername(Socket),
- Opts = ?PUT_INTERNAL_OPT([{user_pid,self()}, {host,Host}], Options),
- ssh_connection_handler:start_connection(client, Socket, Opts, NegotiationTimeout);
- {error,SockError} ->
- {error,SockError}
- end
- end;
+ case valid_socket_to_use(Socket, ?GET_OPT(transport,Options)) of
+ ok ->
+ connect_socket(Socket, Options, NegotiationTimeout);
+ {error,SockError} ->
+ {error,SockError}
+ end
+ end;
connect(Host, Port, Options) when is_integer(Port),
Port>0,
@@ -149,9 +147,9 @@ connect(Host, Port, Options) when is_integer(Port),
Options :: client_options(),
NegotiationTimeout :: timeout().
-connect(Host0, Port, UserOptions, Timeout) when is_integer(Port),
- Port>0,
- is_list(UserOptions) ->
+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;
@@ -162,8 +160,7 @@ connect(Host0, Port, UserOptions, Timeout) when is_integer(Port),
Host = mangle_connect_address(Host0, SocketOpts),
try Transport:connect(Host, Port, SocketOpts, ConnectionTimeout) of
{ok, Socket} ->
- Opts = ?PUT_INTERNAL_OPT([{user_pid,self()}, {host,Host}], Options),
- ssh_connection_handler:start_connection(client, Socket, Opts, Timeout);
+ connect_socket(Socket, Options, NegotiationTimeout);
{error, Reason} ->
{error, Reason}
catch
@@ -174,6 +171,22 @@ connect(Host0, Port, UserOptions, Timeout) when is_integer(Port),
end
end.
+
+connect_socket(Socket, Options0, NegotiationTimeout) ->
+ {ok, {Host,Port}} = inet:sockname(Socket),
+ Profile = ?GET_OPT(profile, Options0),
+ {ok, SystemSup} = sshc_sup:start_child(Host, Port, Profile, Options0),
+ {ok, SubSysSup} = ssh_system_sup:start_subsystem(SystemSup, client, Host, Port, Profile, Options0),
+ ConnectionSup = ssh_system_sup:connection_supervisor(SystemSup),
+ Opts = ?PUT_INTERNAL_OPT([{user_pid,self()},
+ {host,Host},
+ {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() .
@@ -382,7 +395,7 @@ stop_listener(Address, Port, Profile) ->
-spec stop_daemon(DaemonRef::daemon_ref()) -> ok.
stop_daemon(SysSup) ->
- ssh_system_sup:stop_system(SysSup).
+ ssh_system_sup:stop_system(server, SysSup).
-spec stop_daemon(inet:ip_address(), inet:port_number()) -> ok.
@@ -395,11 +408,11 @@ stop_daemon(Address, Port) ->
stop_daemon(any, Port, Profile) ->
map_ip(fun(IP) ->
- ssh_system_sup:stop_system(IP, Port, Profile)
+ ssh_system_sup:stop_system(server, IP, Port, Profile)
end, [{0,0,0,0},{0,0,0,0,0,0,0,0}]);
stop_daemon(Address, Port, Profile) ->
map_ip(fun(IP) ->
- ssh_system_sup:stop_system(IP, Port, Profile)
+ ssh_system_sup:stop_system(server, IP, Port, Profile)
end, {address,Address}).
%%--------------------------------------------------------------------
diff --git a/lib/ssh/src/ssh_server_channel_sup.erl b/lib/ssh/src/ssh_channel_sup.erl
index ff74061bb3..4b36c8a5a0 100644
--- a/lib/ssh/src/ssh_server_channel_sup.erl
+++ b/lib/ssh/src/ssh_channel_sup.erl
@@ -22,11 +22,12 @@
%%----------------------------------------------------------------------
%% Purpose: Ssh channel supervisor.
%%----------------------------------------------------------------------
--module(ssh_server_channel_sup).
+-module(ssh_channel_sup).
-behaviour(supervisor).
+-include("ssh.hrl").
--export([start_link/1, start_child/5]).
+-export([start_link/1, start_child/8]).
%% Supervisor callback
-export([init/1]).
@@ -37,15 +38,36 @@
start_link(Args) ->
supervisor:start_link(?MODULE, [Args]).
-start_child(Sup, Callback, Id, Args, Exec) ->
+
+start_child(client, ChannelSup, ConnRef, Callback, Id, Args, Exec, _Opts) when is_pid(ConnRef) ->
+ start_the_child(ssh_client_channel, ChannelSup, ConnRef, Callback, Id, Args, Exec);
+start_child(server, ChannelSup, ConnRef, Callback, Id, Args, Exec, Opts) when is_pid(ConnRef) ->
+ case max_num_channels_not_exceeded(ChannelSup, Opts) of
+ true ->
+ start_the_child(ssh_server_channel, ChannelSup, ConnRef, Callback, Id, Args, Exec);
+ false ->
+ {error, max_num_channels_exceeded}
+ end.
+
+
+start_the_child(ChanMod, ChannelSup, ConnRef, Callback, Id, Args, Exec) ->
ChildSpec =
#{id => make_ref(),
- start => {ssh_server_channel, start_link, [self(), Id, Callback, Args, Exec]},
+ start => {ChanMod, start_link, [ConnRef, Id, Callback, Args, Exec]},
restart => temporary,
type => worker,
- modules => [ssh_server_channel]
+ modules => [ChanMod]
},
- supervisor:start_child(Sup, ChildSpec).
+ case supervisor:start_child(ChannelSup, ChildSpec) of
+ {ok, Pid} ->
+ {ok, Pid};
+ {ok, Pid, _Info} ->
+ {ok,Pid};
+ {error, {Error,_Info}} ->
+ {error, Error};
+ {error, Error} ->
+ {error, Error}
+ end.
%%%=========================================================================
%%% Supervisor callback
@@ -60,3 +82,9 @@ init(_Args) ->
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
+max_num_channels_not_exceeded(ChannelSup, Opts) ->
+ MaxNumChannels = ?GET_OPT(max_channels, Opts),
+ NumChannels = length([x || {_,_,worker,[ssh_server_channel]} <-
+ supervisor:which_children(ChannelSup)]),
+ %% Note that NumChannels is BEFORE starting a new one
+ NumChannels < MaxNumChannels.
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index c5316bf133..067e5230c9 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -648,19 +648,14 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
#channel{remote_id=RemoteId} = Channel =
ssh_client_channel:cache_lookup(Cache, ChannelId),
Reply =
- try
- start_subsystem(SsName, Connection, Channel,
- {subsystem, ChannelId, WantReply, binary_to_list(SsName)})
- of
+ case start_subsystem(SsName, Connection, Channel,
+ {subsystem, ChannelId, WantReply, binary_to_list(SsName)}) of
{ok, Pid} ->
erlang:monitor(process, Pid),
ssh_client_channel:cache_update(Cache, Channel#channel{user=Pid}),
channel_success_msg(RemoteId);
{error,_Error} ->
channel_failure_msg(RemoteId)
- catch
- _:_ ->
- channel_failure_msg(RemoteId)
end,
{[{connection_reply,Reply}], Connection};
@@ -921,7 +916,7 @@ start_cli(#connection{options = Options,
no_cli ->
{error, cli_disabled};
{CbModule, Args} ->
- start_channel(CbModule, ChannelId, Args, SubSysSup, Exec, Options)
+ ssh_subsystem_sup:start_channel(server, SubSysSup, self(), CbModule, ChannelId, Args, Exec, Options)
end.
@@ -931,37 +926,15 @@ start_subsystem(BinName, #connection{options = Options,
Name = binary_to_list(BinName),
case check_subsystem(Name, Options) of
{Callback, Opts} when is_atom(Callback), Callback =/= none ->
- start_channel(Callback, ChannelId, Opts, SubSysSup, Options);
- {Other, _} when Other =/= none ->
+ ssh_subsystem_sup:start_channel(server, SubSysSup, self(), Callback, ChannelId, Opts, undefined, Options);
+ {none, _} ->
+ {error, bad_subsystem};
+ {_, _} ->
{error, legacy_option_not_supported}
end.
%%% Helpers for starting cli/subsystems
-start_channel(Cb, Id, Args, SubSysSup, Opts) ->
- start_channel(Cb, Id, Args, SubSysSup, undefined, Opts).
-
-start_channel(Cb, Id, Args, SubSysSup, Exec, Opts) ->
- ChannelSup = ssh_subsystem_sup:channel_supervisor(SubSysSup),
- case max_num_channels_not_exceeded(ChannelSup, Opts) of
- true ->
- case ssh_server_channel_sup:start_child(ChannelSup, Cb, Id, Args, Exec) of
- {error,{Error,_Info}} ->
- throw(Error);
- Others ->
- Others
- end;
- false ->
- throw(max_num_channels_exceeded)
- end.
-
-max_num_channels_not_exceeded(ChannelSup, Opts) ->
- MaxNumChannels = ?GET_OPT(max_channels, Opts),
- NumChannels = length([x || {_,_,worker,[ssh_server_channel]} <-
- supervisor:which_children(ChannelSup)]),
- %% Note that NumChannels is BEFORE starting a new one
- NumChannels < MaxNumChannels.
-
check_subsystem("sftp"= SsName, Options) ->
case ?GET_OPT(subsystems, Options) of
no_subsys -> % FIXME: Can 'no_subsys' ever be matched?
@@ -1300,13 +1273,13 @@ handle_cli_msg(C0, ChId, Reply0) ->
Ch0 = ssh_client_channel:cache_lookup(Cache, ChId),
case Ch0#channel.user of
undefined ->
- case (catch start_cli(C0, ChId)) of
+ case start_cli(C0, ChId) of
{ok, Pid} ->
erlang:monitor(process, Pid),
Ch = Ch0#channel{user = Pid},
ssh_client_channel:cache_update(Cache, Ch),
reply_msg(Ch, C0, Reply0);
- _Other ->
+ {error, _Error} ->
Reply = {connection_reply, channel_failure_msg(Ch0#channel.remote_id)},
{[Reply], C0}
end;
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index e984cbb21b..cf8cde443f 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -48,6 +48,7 @@
-export([start_connection/4,
available_hkey_algorithms/2,
open_channel/6,
+ start_channel/5,
request/6, request/7,
reply_request/3,
send/5,
@@ -126,35 +127,29 @@ stop(ConnectionHandler)->
timeout()
) -> {ok, connection_ref()} | {error, term()}.
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-start_connection(client = Role, Socket, Options, Timeout) ->
+start_connection(Role, Socket, Options, Timeout) ->
try
- {ok, Pid} = sshc_sup:start_child([Role, Socket, Options]),
- ok = socket_control(Socket, Pid, Options),
- handshake(Pid, erlang:monitor(process,Pid), Timeout)
- catch
- exit:{noproc, _} ->
- {error, ssh_not_started};
- _:Error ->
- {error, Error}
- end;
-
-start_connection(server = Role, Socket, Options, Timeout) ->
- try
- case ?GET_OPT(parallel_login, Options) of
- true ->
- HandshakerPid =
- spawn_link(fun() ->
- receive
- {do_handshake, Pid} ->
- handshake(Pid, erlang:monitor(process,Pid), Timeout)
- 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
+ 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() ->
+ receive
+ {do_handshake, Pid} ->
+ handshake(Pid, erlang:monitor(process,Pid), Timeout)
+ 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};
@@ -176,6 +171,8 @@ disconnect(Code, DetailedText, Module, Line) ->
[{next_event, internal, {send_disconnect, Code, DetailedText, Module, Line}}]}).
%%--------------------------------------------------------------------
+%%% Open a channel in the connection to the peer, that is, do the ssh
+%%% signalling with the peer.
-spec open_channel(connection_ref(),
string(),
iodata(),
@@ -195,6 +192,18 @@ open_channel(ConnectionHandler,
Timeout}).
%%--------------------------------------------------------------------
+%%% Start a channel handling process in the superviser tree
+-spec start_channel(connection_ref(), atom(), channel_id(), list(), term()) ->
+ {ok, pid()} | {error, term()}.
+
+%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+start_channel(ConnectionHandler, CallbackModule, ChannelId, Args, Exec) ->
+ {ok, {SubSysSup,Role,Opts}} = call(ConnectionHandler, get_misc),
+ ssh_subsystem_sup:start_channel(Role, SubSysSup,
+ ConnectionHandler, CallbackModule, ChannelId,
+ Args, Exec, Opts).
+
+%%--------------------------------------------------------------------
-spec request(connection_ref(),
pid(),
channel_id(),
@@ -378,8 +387,21 @@ alg(ConnectionHandler) ->
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
init_connection_handler(Role, Socket, Opts) ->
case init([Role, Socket, Opts]) of
- {ok, StartState, D} ->
+ {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,
@@ -1247,6 +1269,13 @@ handle_event({call,From}, {eof, ChannelId}, StateName, D0)
{keep_state, D0, [{reply,From,{error,closed}}]}
end;
+handle_event({call,From}, get_misc, StateName,
+ #data{connection_state = #connection{options = Opts}} = D) when ?CONNECTED(StateName) ->
+ Sups = ?GET_INTERNAL_OPT(supervisors, Opts),
+ SubSysSup = proplists:get_value(subsystem_sup, Sups),
+ Reply = {ok, {SubSysSup, role(StateName), Opts}},
+ {keep_state, D, [{reply,From,Reply}]};
+
handle_event({call,From},
{open, ChannelPid, Type, InitialWindowSize, MaxPacketSize, Data, Timeout},
StateName,
@@ -1661,17 +1690,36 @@ 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),
- {ok, Pid} = ssh_connection_sup:start_child(ConnectionSup, [Role, Socket, Options]),
- ok = socket_control(Socket, Pid, Options),
+ 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
-stop_subsystem(#data{connection_state =
+stop_subsystem(#data{ssh_params =
+ #ssh{role = Role},
+ connection_state =
#connection{system_supervisor = SysSup,
- sub_system_supervisor = SubSysSup}}) when is_pid(SubSysSup) ->
- ssh_system_sup:stop_subsystem(SysSup, SubSysSup);
+ sub_system_supervisor = SubSysSup}
+ }) when is_pid(SysSup) andalso is_pid(SubSysSup) ->
+ process_flag(trap_exit, false),
+ C = self(),
+ spawn(fun() ->
+ Mref = erlang:monitor(process, C),
+ receive
+ {'DOWN', Mref, process, C, _Info} -> ok
+ after
+ 10000 -> ok
+ end,
+ case Role of
+ client ->
+ ssh_system_sup:stop_system(Role, SysSup);
+ _ ->
+ ssh_system_sup:stop_subsystem(SysSup, SubSysSup)
+ end
+ end);
stop_subsystem(_) ->
ok.
@@ -1763,6 +1811,8 @@ call(FsmPid, Event, Timeout) ->
exit:{normal, _R} ->
{error, closed};
exit:{{shutdown, _R},_} ->
+ {error, closed};
+ exit:{shutdown, _R} ->
{error, closed}
end.
diff --git a/lib/ssh/src/ssh_info.erl b/lib/ssh/src/ssh_info.erl
index 79cd95e422..11f4bc51e6 100644
--- a/lib/ssh/src/ssh_info.erl
+++ b/lib/ssh/src/ssh_info.erl
@@ -140,7 +140,7 @@ print_system_sup({{ssh_acceptor_sup,_LocalHost,_LocalPort,_Profile}, Pid, superv
-print_channels({{server,ssh_server_channel_sup,_,_},Pid,supervisor,[ssh_server_channel_sup]}) when is_pid(Pid) ->
+print_channels({{server,ssh_channel_sup,_,_},Pid,supervisor,[ssh_channel_sup]}) when is_pid(Pid) ->
Children = supervisor:which_children(Pid),
ChannelPids = [P || {R,P,worker,[ssh_server_channel]} <- Children,
is_pid(P),
diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl
index 4b6e187c3a..305c1c31fd 100644
--- a/lib/ssh/src/ssh_sftp.erl
+++ b/lib/ssh/src/ssh_sftp.erl
@@ -162,8 +162,8 @@ start_channel(Cm, UserOptions) when is_pid(Cm) ->
{_SshOpts, ChanOpts, SftpOpts} = handle_options(UserOptions),
case ssh_xfer:attach(Cm, [], ChanOpts) of
{ok, ChannelId, Cm} ->
- case ssh_client_channel:start(Cm, ChannelId,
- ?MODULE, [Cm, ChannelId, SftpOpts]) of
+ case ssh_connection_handler:start_channel(Cm, ?MODULE, ChannelId,
+ [Cm,ChannelId,SftpOpts], undefined) of
{ok, Pid} ->
case wait_for_version_negotiation(Pid, Timeout) of
ok ->
@@ -172,9 +172,7 @@ start_channel(Cm, UserOptions) when is_pid(Cm) ->
TimeOut
end;
{error, Reason} ->
- {error, format_channel_start_error(Reason)};
- ignore ->
- {error, ignore}
+ {error, format_channel_start_error(Reason)}
end;
Error ->
Error
@@ -200,7 +198,8 @@ start_channel(Host, Port, UserOptions) ->
proplists:get_value(timeout, SftpOpts, infinity)),
case ssh_xfer:connect(Host, Port, SshOpts, ChanOpts, Timeout) of
{ok, ChannelId, Cm} ->
- case ssh_client_channel:start(Cm, ChannelId, ?MODULE, [Cm,ChannelId,SftpOpts]) of
+ case ssh_connection_handler:start_channel(Cm, ?MODULE, ChannelId,
+ [Cm,ChannelId,SftpOpts], undefined) of
{ok, Pid} ->
case wait_for_version_negotiation(Pid, Timeout) of
ok ->
@@ -209,9 +208,7 @@ start_channel(Host, Port, UserOptions) ->
TimeOut
end;
{error, Reason} ->
- {error, format_channel_start_error(Reason)};
- ignore ->
- {error, ignore}
+ {error, format_channel_start_error(Reason)}
end;
Error ->
Error
diff --git a/lib/ssh/src/ssh_subsystem_sup.erl b/lib/ssh/src/ssh_subsystem_sup.erl
index 5fc8f7e764..db34735e1b 100644
--- a/lib/ssh/src/ssh_subsystem_sup.erl
+++ b/lib/ssh/src/ssh_subsystem_sup.erl
@@ -30,7 +30,8 @@
-export([start_link/5,
connection_supervisor/1,
- channel_supervisor/1
+ channel_supervisor/1,
+ start_channel/8
]).
%% Supervisor callback
@@ -46,9 +47,13 @@ connection_supervisor(SupPid) ->
Children = supervisor:which_children(SupPid),
ssh_connection_sup(Children).
-channel_supervisor(SupPid) ->
+channel_supervisor(SupPid) when is_pid(SupPid) ->
Children = supervisor:which_children(SupPid),
- ssh_server_channel_sup(Children).
+ ssh_channel_sup(Children).
+
+start_channel(Role, SupPid, ConnRef, Callback, Id, Args, Exec, Opts) ->
+ ChannelSup = channel_supervisor(SupPid),
+ ssh_channel_sup:start_child(Role, ChannelSup, ConnRef, Callback, Id, Args, Exec, Opts).
%%%=========================================================================
%%% Supervisor callback
@@ -64,11 +69,9 @@ init([Role, Address, Port, Profile, Options]) ->
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
-child_specs(client, _Address, _Port, _Profile, _Options) ->
- [];
-child_specs(server, Address, Port, Profile, Options) ->
- [ssh_channel_child_spec(server, Address, Port, Profile, Options),
- ssh_connection_child_spec(server, Address, Port, Profile, Options)].
+child_specs(Role, Address, Port, Profile, Options) ->
+ [ssh_channel_child_spec(Role, Address, Port, Profile, Options),
+ ssh_connection_child_spec(Role, Address, Port, Profile, Options)].
ssh_connection_child_spec(Role, Address, Port, _Profile, Options) ->
#{id => id(Role, ssh_connection_sup, Address, Port),
@@ -78,8 +81,8 @@ ssh_connection_child_spec(Role, Address, Port, _Profile, Options) ->
}.
ssh_channel_child_spec(Role, Address, Port, _Profile, Options) ->
- #{id => id(Role, ssh_server_channel_sup, Address, Port),
- start => {ssh_server_channel_sup, start_link, [Options]},
+ #{id => id(Role, ssh_channel_sup, Address, Port),
+ start => {ssh_channel_sup, start_link, [Options]},
restart => temporary,
type => supervisor
}.
@@ -92,10 +95,10 @@ ssh_connection_sup([{_, Child, _, [ssh_connection_sup]} | _]) ->
ssh_connection_sup([_ | Rest]) ->
ssh_connection_sup(Rest).
-ssh_server_channel_sup([{_, Child, _, [ssh_server_channel_sup]} | _]) ->
+ssh_channel_sup([{_, Child, _, [ssh_channel_sup]} | _]) ->
Child;
-ssh_server_channel_sup([_ | Rest]) ->
- ssh_server_channel_sup(Rest).
+ssh_channel_sup([_ | Rest]) ->
+ ssh_channel_sup(Rest).
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index ed7c0c2bd5..3298fd1158 100644
--- a/lib/ssh/src/ssh_system_sup.erl
+++ b/lib/ssh/src/ssh_system_sup.erl
@@ -31,9 +31,9 @@
-include("ssh.hrl").
--export([start_link/4, stop_listener/1,
- stop_listener/3, stop_system/1,
- stop_system/3, system_supervisor/3,
+-export([start_link/5, stop_listener/1,
+ stop_listener/3, stop_system/2,
+ stop_system/4, system_supervisor/3,
subsystem_supervisor/1, channel_supervisor/1,
connection_supervisor/1,
acceptor_supervisor/1, start_subsystem/6,
@@ -45,14 +45,14 @@
%%%=========================================================================
%%% API
%%%=========================================================================
-start_link(Address, Port, Profile, Options) ->
+start_link(Role, Address, Port, Profile, Options) ->
Name = make_name(Address, Port, Profile),
- supervisor:start_link({local, Name}, ?MODULE, [Address, Port, Profile, Options]).
+ supervisor:start_link({local, Name}, ?MODULE, [Role, Address, Port, Profile, Options]).
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
-init([Address, Port, Profile, Options]) ->
+init([server, Address, Port, Profile, Options]) ->
SupFlags = #{strategy => one_for_one,
intensity => 0,
period => 3600
@@ -68,6 +68,14 @@ init([Address, Port, Profile, Options]) ->
_ ->
[]
end,
+ {ok, {SupFlags,ChildSpecs}};
+
+init([client, _Address, _Port, _Profile, _Options]) ->
+ SupFlags = #{strategy => one_for_one,
+ intensity => 0,
+ period => 3600
+ },
+ ChildSpecs = [],
{ok, {SupFlags,ChildSpecs}}.
%%%=========================================================================
@@ -87,11 +95,10 @@ stop_listener(Address, Port, Profile) ->
system_supervisor(Address, Port, Profile)).
-stop_system(SysSup) ->
- catch sshd_sup:stop_child(SysSup),
- ok.
+stop_system(server, SysSup) -> catch sshd_sup:stop_child(SysSup), ok;
+stop_system(client, SysSup) -> catch sshc_sup:stop_child(SysSup), ok.
-stop_system(Address, Port, Profile) ->
+stop_system(server, Address, Port, Profile) ->
catch sshd_sup:stop_child(Address, Port, Profile),
ok.
diff --git a/lib/ssh/src/sshc_sup.erl b/lib/ssh/src/sshc_sup.erl
index 869de244ac..0c9f8be5a9 100644
--- a/lib/ssh/src/sshc_sup.erl
+++ b/lib/ssh/src/sshc_sup.erl
@@ -27,7 +27,10 @@
-behaviour(supervisor).
--export([start_link/0, start_child/1]).
+-export([start_link/0,
+ start_child/4,
+ stop_child/1
+ ]).
%% Supervisor callback
-export([init/1]).
@@ -38,22 +41,45 @@
%%% API
%%%=========================================================================
start_link() ->
- supervisor:start_link({local,?SSHC_SUP}, ?MODULE, []).
+ supervisor:start_link({local,?MODULE}, ?MODULE, []).
-start_child(Args) ->
- supervisor:start_child(?MODULE, Args).
+start_child(Address, Port, Profile, Options) ->
+ %% Here we a new connction on a new Host/EFERMERAL Port/Profile
+ Spec = child_spec(Address, Port, Profile, Options),
+ supervisor:start_child(?MODULE, Spec).
+
+stop_child(ChildId) when is_tuple(ChildId) ->
+ supervisor:terminate_child(?SSHC_SUP, ChildId);
+stop_child(ChildPid) when is_pid(ChildPid)->
+ stop_child(system_name(ChildPid)).
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
init(_) ->
- SupFlags = #{strategy => simple_one_for_one,
+ SupFlags = #{strategy => one_for_one,
intensity => 0,
period => 3600
},
- ChildSpecs = [#{id => undefined, % As simple_one_for_one is used.
- start => {ssh_connection_handler, start_link, []},
- restart => temporary % because there is no way to restart a crashed connection
- }
- ],
+ ChildSpecs = [],
{ok, {SupFlags,ChildSpecs}}.
+
+%%%=========================================================================
+%%% Internal functions
+%%%=========================================================================
+child_spec(Address, Port, Profile, Options) ->
+ #{id => id(Address, Port, Profile),
+ start => {ssh_system_sup, start_link, [client, Address, Port, Profile, Options]},
+ restart => temporary,
+ type => supervisor
+ }.
+
+id(Address, Port, Profile) ->
+ {client, ssh_system_sup, Address, Port, Profile}.
+
+system_name(SysSup) ->
+ case lists:keyfind(SysSup, 2, supervisor:which_children(?SSHC_SUP)) of
+ {Name, SysSup, _, _} -> Name;
+ false -> undefind
+ end.
+
diff --git a/lib/ssh/src/sshd_sup.erl b/lib/ssh/src/sshd_sup.erl
index b5361abba5..b716b66ec7 100644
--- a/lib/ssh/src/sshd_sup.erl
+++ b/lib/ssh/src/sshd_sup.erl
@@ -89,7 +89,7 @@ init(_) ->
%%%=========================================================================
child_spec(Address, Port, Profile, Options) ->
#{id => id(Address, Port, Profile),
- start => {ssh_system_sup, start_link, [Address, Port, Profile, Options]},
+ start => {ssh_system_sup, start_link, [server, Address, Port, Profile, Options]},
restart => temporary,
type => supervisor
}.
diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl
index a0e3d809be..3b5e858c53 100644
--- a/lib/ssh/test/ssh_sup_SUITE.erl
+++ b/lib/ssh/test/ssh_sup_SUITE.erl
@@ -116,18 +116,18 @@ sshc_subtree(Config) when is_list(Config) ->
{user_interaction, false},
{user, ?USER}, {password, ?PASSWD},{user_dir, UserDir}]),
- ?wait_match([{_, _,worker,[ssh_connection_handler]}],
+ ?wait_match([{_, _,supervisor,[ssh_system_sup]}],
supervisor:which_children(sshc_sup)),
{ok, Pid2} = ssh:connect(Host, Port, [{silently_accept_hosts, true},
{user_interaction, false},
{user, ?USER}, {password, ?PASSWD}, {user_dir, UserDir}]),
- ?wait_match([{_,_,worker,[ssh_connection_handler]},
- {_,_,worker,[ssh_connection_handler]}],
+ ?wait_match([{_, _,supervisor,[ssh_system_sup]},
+ {_, _,supervisor,[ssh_system_sup]}],
supervisor:which_children(sshc_sup)),
ssh:close(Pid1),
- ?wait_match([{_,_,worker,[ssh_connection_handler]}],
+ ?wait_match([{_, _,supervisor,[ssh_system_sup]}],
supervisor:which_children(sshc_sup)),
ssh:close(Pid2),
?wait_match([], supervisor:which_children(sshc_sup)).
@@ -217,6 +217,7 @@ killed_acceptor_restarts(Config) ->
ct:log("~s",[lists:flatten(ssh_info:string())]),
%% Make acceptor restart:
+ ct:pal("Expect a SUPERVISOR REPORT with offender {pid,~p}....~n", [AccPid]),
exit(AccPid, kill),
?wait_match(undefined, process_info(AccPid)),
@@ -226,6 +227,8 @@ killed_acceptor_restarts(Config) ->
AccPid1,
500, 30),
+ ct:pal("... now there should not be any SUPERVISOR REPORT.~n", []),
+
true = (AccPid1 =/= AccPid2),
%% Connect second client and check it is alive:
@@ -339,9 +342,9 @@ chk_empty_con_daemon(Daemon) ->
?wait_match([{{server,ssh_connection_sup, _,_},
ConnectionSup, supervisor,
[ssh_connection_sup]},
- {{server,ssh_server_channel_sup,_ ,_},
+ {{server,ssh_channel_sup,_ ,_},
ChannelSup,supervisor,
- [ssh_server_channel_sup]}],
+ [ssh_channel_sup]}],
supervisor:which_children(SubSysSup),
[ConnectionSup,ChannelSup]),
?wait_match([{{ssh_acceptor_sup,_,_,_},_,worker,[ssh_acceptor]}],
@@ -372,9 +375,9 @@ check_sshd_system_tree(Daemon, Config) ->
?wait_match([{{server,ssh_connection_sup, _,_},
ConnectionSup, supervisor,
[ssh_connection_sup]},
- {{server,ssh_server_channel_sup,_ ,_},
+ {{server,ssh_channel_sup,_ ,_},
ChannelSup,supervisor,
- [ssh_server_channel_sup]}],
+ [ssh_channel_sup]}],
supervisor:which_children(SubSysSup),
[ConnectionSup,ChannelSup]),