summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Nilsson <hans@erlang.org>2021-03-16 16:49:25 +0100
committerHans Nilsson <hans@erlang.org>2021-04-15 16:28:24 +0200
commitbc26a8a8c501cec95b1c19a08ec926b26ebc66da (patch)
treeed8e1299d369d272665192e1562e408ba8a023e9
parent2f4b2f0925fa1cd00ee2e7ef5eae779a875d0c5a (diff)
downloaderlang-bc26a8a8c501cec95b1c19a08ec926b26ebc66da.tar.gz
ssh: Re-write supervisor tree to use PR-4368
-rw-r--r--lib/ssh/src/Makefile7
-rw-r--r--lib/ssh/src/ssh.app.src5
-rw-r--r--lib/ssh/src/ssh.erl169
-rw-r--r--lib/ssh/src/ssh.hrl7
-rw-r--r--lib/ssh/src/ssh_acceptor.erl149
-rw-r--r--lib/ssh/src/ssh_acceptor_sup.erl57
-rw-r--r--lib/ssh/src/ssh_app.erl50
-rw-r--r--lib/ssh/src/ssh_channel_sup.erl41
-rw-r--r--lib/ssh/src/ssh_client_channel.erl9
-rw-r--r--lib/ssh/src/ssh_connect.hrl5
-rw-r--r--lib/ssh/src/ssh_connection.erl3
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl190
-rw-r--r--lib/ssh/src/ssh_connection_sup.erl58
-rw-r--r--lib/ssh/src/ssh_controller.erl125
-rw-r--r--lib/ssh/src/ssh_lib.erl4
-rw-r--r--lib/ssh/src/ssh_server_channel.erl5
-rw-r--r--lib/ssh/src/ssh_sftp.erl2
-rw-r--r--lib/ssh/src/ssh_subsystem_sup.erl123
-rw-r--r--lib/ssh/src/ssh_sup.erl49
-rw-r--r--lib/ssh/src/ssh_system_sup.erl283
-rw-r--r--lib/ssh/src/sshc_sup.erl109
-rw-r--r--lib/ssh/src/sshd_sup.erl114
-rw-r--r--lib/ssh/test/ssh.cover2
-rw-r--r--lib/ssh/test/ssh_connection_SUITE.erl2
-rw-r--r--lib/ssh/test/ssh_limited.cover2
-rw-r--r--lib/ssh/test/ssh_sup_SUITE.erl219
26 files changed, 669 insertions, 1120 deletions
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index 29d77fa6f5..517a6611c4 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -66,8 +66,6 @@ MODULES= \
ssh_cli \
ssh_connection \
ssh_connection_handler \
- ssh_connection_sup \
- ssh_controller \
ssh_file \
ssh_fsm_kexinit \
ssh_fsm_userauth_client \
@@ -83,16 +81,13 @@ MODULES= \
ssh_sftpd_file\
ssh_shell \
ssh_subsystem_sup \
- ssh_sup \
ssh_system_sup \
ssh_tcpip_forward_srv \
ssh_tcpip_forward_client \
ssh_tcpip_forward_acceptor_sup \
ssh_tcpip_forward_acceptor \
ssh_transport \
- ssh_xfer \
- sshc_sup \
- sshd_sup
+ ssh_xfer
HRL_FILES =
diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src
index 085bb14383..57465b9fe8 100644
--- a/lib/ssh/src/ssh.app.src
+++ b/lib/ssh/src/ssh.app.src
@@ -22,14 +22,10 @@
ssh_fsm_kexinit,
ssh_fsm_userauth_client,
ssh_fsm_userauth_server,
- ssh_connection_sup,
- ssh_controller,
ssh_daemon_channel,
ssh_dbg,
ssh_lib,
ssh_shell,
- sshc_sup,
- sshd_sup,
ssh_io,
ssh_info,
ssh_file,
@@ -41,7 +37,6 @@
ssh_sftpd_file,
ssh_sftpd_file_api,
ssh_subsystem_sup,
- ssh_sup,
ssh_tcpip_forward_client,
ssh_tcpip_forward_srv,
ssh_tcpip_forward_acceptor_sup,
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 22fc8f40be..867e795c11 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -144,7 +144,7 @@ connect(Socket, UserOptions, NegotiationTimeout) when is_list(UserOptions) ->
Options = #{} ->
case valid_socket_to_use(Socket, ?GET_OPT(transport,Options)) of
ok ->
- ssh_connection_handler:start_link(client, Socket, Options, NegotiationTimeout);
+ continue_connect(Socket, Options, NegotiationTimeout);
{error,SockError} ->
{error,SockError}
end
@@ -165,10 +165,34 @@ connect(Host0, Port, UserOptions, NegotiationTimeout) when is_integer(Port),
{error, Reason};
Options ->
+ SocketOpts = [{active,false} | ?GET_OPT(socket_options,Options)],
Host = mangle_connect_address(Host0, Options),
- ssh_connection_handler:start_link(client, Host, Port, Options, NegotiationTimeout)
+ try
+ {_, Callback, _} = ?GET_OPT(transport, Options),
+ Callback:connect(Host, Port, SocketOpts, ?GET_OPT(connect_timeout,Options))
+ of
+ {ok, Socket} ->
+ continue_connect(Socket, Options, NegotiationTimeout);
+ {error, Reason} ->
+ {error, Reason}
+ catch
+ _:badarg -> {error, {options,?GET_OPT(socket_options,Options)}};
+ _:{error,Reason} -> {error,Reason};
+ error:Error -> {error,Error};
+ Class:Error -> {error, {Class,Error}}
+ end
end.
+%%%----------------
+continue_connect(Socket, Options0, NegTimeout) ->
+ {ok, {SockHost,SockPort}} = inet:sockname(Socket),
+ Options = ?PUT_INTERNAL_OPT([{negotiation_timeout,NegTimeout}], Options0),
+ Address = #address{address = SockHost,
+ port = SockPort,
+ profile = ?GET_OPT(profile,Options)
+ },
+ ssh_system_sup:start_subsystem(client, Address, Socket, Options).
+
%%--------------------------------------------------------------------
-spec close(ConnectionRef) -> ok | {error,term()} when
ConnectionRef :: connection_ref() .
@@ -254,20 +278,17 @@ daemon(Socket, UserOptions) ->
case valid_socket_to_use(Socket, ?GET_OPT(transport,Options0)) of
ok ->
try
- Options = ?PUT_INTERNAL_OPT({connected_socket, Socket}, Options0),
%% throws error:Error if no usable hostkey is found
- ssh_connection_handler:available_hkey_algorithms(server, Options),
- {ok, {IP,Port}} = inet:sockname(Socket),
- case sshd_sup:start_child(IP, Port, Options) of
- Result = {ok,_} ->
- case ssh_connection_handler:start_link(server, Socket, Options,
- ?GET_OPT(negotiation_timeout,Options))
- of
- {error,Error} ->
- {error,Error};
- _ ->
- Result
- end;
+ ssh_connection_handler:available_hkey_algorithms(server, Options0),
+ {ok, {SockHost,SockPort}} = inet:sockname(Socket),
+ Address = #address{address = SockHost,
+ port = SockPort,
+ profile = ?GET_OPT(profile,Options0)
+ },
+ Options = ?PUT_INTERNAL_OPT({connected_socket, Socket}, Options0),
+ case ssh_system_sup:start_subsystem(server, Address, Socket, Options) of
+ {ok,Pid} ->
+ {ok,Pid};
{error, {already_started, _}} ->
{error, eaddrinuse};
{error, Error} ->
@@ -288,7 +309,7 @@ daemon(Socket, UserOptions) ->
{error,OptionError} ->
{error,OptionError}
- end.
+ end.
@@ -301,26 +322,35 @@ daemon(Host0, Port0, UserOptions0) when 0 =< Port0, Port0 =< 65535,
try
{Host1, UserOptions} = handle_daemon_args(Host0, UserOptions0),
#{} = Options0 = ssh_options:handle_options(server, UserOptions),
- open_listen_socket(Host1, Port0, Options0)
+ %% We need to open the listen socket here before start of the system supervisor. That
+ %% is because Port0 might be 0, or if an FD is provided in the Options0, in which case
+ %% the real listening port will be known only after the gen_tcp:listen call.
+ maybe_open_listen_socket(Host1, Port0, Options0)
of
{Host, Port, ListenSocket, Options1} ->
try
%% Now Host,Port is what to use for the supervisor to register its name,
- %% and ListenSocket is for listening on connections. But it is still owned
- %% by self()...
+ %% and ListenSocket, if provided, is for listening on connections. But
+ %% it is still owned by self()...
%% throws error:Error if no usable hostkey is found
ssh_connection_handler:available_hkey_algorithms(server, Options1),
- sshd_sup:start_child(Host, Port, Options1)
+ ssh_system_sup:start_system(server,
+ #address{address = Host,
+ port = Port,
+ profile = ?GET_OPT(profile,Options1)},
+ Options1)
of
- Result = {ok,_} ->
+ {ok,DaemonRef} when ListenSocket == undefined ->
+ {ok,DaemonRef};
+ {ok,DaemonRef} ->
receive
{request_control, ListenSocket, ReqPid} ->
{_, Callback, _} = ?GET_OPT(transport, Options1),
ok = Callback:controlling_process(ListenSocket, ReqPid),
ReqPid ! {its_yours,ListenSocket}
end,
- Result;
+ {ok,DaemonRef};
{error, {already_started, _}} ->
close_listen_socket(ListenSocket, Options1),
{error, eaddrinuse};
@@ -370,20 +400,16 @@ daemon(_, _, _) ->
InfoTuple :: daemon_info_tuple().
daemon_info(DaemonRef) ->
- case catch ssh_system_sup:acceptor_supervisor(DaemonRef) of
- AsupPid when is_pid(AsupPid) ->
- [{Host,Port,Profile}] =
- [{Hst,Prt,Prf}
- || {{ssh_acceptor_sup,Hst,Prt,Prf},_Pid,worker,[ssh_acceptor]}
- <- supervisor:which_children(AsupPid)],
- IP =
- case inet:parse_strict_address(Host) of
- {ok,IP0} -> IP0;
- _ -> Host
+ case ssh_system_sup:get_daemon_listen_address(DaemonRef) of
+ {ok,A} ->
+ Address =
+ case inet:parse_strict_address(A#address.address) of
+ {ok,IP} -> A#address{address=IP};
+ _ -> A
end,
-
Opts =
- case ssh_system_sup:get_options(DaemonRef, Host, Port, Profile) of
+ %% Pick a subset of the Options to present:
+ case ssh_system_sup:get_options(DaemonRef, Address) of
{ok, OptMap} ->
lists:sort(
maps:to_list(
@@ -394,11 +420,12 @@ daemon_info(DaemonRef) ->
[]
end,
- {ok, [{port,Port},
- {ip,IP},
- {profile,Profile},
- {options,Opts}
+ {ok, [{port, Address#address.port},
+ {ip, Address#address.address},
+ {profile, Address#address.profile},
+ {options, Opts}
]};
+
_ ->
{error,bad_daemon_ref}
end.
@@ -442,14 +469,14 @@ stop_listener(Address, Port) ->
-spec stop_listener(any|inet:ip_address(), inet:port_number(), term()) -> ok.
-stop_listener(any, Port, Profile) ->
- map_ip(fun(IP) ->
- ssh_system_sup:stop_listener(IP, Port, Profile)
- end, [{0,0,0,0},{0,0,0,0,0,0,0,0}]);
stop_listener(Address, Port, Profile) ->
- map_ip(fun(IP) ->
- ssh_system_sup:stop_listener(IP, Port, Profile)
- end, {address,Address}).
+ lists:foreach(fun({Sup,_Addr}) ->
+ stop_listener(Sup)
+ end,
+ ssh_system_sup:addresses(server,
+ #address{address=Address,
+ port=Port,
+ profile=Profile})).
%%--------------------------------------------------------------------
%% Description: Stops the listener and all connections started by
@@ -469,14 +496,14 @@ stop_daemon(Address, Port) ->
-spec stop_daemon(any|inet:ip_address(), inet:port_number(), atom()) -> ok.
-stop_daemon(any, Port, Profile) ->
- map_ip(fun(IP) ->
- 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(server, IP, Port, Profile)
- end, {address,Address}).
+ lists:foreach(fun({Sup,_Addr}) ->
+ stop_daemon(Sup)
+ end,
+ ssh_system_sup:addresses(server,
+ #address{address=Address,
+ port=Port,
+ profile=Profile})).
%%--------------------------------------------------------------------
%% Description: Starts an interactive shell to an SSH server on the
@@ -752,17 +779,26 @@ is_tcp_socket(Socket) ->
end.
%%%----------------------------------------------------------------
-open_listen_socket(_Host0, Port0, Options0) ->
- {ok,LSock} =
- case ?GET_SOCKET_OPT(fd, Options0) of
- undefined ->
- ssh_acceptor:listen(Port0, Options0);
+maybe_open_listen_socket(Host, Port, Options) ->
+ Opened =
+ case ?GET_SOCKET_OPT(fd, Options) of
+ undefined when Port == 0 ->
+ ssh_acceptor:listen(0, Options);
Fd when is_integer(Fd) ->
%% Do gen_tcp:listen with the option {fd,Fd}:
- ssh_acceptor:listen(0, Options0)
+ ssh_acceptor:listen(0, Options);
+ undefined ->
+ open_later
end,
- {ok,{LHost,LPort}} = inet:sockname(LSock),
- {LHost, LPort, LSock, ?PUT_INTERNAL_OPT({lsocket,{LSock,self()}}, Options0)}.
+ case Opened of
+ {ok,LSock} ->
+ {ok,{LHost,LPort}} = inet:sockname(LSock),
+ {LHost, LPort, LSock, ?PUT_INTERNAL_OPT({lsocket,{LSock,self()}}, Options)};
+ open_later ->
+ {Host, Port, undefined, Options};
+ Others ->
+ Others
+ end.
%%%----------------------------------------------------------------
close_listen_socket(ListenSocket, Options) ->
@@ -774,19 +810,6 @@ close_listen_socket(ListenSocket, Options) ->
end.
%%%----------------------------------------------------------------
-map_ip(Fun, {address,IP}) when is_tuple(IP) ->
- Fun(IP);
-map_ip(Fun, {address,Address}) ->
- IPs = try {ok,#hostent{h_addr_list=IP0s}} = inet:gethostbyname(Address),
- IP0s
- catch
- _:_ -> []
- end,
- map_ip(Fun, IPs);
-map_ip(Fun, IPs) ->
- lists:map(Fun, IPs).
-
-%%%----------------------------------------------------------------
is_host(X, Opts) ->
try is_host1(mangle_connect_address(X, Opts))
catch
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index 33f6833830..848513e6a5 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -36,6 +36,8 @@
-define(DEFAULT_SHELL, {shell, start, []} ).
+-define(DEFAULT_TIMEOUT, 5000).
+
-define(MAX_RND_PADDING_LEN, 15).
-define(SUPPORTED_AUTH_METHODS, "publickey,keyboard-interactive,password").
@@ -410,6 +412,11 @@
%% Records
+-record(address, {address,
+ port,
+ profile
+ }).
+
-record(ssh,
{
role :: client | role(),
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index 9899fc7098..3ea066f98d 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -25,12 +25,12 @@
-include("ssh.hrl").
%% Internal application API
--export([start_link/4,
+-export([start_link/3,
number_of_connections/1,
listen/2]).
%% spawn export
--export([acceptor_init/5, acceptor_loop/6]).
+-export([acceptor_init/4, acceptor_loop/7]).
-behaviour(ssh_dbg).
-export([ssh_dbg_trace_points/0, ssh_dbg_flags/1, ssh_dbg_on/1, ssh_dbg_off/1, ssh_dbg_format/2]).
@@ -40,61 +40,9 @@
%%====================================================================
%% Internal application API
%%====================================================================
-start_link(Port, Address, Options, AcceptTimeout) ->
- Args = [self(), Port, Address, Options, AcceptTimeout],
- proc_lib:start_link(?MODULE, acceptor_init, Args).
-
-%%%----------------------------------------------------------------
-number_of_connections(SysSup) ->
- length([S || S <- supervisor:which_children(SysSup),
- has_worker(SysSup,S)]).
-
-
-has_worker(SysSup, {R,SubSysSup,supervisor,[ssh_subsystem_sup]}) when is_reference(R),
- is_pid(SubSysSup) ->
- try
- {{server, ssh_connection_sup, _, _}, Pid, supervisor, [ssh_connection_sup]} =
- lists:keyfind([ssh_connection_sup], 4, supervisor:which_children(SubSysSup)),
- {Pid, supervisor:which_children(Pid)}
- of
- {ConnSup,[]} ->
- %% Strange. Since the connection supervisor exists, there should have been
- %% a connection here.
- %% It might be that the connection_handler worker has "just died", maybe
- %% due to a exit(_,kill). It might also be so that the worker is starting.
- %% Spawn a killer that redo the test and kills it if the problem persists.
- %% TODO: Fix this better in the supervisor tree....
- spawn(fun() ->
- timer:sleep(10),
- try supervisor:which_children(ConnSup)
- of
- [] ->
- %% we are on the server-side:
- ssh_system_sup:stop_subsystem(SysSup, SubSysSup);
- [_] ->
- %% is ok now
- ok;
- _ ->
- %% What??
- error
- catch _:_ ->
- %% What??
- error
- end
- end),
- false;
- {_ConnSup,[_]}->
- true;
- _ ->
- %% What??
- false
- catch _:_ ->
- %% What??
- false
- end;
-
-has_worker(_,_) ->
- false.
+%% Supposed to be called in a child-spec of the ssh_acceptor_sup
+start_link(SystemSup, Address, Options) ->
+ proc_lib:start_link(?MODULE, acceptor_init, [self(),SystemSup,Address,Options]).
%%%----------------------------------------------------------------
listen(Port, Options) ->
@@ -114,29 +62,43 @@ listen(Port, Options) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-acceptor_init(Parent, Port, Address, Opts, AcceptTimeout) ->
- try
- ?GET_INTERNAL_OPT(lsocket, Opts)
- of
+acceptor_init(Parent, SystemSup,
+ #address{address=Address, port=Port, profile=_Profile},
+ Opts) ->
+ AcceptTimeout = ?GET_INTERNAL_OPT(timeout, Opts, ?DEFAULT_TIMEOUT),
+ {_, Callback, _} = ?GET_OPT(transport, Opts),
+ case ?GET_INTERNAL_OPT(lsocket, Opts, undefined) of
{LSock, SockOwner} ->
+ %% A listening socket (or fd option) was provided in the ssh:daemon call
case inet:sockname(LSock) of
- {ok,{_,Port}} -> % A usable, open LSock
+ {ok,{_,Port}} ->
+ %% A usable, open LSock
proc_lib:init_ack(Parent, {ok, self()}),
request_ownership(LSock, SockOwner),
- {_, Callback, _} = ?GET_OPT(transport, Opts),
- acceptor_loop(Callback, Port, Address, Opts, LSock, AcceptTimeout);
+ acceptor_loop(Callback, Port, Address, Opts, LSock, AcceptTimeout, SystemSup);
+
+ {error,_Error} ->
+ %% Not open, a restart
+ %% Allow gen_tcp:listen to fail 4 times if eaddrinuse (It is a bug fix):
+ case try_listen(Port, Opts, 4) of
+ {ok,NewLSock} ->
+ proc_lib:init_ack(Parent, {ok, self()}),
+ Opts1 = ?DELETE_INTERNAL_OPT(lsocket, Opts),
+ acceptor_loop(Callback, Port, Address, Opts1, NewLSock, AcceptTimeout, SystemSup);
+ {error,Error} ->
+ proc_lib:init_ack(Parent, {error,Error})
+ end
+ end;
- {error,_} -> % Not open, a restart
- %% Allow gen_tcp:listen to fail 4 times if eaddrinuse:
- {ok,NewLSock} = try_listen(Port, Opts, 4),
+ undefined ->
+ %% No listening socket (nor fd option) was provided; open a listening socket:
+ case listen(Port, Opts) of
+ {ok,LSock} ->
proc_lib:init_ack(Parent, {ok, self()}),
- Opts1 = ?DELETE_INTERNAL_OPT(lsocket, Opts),
- {_, Callback, _} = ?GET_OPT(transport, Opts1),
- acceptor_loop(Callback, Port, Address, Opts1, NewLSock, AcceptTimeout)
+ acceptor_loop(Callback, Port, Address, Opts, LSock, AcceptTimeout, SystemSup);
+ {error,Error} ->
+ proc_lib:init_ack(Parent, {error,Error})
end
- catch
- _:_ ->
- {error,use_existing_socket_failed}
end.
@@ -160,11 +122,11 @@ request_ownership(LSock, SockOwner) ->
end.
%%%----------------------------------------------------------------
-acceptor_loop(Callback, Port, Address, Opts, ListenSocket, AcceptTimeout) ->
+acceptor_loop(Callback, Port, Address, Opts, ListenSocket, AcceptTimeout, SystemSup) ->
case Callback:accept(ListenSocket, AcceptTimeout) of
{ok,Socket} ->
{ok, {FromIP,FromPort}} = inet:peername(Socket), % Just in case of error in next line:
- case handle_connection(Address, Port, Opts, Socket) of
+ case handle_connection(SystemSup, Address, Port, Opts, Socket) of
{error,Error} ->
catch Callback:close(Socket),
handle_error(Error, Address, Port, FromIP, FromPort);
@@ -174,18 +136,22 @@ acceptor_loop(Callback, Port, Address, Opts, ListenSocket, AcceptTimeout) ->
{error,Error} ->
handle_error(Error, Address, Port)
end,
- ?MODULE:acceptor_loop(Callback, Port, Address, Opts, ListenSocket, AcceptTimeout).
+ ?MODULE:acceptor_loop(Callback, Port, Address, Opts, ListenSocket, AcceptTimeout, SystemSup).
%%%----------------------------------------------------------------
-handle_connection(Address, Port, Options, Socket) ->
- Profile = ?GET_OPT(profile, Options),
- SystemSup = ssh_system_sup:system_supervisor(Address, Port, Profile),
-
- MaxSessions = ?GET_OPT(max_sessions, Options),
+handle_connection(SystemSup, Address, Port, Options0, Socket) ->
+ MaxSessions = ?GET_OPT(max_sessions, Options0),
case number_of_connections(SystemSup) < MaxSessions of
true ->
- NegTimeout = ?GET_OPT(negotiation_timeout, Options),
- ssh_connection_handler:start_link(server, Address, Port, Socket, Options, NegTimeout);
+ Options = ?PUT_INTERNAL_OPT([{user_pid, self()}
+ ], Options0),
+ ssh_system_sup:start_subsystem(server,
+ #address{address = Address,
+ port = Port,
+ profile = ?GET_OPT(profile,Options)
+ },
+ Socket,
+ Options);
false ->
{error,{max_sessions,MaxSessions}}
end.
@@ -233,6 +199,12 @@ handle_error(Reason, ToAddress, ToPort, FromAddress, FromPort) ->
io_lib:format(": ~p", [Error])])
end.
+%%%----------------------------------------------------------------
+number_of_connections(SysSupPid) ->
+ lists:foldl(fun({_Ref,_Pid,supervisor,[ssh_subsystem_sup]}, N) -> N+1;
+ (_, N) -> N
+ end, 0, supervisor:which_children(SysSupPid)).
+
%%%################################################################
%%%#
%%%# Tracing
@@ -242,17 +214,16 @@ ssh_dbg_trace_points() -> [connections].
ssh_dbg_flags(connections) -> [c].
-ssh_dbg_on(connections) -> dbg:tp(?MODULE, acceptor_init, 5, x),
+ssh_dbg_on(connections) -> dbg:tp(?MODULE, acceptor_init, 4, x),
dbg:tpl(?MODULE, handle_connection, 4, x).
-ssh_dbg_off(connections) -> dbg:ctp(?MODULE, acceptor_init, 5),
+ssh_dbg_off(connections) -> dbg:ctp(?MODULE, acceptor_init, 4),
dbg:ctp(?MODULE, handle_connection, 4).
-ssh_dbg_format(connections, {call, {?MODULE,acceptor_init,
- [_Parent, Port, Address, _Opts, _AcceptTimeout]}}) ->
- [io_lib:format("Starting LISTENER on ~s:~p\n", [ssh_lib:format_address(Address),Port])
+ssh_dbg_format(connections, {call, {?MODULE,acceptor_init, [_Parent, _SysSup, Address, _Opts]}}) ->
+ [io_lib:format("Starting LISTENER on ~s\n", [ssh_lib:format_address(Address)])
];
-ssh_dbg_format(connections, {return_from, {?MODULE,acceptor_init,5}, _Ret}) ->
+ssh_dbg_format(connections, {return_from, {?MODULE,acceptor_init,4}, _Ret}) ->
skip;
ssh_dbg_format(connections, {call, {?MODULE,handle_connection,[_,_,_,_]}}) ->
diff --git a/lib/ssh/src/ssh_acceptor_sup.erl b/lib/ssh/src/ssh_acceptor_sup.erl
index 15a2238dd3..749de43776 100644
--- a/lib/ssh/src/ssh_acceptor_sup.erl
+++ b/lib/ssh/src/ssh_acceptor_sup.erl
@@ -29,64 +29,43 @@
-include("ssh.hrl").
--export([start_link/4, start_child/5, stop_child/4]).
+-export([start_link/3,
+ restart_child/2
+ ]).
%% Supervisor callback
-export([init/1]).
--define(DEFAULT_TIMEOUT, 50000).
-
%%%=========================================================================
%%% API
%%%=========================================================================
-start_link(Address, Port, Profile, Options) ->
- supervisor:start_link(?MODULE, [Address, Port, Profile, Options]).
-
-start_child(AccSup, Address, Port, Profile, Options) ->
- Spec = child_spec(Address, Port, Profile, Options),
- case supervisor:start_child(AccSup, Spec) of
- {error, already_present} ->
- %% Is this ever called?
- stop_child(AccSup, Address, Port, Profile),
- supervisor:start_child(AccSup, Spec);
- Reply ->
- %% Reply = {ok,SystemSupPid} when the user calls ssh:daemon
- %% after having called ssh:stop_listening
- Reply
+start_link(SystemSup, Address, Options) ->
+ case supervisor:start_link(?MODULE, [SystemSup, Address, Options]) of
+ {error, {shutdown, {failed_to_start_child, _, Error}}} ->
+ {error,Error};
+ Other ->
+ Other
end.
-stop_child(AccSup, Address, Port, Profile) ->
- Name = id(Address, Port, Profile),
- case supervisor:terminate_child(AccSup, Name) of
- ok ->
- supervisor:delete_child(AccSup, Name);
- Error ->
- Error
- end.
+restart_child(AccSup, Address) ->
+ supervisor:restart_child(AccSup, {?MODULE,Address}).
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
-init([Address, Port, Profile, Options]) ->
- %% Initial start of ssh_acceptor_sup for this port or new start after
- %% ssh:stop_daemon
+init([SystemSup, Address, Options]) ->
+ %% Initial start of ssh_acceptor_sup for this port
SupFlags = #{strategy => one_for_one,
intensity => 10,
period => 3600
},
- ChildSpecs = [child_spec(Address, Port, Profile, Options)],
+ ChildSpecs = [#{id => {?MODULE,Address},
+ start => {ssh_acceptor, start_link, [SystemSup, Address, Options]},
+ restart => transient % because a crashed listener could be replaced by a new one
+ }
+ ],
{ok, {SupFlags,ChildSpecs}}.
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
-child_spec(Address, Port, Profile, Options) ->
- Timeout = ?GET_INTERNAL_OPT(timeout, Options, ?DEFAULT_TIMEOUT),
- #{id => id(Address, Port, Profile),
- start => {ssh_acceptor, start_link, [Port, Address, Options, Timeout]},
- restart => transient % because a crashed listener could be replaced by a new one
- }.
-
-id(Address, Port, Profile) ->
- {ssh_acceptor_sup, Address, Port, Profile}.
-
diff --git a/lib/ssh/src/ssh_app.erl b/lib/ssh/src/ssh_app.erl
index d3680e20da..2e8b671362 100644
--- a/lib/ssh/src/ssh_app.erl
+++ b/lib/ssh/src/ssh_app.erl
@@ -20,16 +20,62 @@
%%
-%% Purpose : Application master for SSH.
+%%%=========================================================================
+%%% Purpose : Application master and top supervisors for SSH.
+%%%
+%%% -----> ssh_sup -----+-----> sshc_sup --+--> "system sup" (etc)
+%%% | |
+%%% | +--> "system sup" (etc)
+%%% | :
+%%% | +--> "system sup" (etc)
+%%% |
+%%% +-----> sshc_sup --+--> "system sup" (etc)
+%%% |
+%%% +--> "system sup" (etc)
+%%% :
+%%% +--> "system sup" (etc)
-module(ssh_app).
-behaviour(application).
+-behaviour(supervisor).
+%% 'application' export:
-export([start/2, stop/1]).
+%% 'supervisor' export:
+-export([init/1]).
+
+
+%%%=========================================================================
+%%% Application callback
+%%%=========================================================================
start(_Type, _State) ->
- supervisor:start_link({local, ssh_sup}, ssh_sup, []).
+ supervisor:start_link({local,ssh_sup}, ?MODULE, [ssh_sup]).
stop(_State) ->
ok.
+
+%%%=========================================================================
+%%% Supervisor callback
+%%%=========================================================================
+init([ssh_sup]) ->
+ SupFlags = #{strategy => one_for_one,
+ intensity => 10,
+ period => 3600
+ },
+ ChildSpecs = [#{id => SupName,
+ start => {supervisor, start_link,
+ [{local,SupName}, ?MODULE, [sshX_sup]]},
+ type => supervisor}
+ || SupName <- [sshd_sup, sshc_sup]
+ ],
+ {ok, {SupFlags,ChildSpecs}};
+
+init([sshX_sup]) ->
+ SupFlags = #{strategy => one_for_one,
+ intensity => 10,
+ period => 3600
+ },
+ ChildSpecs = [],
+ {ok, {SupFlags,ChildSpecs}}.
diff --git a/lib/ssh/src/ssh_channel_sup.erl b/lib/ssh/src/ssh_channel_sup.erl
index 4b36c8a5a0..bdecfe8c21 100644
--- a/lib/ssh/src/ssh_channel_sup.erl
+++ b/lib/ssh/src/ssh_channel_sup.erl
@@ -40,35 +40,17 @@ start_link(Args) ->
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_the_channel(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);
+ start_the_channel(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 => {ChanMod, start_link, [ConnRef, Id, Callback, Args, Exec]},
- restart => temporary,
- type => worker,
- modules => [ChanMod]
- },
- 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
%%%=========================================================================
@@ -88,3 +70,20 @@ max_num_channels_not_exceeded(ChannelSup, Opts) ->
supervisor:which_children(ChannelSup)]),
%% Note that NumChannels is BEFORE starting a new one
NumChannels < MaxNumChannels.
+
+
+start_the_channel(ChanMod, ChannelSup, ConnRef, Callback, Id, Args, Exec) ->
+ ChildSpec =
+ #{id => make_ref(),
+ start => {ChanMod, start_link, [ConnRef, Id, Callback, Args, Exec]},
+ restart => temporary,
+ type => worker,
+ modules => [ChanMod]
+ },
+ 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.
+
diff --git a/lib/ssh/src/ssh_client_channel.erl b/lib/ssh/src/ssh_client_channel.erl
index 3cfffc25b4..455cb72d2f 100644
--- a/lib/ssh/src/ssh_client_channel.erl
+++ b/lib/ssh/src/ssh_client_channel.erl
@@ -70,7 +70,8 @@
-export([cache_create/0, cache_lookup/2, cache_update/2,
cache_delete/1, cache_delete/2, cache_foldl/3,
cache_info/2, cache_find/2,
- get_print_info/1]).
+ get_print_info/1, get_print_info/2
+ ]).
-behaviour(ssh_dbg).
-export([ssh_dbg_trace_points/0, ssh_dbg_flags/1, ssh_dbg_on/1, ssh_dbg_off/1, ssh_dbg_format/2]).
@@ -212,6 +213,9 @@ handle_call(get_print_info, _From, State) ->
},
{reply, Reply, State};
+handle_call({get_print_info,channel_cb}, _From, State) ->
+ {reply, State#state.channel_cb, State};
+
handle_call(Request, From, #state{channel_cb = Module,
channel_state = ChannelState} = State) ->
try Module:handle_call(Request, From, ChannelState) of
@@ -365,6 +369,9 @@ cache_find(ChannelPid, Cache) ->
get_print_info(Pid) ->
call(Pid, get_print_info, 1000).
+get_print_info(Pid, Arg) ->
+ call(Pid, {get_print_info,Arg}, 1000).
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
diff --git a/lib/ssh/src/ssh_connect.hrl b/lib/ssh/src/ssh_connect.hrl
index e00e78d6b7..38e2b2de0b 100644
--- a/lib/ssh/src/ssh_connect.hrl
+++ b/lib/ssh/src/ssh_connect.hrl
@@ -25,7 +25,6 @@
-define(DEFAULT_PACKET_SIZE, 65536).
-define(DEFAULT_WINDOW_SIZE, 10*?DEFAULT_PACKET_SIZE).
--define(DEFAULT_TIMEOUT, 5000).
-define(MAX_PROTO_VERSION, 255). % Max length of the hello string
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -268,7 +267,5 @@
cli_spec,
options,
exec,
- system_supervisor,
- sub_system_supervisor,
- connection_supervisor
+ sub_system_supervisor
}).
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index a966f7bbf1..b8dd091c94 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -918,8 +918,7 @@ handle_msg(#ssh_msg_global_request{name = <<"tcpip-forward">>,
{[{connection_reply, request_failure_msg()}], Connection};
true ->
- Sups = ?GET_INTERNAL_OPT(supervisors, Opts),
- SubSysSup = proplists:get_value(subsystem_sup, Sups),
+ SubSysSup = ?GET_INTERNAL_OPT(subsystem_sup, Opts),
FwdSup = ssh_subsystem_sup:tcpip_fwd_supervisor(SubSysSup),
ConnPid = self(),
case ssh_tcpip_forward_acceptor:supervised_start(FwdSup,
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 1bcfeb1146..13790157c7 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -42,7 +42,8 @@
%%====================================================================
%%% Start and stop
--export([start_link/4, start_link/5, start_link/6,
+-export([start_link_ng/4, start_link_ng/5,
+ takeover/4,
stop/1
]).
@@ -95,74 +96,44 @@
%% Start / stop
%%====================================================================
-start_link(client, Host, Port, Options, NegotiationTimeout) ->
- {_, Callback, _} = ?GET_OPT(transport, Options),
- SocketOpts = [{active,false} | ?GET_OPT(socket_options,Options)],
- try Callback:connect(Host, Port, SocketOpts, ?GET_OPT(connect_timeout,Options)) of
- {ok, Socket} ->
- start_link(client, Socket, Options, NegotiationTimeout);
- {error, Reason} ->
- {error, Reason}
- catch
- _:badarg -> {error, {options,?GET_OPT(socket_options,Options)}};
- _:{error,Reason} -> {error,Reason};
- error:Error -> {error,Error};
- Class:Error -> {error, {Class,Error}}
+start_link_ng(Role, Address, Socket, Options) ->
+ start_link_ng(Role, Address, undefined, Socket, Options).
+
+start_link_ng(Role, _Address=#address{}, Id, Socket, Options) ->
+ case gen_statem:start_link(?MODULE,
+ [Role, Socket, Options],
+ [{spawn_opt, [{message_queue_data,off_heap}]}]) of
+
+ {ok, Pid} when Id =/= undefined ->
+ %% Announce the ConnectionRef to the system supervisor so it could
+ %% 1) initiate the socket handover, and
+ %% 2) be returned to whoever called for example ssh:connect; the Pid
+ %% returned from this function is "consumed" by the subsystem
+ %% supervisor.
+ ?GET_INTERNAL_OPT(user_pid,Options) ! {new_connection_ref, Id, Pid},
+ {ok, Pid};
+
+ Others ->
+ Others
end.
-start_link(Role, Socket, Options, NegotiationTimeout) ->
- {ok, {Host,Port}} = inet:sockname(Socket),
- start_link(Role, Host, Port, Socket, Options, NegotiationTimeout).
-start_link(Role, Host, Port, Socket, Options0, NegotiationTimeout) ->
- try
- Options1 = ?PUT_INTERNAL_OPT([{user_pid, self()}
- ], Options0),
- Profile = ?GET_OPT(profile, Options1),
- Sup = case Role of
- client -> sshc_sup;
- server -> sshd_sup
- end,
- {ok, {SystemSup, SubSysSup}} =
- Sup:start_system_subsystem(Host, Port, Profile, Options1),
- ConnectionSup = ssh_system_sup:connection_supervisor(SystemSup),
- Options = ?PUT_INTERNAL_OPT([{supervisors, [{system_sup, SystemSup},
- {subsystem_sup, SubSysSup},
- {connection_sup, ConnectionSup}]}
- ], Options1),
-
- %% This is essentially gen_statem:start_link/3 :
- case ssh_connection_sup:start_child(ConnectionSup,
- [?MODULE,
- [Role, Socket, Options],
- [{spawn_opt, [{message_queue_data,off_heap}]}]]
- ) of
- {ok, Pid} ->
- %% Now the connection_handler process is started
- %% First set the group leader if it is a client:
- case Role of
- client ->
- group_leader(group_leader(), Pid);
- _ ->
- ok
- end,
- %% No message handling yet. It begins when the socket_control/3 is called
- case socket_control(Socket, Pid, Options) of
- ok ->
- %% handshake returns {ok,Pid} after a successful connection setup.
- %% or {error,Reason} after an unsuccesful one:
- 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};
- error:Error -> {error,Error};
- Class:Error -> {error, {Class,Error}}
+takeover(ConnPid, client, Socket, Options) ->
+ group_leader(group_leader(), ConnPid),
+ takeover(ConnPid, common, Socket, Options);
+
+takeover(ConnPid, _, Socket, Options) ->
+ {_, Callback, _} = ?GET_OPT(transport, Options),
+ case Callback:controlling_process(Socket, ConnPid) of
+ ok ->
+ gen_statem:cast(ConnPid, socket_control),
+ NegTimeout = ?GET_INTERNAL_OPT(negotiation_timeout,
+ Options,
+ ?GET_OPT(negotiation_timeout, Options)
+ ),
+ handshake(ConnPid, erlang:monitor(process,ConnPid), NegTimeout);
+ {error, Reason} ->
+ {error, Reason}
end.
%%--------------------------------------------------------------------
@@ -455,14 +426,11 @@ init([Role, Socket, Opts]) when Role==client ; Role==server ->
%%% 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)
+ sub_system_supervisor = ?GET_INTERNAL_OPT(subsystem_sup, Opts)
},
case Role of
server ->
@@ -534,29 +502,20 @@ 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
{Pid, ssh_connected} ->
- erlang:demonitor(Ref),
+ erlang:demonitor(Ref, [flush]),
{ok, Pid};
{Pid, {not_connected, Reason}} ->
- erlang:demonitor(Ref),
+ erlang:demonitor(Ref, [flush]),
{error, Reason};
{'DOWN', Ref, process, Pid, {shutdown, Reason}} ->
{error, Reason};
{'DOWN', Ref, process, Pid, Reason} ->
{error, Reason}
after Timeout ->
+ erlang:demonitor(Ref, [flush]),
ssh_connection_handler:stop(Pid),
{error, timeout}
end.
@@ -1037,8 +996,7 @@ handle_event({call,From}, {eof, ChannelId}, StateName, D0)
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),
+ SubSysSup = ?GET_INTERNAL_OPT(subsystem_sup, Opts),
Reply = {ok, {SubSysSup, ?role(StateName), Opts}},
{keep_state, D, [{reply,From,Reply}]};
@@ -1384,23 +1342,10 @@ handle_event(Type, Ev, StateName, D0) ->
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
terminate(normal, _StateName, D) ->
- stop_subsystem(D),
- close_transport(D);
-
-terminate({shutdown,"Connection closed"}, _StateName, D) ->
- %% Normal: terminated by a sent by peer
- stop_subsystem(D),
- close_transport(D);
-
-terminate({shutdown,{init,Reason}}, StateName, D) ->
- %% Error in initiation. "This error should not occur".
- log(error, D, "Shutdown in init (StateName=~p): ~p~n", [StateName,Reason]),
- stop_subsystem(D),
close_transport(D);
terminate({shutdown,_R}, _StateName, D) ->
%% Internal termination, usually already reported via ?send_disconnect resulting in a log entry
- stop_subsystem(D),
close_transport(D);
terminate(shutdown, _StateName, D0) ->
@@ -1411,11 +1356,6 @@ terminate(shutdown, _StateName, D0) ->
D0),
close_transport(D);
-terminate(killed, _StateName, D) ->
- %% Got a killed signal
- stop_subsystem(D),
- close_transport(D);
-
terminate(Reason, StateName, D0) ->
%% Others, e.g undef, {badmatch,_}, ...
log(error, D0, Reason),
@@ -1423,7 +1363,6 @@ terminate(Reason, StateName, D0) ->
"Internal error",
io_lib:format("Reason: ~p",[Reason]),
StateName, D0),
- stop_subsystem(D),
close_transport(D).
%%--------------------------------------------------------------------
@@ -1501,51 +1440,10 @@ code_change(_OldVsn, StateName, State, _Extra) ->
%%====================================================================
%%--------------------------------------------------------------------
-%% Starting
-
-%%--------------------------------------------------------------------
-%% Stopping
-
-stop_subsystem(#data{ssh_params =
- #ssh{role = Role},
- connection_state =
- #connection{system_supervisor = SysSup,
- sub_system_supervisor = SubSysSup}
- }) when is_pid(SysSup) andalso is_pid(SubSysSup) ->
- C = self(),
- spawn(fun() ->
- wait_until_dead(C, 10000),
- case Role of
- server ->
- ssh_system_sup:stop_subsystem(SysSup, SubSysSup);
- client ->
- ssh_system_sup:stop_subsystem(SysSup, SubSysSup),
- wait_until_dead(SubSysSup, 1000),
- sshc_sup:stop_system(SysSup)
- end
- end);
-stop_subsystem(_) ->
- ok.
-
-
-wait_until_dead(Pid, Timeout) ->
- Mref = erlang:monitor(process, Pid),
- receive
- {'DOWN', Mref, process, Pid, _Info} -> ok
- after
- Timeout -> ok
- end.
-
-
close_transport(#data{transport_cb = Transport,
socket = Socket}) ->
- try
- Transport:close(Socket)
- of
- _ -> ok
- catch
- _:_ -> ok
- end.
+ catch Transport:close(Socket),
+ ok.
%%--------------------------------------------------------------------
available_hkey_algorithms(client, Options) ->
diff --git a/lib/ssh/src/ssh_connection_sup.erl b/lib/ssh/src/ssh_connection_sup.erl
deleted file mode 100644
index 192ce6f65d..0000000000
--- a/lib/ssh/src/ssh_connection_sup.erl
+++ /dev/null
@@ -1,58 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% Purpose: Ssh connection supervisor.
-%%----------------------------------------------------------------------
-
--module(ssh_connection_sup).
-
--behaviour(supervisor).
-
-%% API
--export([start_link/1]).
--export([start_child/2]).
-
-%% Supervisor callback
--export([init/1]).
-
-%%%=========================================================================
-%%% API
-%%%=========================================================================
-start_link(Args) ->
- supervisor:start_link(?MODULE, [Args]).
-
-start_child(Sup, Args) ->
- supervisor:start_child(Sup, Args).
-
-%%%=========================================================================
-%%% Supervisor callback
-%%%=========================================================================
-init(_) ->
- SupFlags = #{strategy => simple_one_for_one,
- intensity => 0,
- period => 3600
- },
- ChildSpecs = [#{id => undefined, % As simple_one_for_one is used.
- start => {gen_statem, start_link, []},
- restart => temporary % because there is no way to restart a crashed connection
- }
- ],
- {ok, {SupFlags,ChildSpecs}}.
diff --git a/lib/ssh/src/ssh_controller.erl b/lib/ssh/src/ssh_controller.erl
deleted file mode 100644
index d8fbc8d0f2..0000000000
--- a/lib/ssh/src/ssh_controller.erl
+++ /dev/null
@@ -1,125 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2020. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% Purpose: Handles an ssh connection, e.i. both the
-%% setup SSH Transport Layer Protocol (RFC 4253), Authentication
-%% Protocol (RFC 4252) and SSH connection Protocol (RFC 4255)
-%% Details of the different protocols are
-%% implemented in ssh_transport.erl, ssh_auth.erl and ssh_connection.erl
-%% ----------------------------------------------------------------------
-
--module(ssh_controller).
-
--behaviour(gen_server).
-
-
-%%====================================================================
-%%% Exports
-%%====================================================================
-
-%%% API
--export([start_system_subsystem/7,
- stop_system/2
- ]).
-
-%%% Start and stop
--export([start_link/2
- ]).
-
--export([init/1,
- handle_call/3,
- handle_cast/2
- ]).
-
-%%====================================================================
-%% Start / stop
-%%====================================================================
-
-start_link(Role, RegName) ->
- gen_server:start_link({local,RegName}, ?MODULE, [Role], []).
-
-%%====================================================================
-%% Internal application API
-%%====================================================================
-
--define(TIMEOUT, 30000).
-
-start_system_subsystem(Controller, Sup, Host, Port, Profile, Options, ChildSpec) ->
- gen_server:call(Controller, {start_system_subsystem, Sup, Host, Port, Profile, Options, ChildSpec}, ?TIMEOUT).
-
-stop_system(Controller, SysSup) ->
- gen_server:call(Controller, {stop_system,SysSup}, ?TIMEOUT).
-
-%%====================================================================
-%% Internal process state
-%%====================================================================
--record(data, {
- role
- }).
-
-%%====================================================================
-%% Intitialisation
-%%====================================================================
-init([Role]=_Args) ->
- {ok, #data{role=Role}}.
-
-%%====================================================================
-%% gen_server callbacks
-%%====================================================================
-handle_call({start_system_subsystem, Sup, Address, Port, Profile, Options, ChildSpec}, _From, D) ->
- try
- {ok,SystemSup0} =
- case ssh_system_sup:system_supervisor(Address, Port, Profile) of
- undefined ->
- supervisor:start_child(Sup, ChildSpec);
- Pid ->
- {ok,Pid}
- end,
- {SystemSup0, ssh_system_sup:start_subsystem(SystemSup0, D#data.role, Address, Port, Profile, Options)}
- of
- {SystemSup, {ok,SubSysSup}} ->
- {reply, {ok,{SystemSup,SubSysSup}}, D}
- catch
- C:E:S ->
- {reply, {error,{failed,C,E,S}}, D}
- end;
-
-
-handle_call({stop_system,SysSup}, _From, D) ->
- try
- case supervisor:which_children(SysSup) of
- [] ->
- ssh_system_sup:stop_system(D#data.role, SysSup);
- _X ->
- ok
- end
- catch
- _:_ ->
- %% Already stopped (?)
- skip
- end,
- {reply, ok, D}.
-
-
-
-
-handle_cast(_Request, D) ->
- {noreply, D}.
diff --git a/lib/ssh/src/ssh_lib.erl b/lib/ssh/src/ssh_lib.erl
index c1553896fa..edfd1bb8a5 100644
--- a/lib/ssh/src/ssh_lib.erl
+++ b/lib/ssh/src/ssh_lib.erl
@@ -30,6 +30,8 @@
format_time_ms/1
]).
+-include("ssh.hrl").
+
%%%----------------------------------------------------------------
format_address_port({IP,Port}) when is_integer(Port) ->
format_address_port(IP, Port);
@@ -44,6 +46,8 @@ format_address_port(Address, Port) ->
end.
%%%----------------------------------------------------------------
+format_address(#address{address=A, port=P}) ->
+ format_address_port(A,P);
format_address(A) ->
try inet:ntoa(A)
catch
diff --git a/lib/ssh/src/ssh_server_channel.erl b/lib/ssh/src/ssh_server_channel.erl
index a7489847ff..11cdfbdf17 100644
--- a/lib/ssh/src/ssh_server_channel.erl
+++ b/lib/ssh/src/ssh_server_channel.erl
@@ -44,7 +44,7 @@
%%% Internal API
-export([start_link/5,
- get_print_info/1
+ get_print_info/1, get_print_info/2
]).
start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) ->
@@ -53,3 +53,6 @@ start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) ->
get_print_info(Pid) ->
ssh_client_channel:get_print_info(Pid).
+
+get_print_info(Pid, Arg) ->
+ ssh_client_channel:get_print_info(Pid, Arg).
diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl
index f16db5af6d..22997d863a 100644
--- a/lib/ssh/src/ssh_sftp.erl
+++ b/lib/ssh/src/ssh_sftp.erl
@@ -234,8 +234,8 @@ stop_channel(Pid) ->
receive {'DOWN',MonRef,_,_,_} -> ok
after
1000 ->
- exit(Pid, kill),
erlang:demonitor(MonRef, [flush]),
+ exit(Pid, kill),
ok
end;
false ->
diff --git a/lib/ssh/src/ssh_subsystem_sup.erl b/lib/ssh/src/ssh_subsystem_sup.erl
index 140b219b32..28a23d434b 100644
--- a/lib/ssh/src/ssh_subsystem_sup.erl
+++ b/lib/ssh/src/ssh_subsystem_sup.erl
@@ -29,10 +29,8 @@
-include("ssh.hrl").
-export([start_link/5,
- connection_supervisor/1,
- channel_supervisor/1,
- tcpip_fwd_supervisor/1,
- start_channel/8
+ start_channel/8,
+ tcpip_fwd_supervisor/1
]).
%% Supervisor callback
@@ -41,81 +39,72 @@
%%%=========================================================================
%%% API
%%%=========================================================================
-start_link(Role, Address, Port, Profile, Options) ->
- supervisor:start_link(?MODULE, [Role, Address, Port, Profile, Options]).
-
-connection_supervisor(SupPid) ->
- Children = supervisor:which_children(SupPid),
- ssh_connection_sup(Children).
-
-channel_supervisor(SupPid) when is_pid(SupPid) ->
- Children = supervisor:which_children(SupPid),
- ssh_channel_sup(Children).
-
-tcpip_fwd_supervisor(SupPid) when is_pid(SupPid) ->
- Children = supervisor:which_children(SupPid),
- tcpip_fwd_sup(Children).
+start_link(Role, Address=#address{}, Id, Socket, Options) ->
+ case supervisor:start_link(?MODULE, [Role, Address, Id, Socket, Options]) of
+ {error, {shutdown, {failed_to_start_child, _, Error}}} ->
+ {error,Error};
+ Other ->
+ Other
+ end.
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).
+tcpip_fwd_supervisor(SubSysSup) ->
+ find_child(tcpip_forward_acceptor_sup, SubSysSup).
+
+
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
-init([Role, Address, Port, Profile, Options]) ->
- SupFlags = #{strategy => one_for_all,
- intensity => 0,
- period => 3600
+init([Role, Address, Id, Socket, Options]) ->
+ SubSysSup = self(),
+ SupFlags = #{strategy => one_for_all,
+ auto_shutdown => any_significant,
+ intensity => 0,
+ period => 3600
},
- ChildSpecs = child_specs(Role, Address, Port, Profile, Options),
+ ChildSpecs = [#{id => connection,
+ restart => temporary,
+ type => worker,
+ significant => true,
+ start => {ssh_connection_handler,
+ start_link_ng,
+ [Role, Address, Id, Socket,
+ ?PUT_INTERNAL_OPT([
+ {subsystem_sup, SubSysSup}
+ ], Options)
+ ]
+ }
+ },
+ #{id => channel_sup,
+ restart => temporary,
+ type => supervisor,
+ start => {ssh_channel_sup, start_link, [Options]}
+ },
+
+ #{id => tcpip_forward_acceptor_sup,
+ restart => temporary,
+ type => supervisor,
+ start => {ssh_tcpip_forward_acceptor_sup, start_link, []}
+ }
+ ],
{ok, {SupFlags,ChildSpecs}}.
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
-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_tcpip_forward_acceptor_child_spec()].
-
-ssh_connection_child_spec(Role, Address, Port, _Profile, Options) ->
- #{id => id(Role, ssh_connection_sup, Address, Port),
- start => {ssh_connection_sup, start_link, [Options]},
- restart => temporary,
- type => supervisor
- }.
-
-ssh_channel_child_spec(Role, Address, Port, _Profile, Options) ->
- #{id => id(Role, ssh_channel_sup, Address, Port),
- start => {ssh_channel_sup, start_link, [Options]},
- restart => temporary,
- type => supervisor
- }.
-
-ssh_tcpip_forward_acceptor_child_spec() ->
- #{id => make_ref(),
- start => {ssh_tcpip_forward_acceptor_sup, start_link, []},
- restart => temporary,
- type => supervisor
- }.
-
-
-id(Role, Sup, Address, Port) ->
- {Role, Sup, Address, Port}.
-
-ssh_connection_sup([{_, Child, _, [ssh_connection_sup]} | _]) ->
- Child;
-ssh_connection_sup([_ | Rest]) ->
- ssh_connection_sup(Rest).
-
-ssh_channel_sup([{_, Child, _, [ssh_channel_sup]} | _]) ->
- Child;
-ssh_channel_sup([_ | Rest]) ->
- ssh_channel_sup(Rest).
-
-tcpip_fwd_sup([{_, Child, _, [ssh_tcpip_forward_acceptor_sup]} | _]) ->
- Child;
-tcpip_fwd_sup([_ | Rest]) ->
- tcpip_fwd_sup(Rest).
+channel_supervisor(SubSysSup) -> find_child(channel_sup, SubSysSup).
+
+find_child(Id, Sup) when is_pid(Sup) ->
+ try
+ {Id, Pid, _, _} = lists:keyfind(Id, 1, supervisor:which_children(Sup)),
+ Pid
+ catch
+ exit:{no_proc,_} ->
+ {error, no_proc};
+ _:_ ->
+ {error, {id_not_found,?MODULE,Id}}
+ end.
diff --git a/lib/ssh/src/ssh_sup.erl b/lib/ssh/src/ssh_sup.erl
deleted file mode 100644
index 61afbcd2ed..0000000000
--- a/lib/ssh/src/ssh_sup.erl
+++ /dev/null
@@ -1,49 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-%%----------------------------------------------------------------------
-%% Purpose: The top supervisor for the ssh application.
-%%----------------------------------------------------------------------
--module(ssh_sup).
-
--behaviour(supervisor).
-
--export([init/1]).
-
-%%%=========================================================================
-%%% Supervisor callback
-%%%=========================================================================
-init(_) ->
- SupFlags = #{strategy => one_for_one,
- intensity => 10,
- period => 3600
- },
- ChildSpecs = [#{id => sshd_sup,
- start => {sshd_sup, start_link, []},
- type => supervisor
- },
- #{id => sshc_sup,
- start => {sshc_sup, start_link, []},
- type => supervisor
- }
- ],
- {ok, {SupFlags,ChildSpecs}}.
-
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index d80fe3e296..7c9a81fe37 100644
--- a/lib/ssh/src/ssh_system_sup.erl
+++ b/lib/ssh/src/ssh_system_sup.erl
@@ -31,153 +31,216 @@
-include("ssh.hrl").
--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,
- stop_subsystem/2,
- get_options/4
+-export([start_link/3,
+ stop_listener/1,
+ stop_system/2,
+ start_system/3,
+ start_subsystem/4,
+ get_daemon_listen_address/1,
+ addresses/1,
+ addresses/2,
+ get_options/2
]).
%% Supervisor callback
-export([init/1]).
--define(START(Address, Port, Profile, Options),
- {ssh_acceptor_sup, start_link, [Address, Port, Profile, Options]}).
-
%%%=========================================================================
%%% API
%%%=========================================================================
-start_link(Role, Address, Port, Profile, Options) ->
- Name = make_name(Address, Port, Profile),
- supervisor:start_link({local, Name}, ?MODULE, [Role, Address, Port, Profile, Options]).
+
+start_system(Role, Address0, Options) ->
+ case find_system_sup(Role, Address0) of
+ {ok,{SysPid,Address}} ->
+ restart_acceptor(SysPid, Address, Options);
+ {error,not_found} ->
+ supervisor:start_child(sup(Role),
+ #{id => {?MODULE,Address0},
+ start => {?MODULE, start_link, [Role, Address0, Options]},
+ restart => temporary,
+ type => supervisor
+ })
+ end.
+
+%%%----------------------------------------------------------------
+stop_system(Role, SysSup) when is_pid(SysSup) ->
+ case lists:keyfind(SysSup, 2, supervisor:which_children(sup(Role))) of
+ {{?MODULE,Name}, SysSup, _, _} -> stop_system(Role, Name);
+ false -> undefind
+ end;
+stop_system(Role, Name) ->
+ supervisor:terminate_child(sup(Role), {?MODULE,Name}).
+
+
+%%%----------------------------------------------------------------
+stop_listener(SystemSup) when is_pid(SystemSup) ->
+ {Name, _, _, _} = lookup(ssh_acceptor_sup, SystemSup),
+ supervisor:terminate_child(SystemSup, Name),
+ supervisor:delete_child(SystemSup, Name).
+
+%%%----------------------------------------------------------------
+get_daemon_listen_address(SystemSup) ->
+ try lookup(ssh_acceptor_sup, SystemSup)
+ of
+ {{ssh_acceptor_sup,Address}, _, _, _} ->
+ {ok, Address};
+ _ ->
+ {error, not_found}
+ catch
+ _:_ ->
+ {error, not_found}
+ end.
+
+%%%----------------------------------------------------------------
+%%% Start the subsystem child. It is a child of the system supervisor (callback = this module)
+start_subsystem(Role, Address=#address{}, Socket, Options0) ->
+ Options = ?PUT_INTERNAL_OPT([{user_pid, self()}], Options0),
+ Id = make_ref(),
+ case get_system_sup(Role, Address, Options) of
+ {ok,SysPid} ->
+ case supervisor:start_child(SysPid,
+ #{id => Id,
+ start => {ssh_subsystem_sup, start_link,
+ [Role,Address,Id,Socket,Options]
+ },
+ restart => temporary,
+ significant => true,
+ type => supervisor
+ })
+ of
+ {ok,_SubSysPid} ->
+ try
+ receive
+ {new_connection_ref, Id, ConnPid} ->
+ ssh_connection_handler:takeover(ConnPid, Role, Socket, Options)
+ after 10000 ->
+
+ error(timeout)
+ end
+ catch
+ error:{badmatch,{error,Error}} ->
+ {error,Error};
+ error:timeout ->
+ %% The connection was started, but the takover procedure timed out,
+ %% therefor it exists a subtree, but it is not quite ready and
+ %% must be removed (by the supervisor above):
+ supervisor:terminate_child(SysPid, Id),
+ {error, connection_start_timeout}
+ end;
+ Others ->
+ Others
+ end;
+ Others ->
+ Others
+ end.
+
+
+%%%----------------------------------------------------------------
+start_link(Role, Address, Options) ->
+ supervisor:start_link(?MODULE, [Role, Address, Options]).
+
+
+%%%----------------------------------------------------------------
+addresses(Role) ->
+ addresses(Role, #address{address=any, port=any, profile=any}).
+
+addresses(Role, #address{address=Address, port=Port, profile=Profile}) ->
+ [{SysSup,A} || {{ssh_system_sup,A},SysSup,supervisor,_} <-
+ supervisor:which_children(sup(Role)),
+ Address == any orelse A#address.address == Address,
+ Port == any orelse A#address.port == Port,
+ Profile == any orelse A#address.profile == Profile].
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
-init([server, Address, Port, Profile, Options]) ->
- SupFlags = #{strategy => one_for_one,
+init([Role, Address, Options]) ->
+ SupFlags = #{strategy => one_for_one,
+ auto_shutdown => all_significant,
intensity => 0,
period => 3600
},
ChildSpecs =
- case ?GET_INTERNAL_OPT(connected_socket,Options,undefined) of
- undefined ->
- [#{id => id(ssh_acceptor_sup, Address, Port, Profile),
- start => ?START(Address,Port,Profile,Options),
- restart => transient,
- type => supervisor
- }];
+ case {Role, is_socket_server(Options)} of
+ {server, false} ->
+ [acceptor_sup_child_spec(_SysSup=self(), Address, Options)];
_ ->
[]
end,
- {ok, {SupFlags,ChildSpecs}};
-
-init([client, _Address, _Port, _Profile, _Options]) ->
- SupFlags = #{strategy => one_for_one,
- intensity => 0,
- period => 3600
- },
- ChildSpecs = [],
{ok, {SupFlags,ChildSpecs}}.
%%%=========================================================================
%%% Service API
%%%=========================================================================
-stop_listener(SystemSup) ->
- {Name, AcceptorSup, _, _} = lookup(ssh_acceptor_sup, SystemSup),
- case supervisor:terminate_child(AcceptorSup, Name) of
- ok ->
- supervisor:delete_child(AcceptorSup, Name);
- Error ->
- Error
- end.
-
-stop_listener(Address, Port, Profile) ->
- stop_listener(
- system_supervisor(Address, Port, Profile)).
-
-stop_system(server, SysSup) -> catch sshd_sup:stop_child(SysSup), ok;
-stop_system(client, SysSup) -> catch sshc_sup:stop_child(SysSup), ok.
+%% A macro to keep get_options/2 and acceptor_sup_child_spec/3 synchronized
+-define(accsup_start(SysSup,Addr,Opts),
+ {ssh_acceptor_sup, start_link, [SysSup,Addr,Opts]}
+ ).
-stop_system(server, Address, Port, Profile) ->
- catch sshd_sup:stop_child(Address, Port, Profile),
- ok.
-
-
-get_options(Sup, Address, Port, Profile) ->
+get_options(Sup, Address = #address{}) ->
+ %% Lookup the Option parameter in the running ssh_acceptor_sup:
try
- {ok, #{start:=?START(Address,Port,Profile,Options)}} =
- supervisor:get_childspec(Sup, id(ssh_acceptor_sup,Address,Port,Profile)),
- {ok, Options}
+ {ok, #{start:=?accsup_start(_, _, Options)}} =
+ supervisor:get_childspec(Sup, {ssh_acceptor_sup,Address}),
+ {ok, Options}
catch
_:_ -> {error,not_found}
end.
-system_supervisor(Address, Port, Profile) ->
- Name = make_name(Address, Port, Profile),
- whereis(Name).
-
-subsystem_supervisor(SystemSup) ->
- {_, Child, _, _} = lookup(ssh_subsystem_sup, SystemSup),
- Child.
-
-channel_supervisor(SystemSup) ->
- ssh_subsystem_sup:channel_supervisor(
- subsystem_supervisor(SystemSup)).
-
-connection_supervisor(SystemSup) ->
- ssh_subsystem_sup:connection_supervisor(
- subsystem_supervisor(SystemSup)).
-
-acceptor_supervisor(SystemSup) ->
- {_, Child, _, _} = lookup(ssh_acceptor_sup, SystemSup),
- Child.
-
-
-start_subsystem(SystemSup, Role, Address, Port, Profile, Options) ->
- SubsystemSpec =
- #{id => make_ref(),
- start => {ssh_subsystem_sup, start_link, [Role, Address, Port, Profile, Options]},
- restart => temporary,
- type => supervisor
- },
- supervisor:start_child(SystemSup, SubsystemSpec).
-
-stop_subsystem(SystemSup, SubSys) ->
- case catch lists:keyfind(SubSys, 2, supervisor:which_children(SystemSup)) of
- false ->
- {error, not_found};
- {Id, _, _, _} ->
- spawn(fun() -> supervisor:terminate_child(SystemSup, Id),
- supervisor:delete_child(SystemSup, Id) end),
- ok;
- {'EXIT', {noproc, _}} ->
- %% Already terminated; probably shutting down.
- ok;
- {'EXIT', {shutdown, _}} ->
- %% Already shutting down.
- ok
- end.
-
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
-id(Sup, Address, Port, Profile) ->
- {Sup, Address, Port, Profile}.
-
-make_name(Address, Port, Profile) ->
- list_to_atom(lists:flatten(io_lib:format("ssh_system_~s_~p_~p_sup", [fmt_host(Address), Port, Profile]))).
-
-fmt_host(IP) when is_tuple(IP) -> inet:ntoa(IP);
-fmt_host(A) when is_atom(A) -> A;
-fmt_host(S) when is_list(S) -> S.
+%% A separate function because this spec is need in >1 places
+acceptor_sup_child_spec(SysSup, Address, Options) ->
+ #{id => {ssh_acceptor_sup,Address},
+ start => ?accsup_start(SysSup, Address, Options),
+ restart => transient,
+ significant => true,
+ type => supervisor
+ }.
lookup(SupModule, SystemSup) ->
lists:keyfind([SupModule], 4,
supervisor:which_children(SystemSup)).
+get_system_sup(Role, Address0, Options) ->
+ case find_system_sup(Role, Address0) of
+ {ok,{SysPid,_Address}} ->
+ {ok,SysPid};
+ {error,not_found} ->
+ start_system(Role, Address0, Options);
+ {error,Error} ->
+ {error,Error}
+ end.
+
+find_system_sup(Role, Address0) ->
+ case addresses(Role, Address0) of
+ [{SysSupPid,Address}] -> {ok,{SysSupPid,Address}};
+ [] -> {error,not_found};
+ [_,_|_] -> {error,ambigous}
+ end.
+
+sup(client) -> sshc_sup;
+sup(server) -> sshd_sup.
+
+
+is_socket_server(Options) ->
+ undefined =/= ?GET_INTERNAL_OPT(connected_socket,Options,undefined).
+
+restart_acceptor(SysPid, Address, Options) ->
+ case lookup(ssh_acceptor_sup, SysPid) of
+ {_,_,supervisor,_} ->
+ {error, eaddrinuse};
+ false ->
+ ChildSpec = acceptor_sup_child_spec(SysPid, Address, Options),
+ case supervisor:start_child(SysPid, ChildSpec) of
+ {ok,_ChildPid} ->
+ {ok,SysPid}; % sic!
+ {ok,_ChildPid,_Info} ->
+ {ok,SysPid}; % sic!
+ {error,Error} ->
+ {error,Error}
+ end
+ end.
diff --git a/lib/ssh/src/sshc_sup.erl b/lib/ssh/src/sshc_sup.erl
deleted file mode 100644
index bbf3d16440..0000000000
--- a/lib/ssh/src/sshc_sup.erl
+++ /dev/null
@@ -1,109 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-%%----------------------------------------------------------------------
-%% 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,
- stop_child/1,
- stop_system/1
- ]).
-
-%% Supervisor callback
--export([init/1]).
-
--define(SSHC_SUP, ?MODULE).
-
-%%%=========================================================================
-%%% API
-%%%=========================================================================
-start_link() ->
- supervisor:start_link({local,?SSHC_SUP}, ?MODULE, []).
-
-start_child(Address, Port, Profile, Options) ->
- case ssh_system_sup:system_supervisor(Address, Port, Profile) of
- undefined ->
- %% Here we a new connction on a new Host/Port/Profile
- Spec = child_spec(Address, Port, Profile, Options),
- supervisor:start_child(?MODULE, Spec);
- Pid ->
- {ok,Pid}
- end.
-
-
-start_system_subsystem(Host, Port, Profile, Options) ->
- ssh_controller:start_system_subsystem(client_controller, ?MODULE, Host, Port, Profile, Options,
- child_spec(Host, Port, Profile, Options)
- ).
-
-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)).
-
-stop_system(SysSup) ->
- ssh_controller:stop_system(client_controller, SysSup).
-
-
-%%%=========================================================================
-%%% Supervisor callback
-%%%=========================================================================
-init(_) ->
- SupFlags = #{strategy => one_for_one,
- intensity => 0,
- period => 3600
- },
- ChildSpecs = [#{id => client_controller,
- start => {ssh_controller, start_link, [client, client_controller]},
- restart => permanent,
- type => worker
- }
- ],
- {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
deleted file mode 100644
index 6fd36bf97a..0000000000
--- a/lib/ssh/src/sshd_sup.erl
+++ /dev/null
@@ -1,114 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-%%----------------------------------------------------------------------
-%% Purpose: The ssh daemon top supervisor
-%%----------------------------------------------------------------------
-
--module(sshd_sup).
-
--behaviour(supervisor).
-
--include("ssh.hrl").
-
--export([start_link/0,
- start_child/3,
- start_system_subsystem/4,
- stop_child/1,
- stop_child/3
- ]).
-
-%% Supervisor callback
--export([init/1]).
-
--define(SSHD_SUP, ?MODULE).
-
-%%%=========================================================================
-%%% API
-%%%=========================================================================
-start_link() ->
- supervisor:start_link({local,?SSHD_SUP}, ?MODULE, []).
-
-start_child(Address, Port, Options) ->
- Profile = ?GET_OPT(profile,Options),
- case ssh_system_sup:system_supervisor(Address, Port, Profile) of
- undefined ->
- %% Here we start listening on a new Host/Port/Profile
- Spec = child_spec(Address, Port, Profile, Options),
- supervisor:start_child(?SSHD_SUP, Spec);
- Pid ->
- %% Here we resume listening on a new Host/Port/Profile after
- %% haveing stopped listening to he same with ssh:stop_listen(Pid)
- AccPid = ssh_system_sup:acceptor_supervisor(Pid),
- ssh_acceptor_sup:start_child(AccPid, 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)->
- stop_child(system_name(ChildPid)).
-
-
-stop_child(Address, Port, Profile) ->
- Id = id(Address, Port, Profile),
- stop_child(Id).
-
-%%%=========================================================================
-%%% Supervisor callback
-%%%=========================================================================
-init(_) ->
- SupFlags = #{strategy => one_for_one,
- intensity => 10,
- period => 3600
- },
- ChildSpecs = [#{id => daemon_controller,
- start => {ssh_controller, start_link, [server, daemon_controller]},
- restart => permanent,
- type => worker
- }
- ],
- {ok, {SupFlags,ChildSpecs}}.
-
-%%%=========================================================================
-%%% Internal functions
-%%%=========================================================================
-child_spec(Address, Port, Profile, Options) ->
- #{id => id(Address, Port, Profile),
- start => {ssh_system_sup, start_link, [server, Address, Port, Profile, Options]},
- restart => temporary,
- type => supervisor
- }.
-
-id(Address, Port, Profile) ->
- {server, ssh_system_sup, Address, Port, Profile}.
-
-system_name(SysSup) ->
- case lists:keyfind(SysSup, 2, supervisor:which_children(?SSHD_SUP)) of
- {Name, SysSup, _, _} -> Name;
- false -> undefind
- end.
-
diff --git a/lib/ssh/test/ssh.cover b/lib/ssh/test/ssh.cover
index aa0da36c75..daf6c723b9 100644
--- a/lib/ssh/test/ssh.cover
+++ b/lib/ssh/test/ssh.cover
@@ -6,7 +6,7 @@
ssh_app,
%% %% Supervisors
- %% ssh_acceptor_sup, ssh_channel_sup, ssh_connection_sup,
+ %% ssh_acceptor_sup, ssh_channel_sup,
%% sshc_sup, sshd_sup, ssh_subsystem_sup, ssh_sup,
%% ssh_system_sup, ssh_tcpip_forward_acceptor_sup,
diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl
index 49168d38bb..9daa887f6c 100644
--- a/lib/ssh/test/ssh_connection_SUITE.erl
+++ b/lib/ssh/test/ssh_connection_SUITE.erl
@@ -1179,7 +1179,7 @@ stop_listener(Config) when is_list(Config) ->
ConnectionRef0 = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
{user, "foo"},
{password, "morot"},
- {user_interaction, true},
+ {user_interaction, false},
{user_dir, UserDir}]),
{ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef0, infinity),
diff --git a/lib/ssh/test/ssh_limited.cover b/lib/ssh/test/ssh_limited.cover
index 2b0fcf5bf6..29c0121ae1 100644
--- a/lib/ssh/test/ssh_limited.cover
+++ b/lib/ssh/test/ssh_limited.cover
@@ -8,7 +8,7 @@
ssh_app,
%% Supervisors
- ssh_acceptor_sup, ssh_channel_sup, ssh_connection_sup,
+ ssh_acceptor_sup, ssh_channel_sup,
sshc_sup, sshd_sup, ssh_subsystem_sup, ssh_sup,
ssh_system_sup, ssh_tcpip_forward_acceptor_sup,
diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl
index 9e0e10c3bb..485bbe465f 100644
--- a/lib/ssh/test/ssh_sup_SUITE.erl
+++ b/lib/ssh/test/ssh_sup_SUITE.erl
@@ -50,6 +50,9 @@
-define(WAIT_FOR_SHUTDOWN, 500).
+-define(SSHC_SUP(Pid), {sshc_sup, Pid, supervisor,[sshc_sup]}).
+-define(SSHD_SUP(Pid), {sshd_sup, Pid, supervisor,[sshd_sup]}).
+
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
@@ -114,23 +117,22 @@ default_tree(Config) when is_list(Config) ->
lists:keysearch(sshc_sup, 1, TopSupChildren),
{value, {sshd_sup, _,supervisor,[sshd_sup]}} =
lists:keysearch(sshd_sup, 1, TopSupChildren),
- ?wait_match([{client_controller,_,worker,_}], supervisor:which_children(sshc_sup)),
- ?wait_match([{daemon_controller,_,worker,_}], supervisor:which_children(sshd_sup)).
+ ?wait_match([], supervisor:which_children(sshc_sup)),
+ ?wait_match([], supervisor:which_children(sshd_sup)).
%%-------------------------------------------------------------------------
sshc_subtree(Config) when is_list(Config) ->
{_Pid, Host, Port} = proplists:get_value(server, Config),
UserDir = proplists:get_value(userdir, Config),
- ?wait_match([{client_controller,_,worker,_}], supervisor:which_children(sshc_sup)),
+ ?wait_match([], supervisor:which_children(sshc_sup)),
{ok, Pid1} = ssh:connect(Host, Port, [{silently_accept_hosts, true},
{user_interaction, false},
{user, ?USER}, {password, ?PASSWD},{user_dir, UserDir}]),
- ?wait_match([{{client,ssh_system_sup, LocalIP, LocalPort, ?DEFAULT_PROFILE},
- SysSup, supervisor,[ssh_system_sup]},
- {client_controller,_,worker,_}
+ ?wait_match([{{ssh_system_sup, {address,LocalIP, LocalPort, ?DEFAULT_PROFILE}},
+ SysSup, supervisor,[ssh_system_sup]}
],
supervisor:which_children(sshc_sup),
[SysSup, LocalIP, LocalPort]),
@@ -140,18 +142,16 @@ sshc_subtree(Config) when is_list(Config) ->
{user_interaction, false},
{user, ?USER}, {password, ?PASSWD}, {user_dir, UserDir}]),
?wait_match([{_, _,supervisor,[ssh_system_sup]},
- {_, _,supervisor,[ssh_system_sup]},
- {client_controller,_,worker,_}
+ {_, _,supervisor,[ssh_system_sup]}
],
supervisor:which_children(sshc_sup)),
ssh:close(Pid1),
- ?wait_match([{_, _,supervisor,[ssh_system_sup]},
- {client_controller,_,worker,_}
+ ?wait_match([{_, _,supervisor,[ssh_system_sup]}
],
supervisor:which_children(sshc_sup)),
ssh:close(Pid2),
- ?wait_match([{client_controller,_,worker,_}], supervisor:which_children(sshc_sup)).
+ ?wait_match([], supervisor:which_children(sshc_sup)).
%%-------------------------------------------------------------------------
sshd_subtree(Config) when is_list(Config) ->
@@ -162,10 +162,10 @@ sshd_subtree(Config) when is_list(Config) ->
[{?USER, ?PASSWD}]}]),
ct:log("Expect HostIP=~p, Port=~p, Daemon=~p",[HostIP,Port,Daemon]),
- ?wait_match([{{server,ssh_system_sup, ListenIP, Port, ?DEFAULT_PROFILE},
+ ?wait_match([{{ssh_system_sup, {address,ListenIP, Port, ?DEFAULT_PROFILE}},
Daemon, supervisor,
- [ssh_system_sup]},
- {daemon_controller,_,worker,_}
+ [ssh_system_sup]
+ }
],
supervisor:which_children(sshd_sup),
[ListenIP,Daemon]),
@@ -173,7 +173,7 @@ sshd_subtree(Config) when is_list(Config) ->
check_sshd_system_tree(Daemon, HostIP, Port, Config),
ssh:stop_daemon(HostIP, Port),
ct:sleep(?WAIT_FOR_SHUTDOWN),
- ?wait_match([{daemon_controller,_,worker,_}], supervisor:which_children(sshd_sup)).
+ ?wait_match([], supervisor:which_children(sshd_sup)).
%%-------------------------------------------------------------------------
sshd_subtree_profile(Config) when is_list(Config) ->
@@ -186,17 +186,18 @@ sshd_subtree_profile(Config) when is_list(Config) ->
[{?USER, ?PASSWD}]},
{profile, Profile}]),
ct:log("Expect HostIP=~p, Port=~p, Profile=~p, Daemon=~p",[HostIP,Port,Profile,Daemon]),
- ?wait_match([{{server,ssh_system_sup, ListenIP,Port,Profile},
+ ?wait_match([{{ssh_system_sup, {address,ListenIP,Port,Profile}},
Daemon, supervisor,
- [ssh_system_sup]},
- {daemon_controller,_,worker,_}],
+ [ssh_system_sup]
+ }
+ ],
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([{daemon_controller,_,worker,_}], supervisor:which_children(sshd_sup)).
+ ?wait_match([], supervisor:which_children(sshd_sup)).
%%-------------------------------------------------------------------------
killed_acceptor_restarts(Config) ->
@@ -304,17 +305,27 @@ shell_channel_tree(Config) ->
{user_interaction, true},
{user_dir, UserDir}]),
- [ChannelSup|_] = Sups0 = chk_empty_con_daemon(Daemon),
+ [SubSysSup,ChPid|_] = Sups0 = chk_empty_con_daemon(Daemon),
{ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
ok = ssh_connection:shell(ConnectionRef,ChannelId0),
success = ssh_connection:ptty_alloc(ConnectionRef, ChannelId0, [{pty_opts,[{onlcr,1}]}]),
- ?wait_match([{_, GroupPid,worker,[ssh_server_channel]}],
- supervisor:which_children(ChannelSup),
- [GroupPid]),
+ ?wait_match([{connection,_,worker,[ssh_connection_handler]},
+ {_,_, supervisor,[ssh_tcpip_forward_acceptor_sup]},
+ {_,ChSup,supervisor,[ssh_channel_sup]}
+ ],
+ supervisor:which_children(SubSysSup),
+ [ChSup]),
+ ?wait_match([{_,GroupPid,worker,[ssh_server_channel]}
+ ],
+ supervisor:which_children(ChSup),
+ [GroupPid]),
+
+
{links,GroupLinks} = erlang:process_info(GroupPid, links),
- [ShellPid] = GroupLinks--[ChannelSup],
+ ct:log("GroupPid = ~p, GroupLinks = ~p Sups0 = ~p",[GroupPid,GroupLinks,Sups0]),
+ [ShellPid] = GroupLinks--[ChSup],
ct:log("GroupPid = ~p, ShellPid = ~p",[GroupPid,ShellPid]),
receive
@@ -355,110 +366,131 @@ shell_channel_tree(Config) ->
chk_empty_con_daemon(Daemon) ->
?wait_match([{_,SubSysSup, supervisor,[ssh_subsystem_sup]},
- {{ssh_acceptor_sup,_,_,_}, AccSup, supervisor,[ssh_acceptor_sup]}],
+ {{ssh_acceptor_sup,_}, AccSup, supervisor,[ssh_acceptor_sup]}],
supervisor:which_children(Daemon),
[SubSysSup,AccSup]),
- ?wait_match([{_,_, supervisor,
- [ssh_tcpip_forward_acceptor_sup]},
- {{server,ssh_connection_sup, _,_},
- ConnectionSup, supervisor,
- [ssh_connection_sup]},
- {{server,ssh_channel_sup,_ ,_},
- ChannelSup,supervisor,
- [ssh_channel_sup]}],
+ ?wait_match([{connection,ServerConnPid,worker,[ssh_connection_handler]},
+ {_,FwdAccSup, supervisor,[ssh_tcpip_forward_acceptor_sup]},
+ {_,ChSup,supervisor,[ssh_channel_sup]}
+ ],
supervisor:which_children(SubSysSup),
- [ConnectionSup,ChannelSup]),
- ?wait_match([{{ssh_acceptor_sup,_,_,_},_,worker,[ssh_acceptor]}],
- supervisor:which_children(AccSup)),
- ?wait_match([{_, _, worker,[gen_statem]}],
- supervisor:which_children(ConnectionSup)),
- ?wait_match([], supervisor:which_children(ChannelSup)),
- [ChannelSup, ConnectionSup, SubSysSup, AccSup].
+ [ChSup,FwdAccSup,ServerConnPid]),
+ ?wait_match([], supervisor:which_children(FwdAccSup)),
+ ?wait_match([], supervisor:which_children(ChSup)),
+ ?wait_match([{{ssh_acceptor_sup,_},_,worker,[ssh_acceptor]}],
+ supervisor:which_children(AccSup),
+ []),
+ [SubSysSup, ChSup, ServerConnPid, AccSup, FwdAccSup].
%%-------------------------------------------------------------------------
%% Help functions
%%-------------------------------------------------------------------------
check_sshd_system_tree(Daemon, Host, Port, Config) ->
UserDir = proplists:get_value(userdir, Config),
- {ok, Client} = ssh:connect(Host, Port, [{silently_accept_hosts, true},
- {user_interaction, false},
- {user, ?USER},
- {password, ?PASSWD},
- {user_dir, UserDir}]),
+ {ok, ClientConn} = ssh:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_interaction, false},
+ {user, ?USER},
+ {password, ?PASSWD},
+ {user_dir, UserDir}]),
?wait_match([{_,SubSysSup, supervisor,[ssh_subsystem_sup]},
- {{ssh_acceptor_sup,_,_,_}, AccSup, supervisor,[ssh_acceptor_sup]}],
+ {{ssh_acceptor_sup,_}, AccSup, supervisor,[ssh_acceptor_sup]}],
supervisor:which_children(Daemon),
[SubSysSup,AccSup]),
- ?wait_match([{_,
- _AcceptorSup, supervisor,
- [ssh_tcpip_forward_acceptor_sup]},
- {{server,ssh_connection_sup, _,_},
- ConnectionSup, supervisor,
- [ssh_connection_sup]},
- {{server,ssh_channel_sup,_ ,_},
- ChannelSup,supervisor,
- [ssh_channel_sup]}],
+ ?wait_match([{connection,ServerConn,worker,[ssh_connection_handler]},
+ {_,FwdAccSup, supervisor,[ssh_tcpip_forward_acceptor_sup]},
+ {_,_,supervisor,[ssh_channel_sup]}
+ ],
supervisor:which_children(SubSysSup),
- [ConnectionSup,ChannelSup]),
-
- ?wait_match([{{ssh_acceptor_sup,_,_,_},_,worker,[ssh_acceptor]}],
+ [FwdAccSup,ServerConn]),
+ ?wait_match([], supervisor:which_children(FwdAccSup)),
+
+ ?wait_match([{{ssh_acceptor_sup,_},_,worker,[ssh_acceptor]}],
supervisor:which_children(AccSup)),
- ?wait_match([{_, _, worker,[gen_statem]}],
- supervisor:which_children(ConnectionSup)),
-
- ?wait_match([], supervisor:which_children(ChannelSup)),
- {ok,PidC} = ssh_sftp:start_channel(Client),
+ {ok,PidC} = ssh_sftp:start_channel(ClientConn),
+ ?wait_match([{connection,ServerConn,worker,[ssh_connection_handler]},
+ {_,FwdAccSup, supervisor,[ssh_tcpip_forward_acceptor_sup]},
+ {_,ChSup,supervisor,[ssh_channel_sup]}
+ ],
+ supervisor:which_children(SubSysSup),
+ [ChSup,ServerConn]),
- ?wait_match([{_, PidS,worker,[ssh_server_channel]}],
- supervisor:which_children(ChannelSup),
+ ?wait_match([{_,PidS,worker,[ssh_server_channel]}],
+ supervisor:which_children(ChSup),
[PidS]),
true = (PidS =/= PidC),
+ ?wait_match([], supervisor:which_children(FwdAccSup)),
- ssh:close(Client).
+ ssh:close(ClientConn).
-check_sshc_system_tree(SysSup, Connection, LocalIP, LocalPort, _Config) ->
+check_sshc_system_tree(SysSup, Connection, _LocalIP, _LocalPort, _Config) ->
?wait_match([{_,SubSysSup,supervisor,[ssh_subsystem_sup]}],
supervisor:which_children(SysSup),
[SubSysSup]),
- ?wait_match([{_,FwdAccSup, supervisor,
- [ssh_tcpip_forward_acceptor_sup]},
- {{client,ssh_connection_sup, LocalIP, LocalPort},
- ConnectionSup, supervisor,
- [ssh_connection_sup]},
- {{client,ssh_channel_sup, LocalIP, LocalPort},
- ChannelSup,supervisor,
- [ssh_channel_sup]}],
+ ?wait_match([{connection,Connection,worker,[ssh_connection_handler]},
+ {_,FwdAccSup, supervisor,[ssh_tcpip_forward_acceptor_sup]},
+ {_,_,supervisor,[ssh_channel_sup]}
+ ],
supervisor:which_children(SubSysSup),
- [ConnectionSup,ChannelSup,FwdAccSup]),
- ?wait_match([{_, Connection, worker,[gen_statem]}],
- supervisor:which_children(ConnectionSup)),
- ?wait_match([], supervisor:which_children(ChannelSup)),
+ [FwdAccSup]),
?wait_match([], supervisor:which_children(FwdAccSup)),
{ok,ChPid1} = ssh_sftp:start_channel(Connection),
- ?wait_match([{_,ChPid1,worker,[ssh_client_channel]}],
- supervisor:which_children(ChannelSup)),
+ ?wait_match([{connection,Connection,worker,[ssh_connection_handler]},
+ {_,FwdAccSup, supervisor,[ssh_tcpip_forward_acceptor_sup]},
+ {_,ChSup,supervisor, [ssh_channel_sup]}
+ ],
+ supervisor:which_children(SubSysSup),
+ [ChSup,FwdAccSup]),
+
+ ?wait_match([{_,ChPid1,worker,[ssh_client_channel]}
+ ],
+ supervisor:which_children(ChSup),
+ [ChPid1]),
{ok,ChPid2} = ssh_sftp:start_channel(Connection),
- ?wait_match([{_,ChPidA,worker,[ssh_client_channel]},
- {_,ChPidB,worker,[ssh_client_channel]}],
- supervisor:which_children(ChannelSup),
- [ChPidA, ChPidB]),
- true = (lists:sort([ChPidA, ChPidB]) == lists:sort([ChPid1, ChPid2])),
+ ?wait_match([{connection,Connection,worker,[ssh_connection_handler]},
+ {_,FwdAccSup, supervisor,[ssh_tcpip_forward_acceptor_sup]},
+ {_,ChSup,supervisor, [ssh_channel_sup]}
+ ],
+ supervisor:which_children(SubSysSup),
+ [ChSup,FwdAccSup]),
+
+ ?wait_match([{_,ChPid2,worker,[ssh_client_channel]},
+ {_,ChPid1,worker,[ssh_client_channel]}
+ ],
+ supervisor:which_children(ChSup),
+ [ChPid1,ChPid2]),
ct:pal("Expect a SUPERVISOR REPORT with offender {pid,~p}....~n", [ChPid1]),
exit(ChPid1, kill),
- ?wait_match([{_,ChPid2,worker,[ssh_client_channel]}],
- supervisor:which_children(ChannelSup)),
+ ?wait_match([{connection,Connection,worker,[ssh_connection_handler]},
+ {_,FwdAccSup, supervisor,[ssh_tcpip_forward_acceptor_sup]},
+ {_,ChSup,supervisor, [ssh_channel_sup]}
+ ],
+ supervisor:which_children(SubSysSup),
+ [ChSup,FwdAccSup]),
+
+ ?wait_match([{_,ChPid2,worker,[ssh_client_channel]}
+ ],
+ supervisor:which_children(ChSup),
+ [ChPid2]),
ct:pal("Expect a SUPERVISOR REPORT with offender {pid,~p}....~n", [ChPid2]),
exit(ChPid2, kill),
- ?wait_match([], supervisor:which_children(ChannelSup)),
+ ?wait_match([{connection,Connection,worker,[ssh_connection_handler]},
+ {_,FwdAccSup, supervisor,[ssh_tcpip_forward_acceptor_sup]},
+ {_,ChSup,supervisor, [ssh_channel_sup]}
+ ],
+ supervisor:which_children(SubSysSup),
+ [ChSup,FwdAccSup]),
+
+ ?wait_match([], supervisor:which_children(ChSup)),
+
ct:pal("... now there should not be any SUPERVISOR REPORT.~n", []).
@@ -469,19 +501,16 @@ acceptor_pid(DaemonPid) ->
Parent ! {self(), supsearch,
[{AccPid,ListenAddr,Port}
- || {{server,ssh_system_sup,ListenAddr,Port,NS},
+ || {{ssh_system_sup,{address,ListenAddr,Port,NS}},
DPid,supervisor,
[ssh_system_sup]} <- supervisor:which_children(sshd_sup),
DPid == DaemonPid,
- {{ssh_acceptor_sup,L1,P1,NS1},
+ {{ssh_acceptor_sup,_},
AccSupPid,supervisor,
[ssh_acceptor_sup]} <- supervisor:which_children(DaemonPid),
- L1 == ListenAddr,
- P1 == Port,
- NS1 == NS1,
- {{ssh_acceptor_sup,L2,P2,NS2},
+ {{ssh_acceptor_sup,{address,L2,P2,NS2}},
AccPid,worker,
[ssh_acceptor]} <- supervisor:which_children(AccSupPid),
L2 == ListenAddr,