diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ssh/src/Makefile | 4 | ||||
-rw-r--r-- | lib/ssh/src/ssh.app.src | 2 | ||||
-rw-r--r-- | lib/ssh/src/ssh.erl | 47 | ||||
-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.erl | 45 | ||||
-rw-r--r-- | lib/ssh/src/ssh_connection_handler.erl | 118 | ||||
-rw-r--r-- | lib/ssh/src/ssh_info.erl | 2 | ||||
-rw-r--r-- | lib/ssh/src/ssh_sftp.erl | 15 | ||||
-rw-r--r-- | lib/ssh/src/ssh_subsystem_sup.erl | 29 | ||||
-rw-r--r-- | lib/ssh/src/ssh_system_sup.erl | 27 | ||||
-rw-r--r-- | lib/ssh/src/sshc_sup.erl | 46 | ||||
-rw-r--r-- | lib/ssh/src/sshd_sup.erl | 2 | ||||
-rw-r--r-- | lib/ssh/test/ssh_sup_SUITE.erl | 19 |
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]), |