diff --git a/lib/ssh/internal_doc/ssh_notes.md b/lib/ssh/internal_doc/ssh_notes.md
index 2d3b8c25ebd4..ef8705fa153d 100644
--- a/lib/ssh/internal_doc/ssh_notes.md
+++ b/lib/ssh/internal_doc/ssh_notes.md
@@ -1,34 +1,73 @@
-# SSH supervision tree (prototype)
+# SSH supervision tree (server side update >= OTP-28)
```mermaid
---
-title: SSH supervision tree (prototype)
+title: SSH supervision tree
---
flowchart RL
- d_sup --> sup[["ssh_sup\n(ssh_app.erl)\n[o4o]"]]
+ d_sup --> sup[["ssh_sup
(ssh_app.erl)
[o4o]"]]
c_sup --> sup
subgraph client
- connection_sup --> c_sup[["sshc_sup\n(ssh_app.erl)\n[o4o]\nauto_shutdown=never"]]
+ connection_sup --> c_sup[["sshc_sup
(ssh_app.erl)
[o4o]
auto_shutdown=never"]]
subgraph connection_c
- connection_handler["ssh_connection_handler\nSIGNIFICANT"] --> connection_sup[["ssh_connection_sup\n[o4a]\nauto_shutdown=any_significant"]]
- channel_sup[["ssh_channel_sup\n[o4o]"]] --> connection_sup
+ connection_handler["ssh_connection_handler
SIGNIFICANT"] --> connection_sup[["ssh_connection_sup
[o4a]
auto_shutdown=any_significant"]]
+ channel_sup[["ssh_channel_sup
[o4o]"]] --> connection_sup
sftp["ssh_sftp"] --> channel_sup
- tcpip_forward_acceptor_sup[["ssh_tcpip_forward_acceptor_sup\n[o4o]"]] --> connection_sup
+ tcpip_forward_acceptor_sup[["ssh_tcpip_forward_acceptor_sup
[o4o]"]] --> connection_sup
+ ssh_tcpip_forward_acceptor["ssh_tcpip_forward_acceptor"] --> tcpip_forward_acceptor_sup
+ end
+ end
+
+ subgraph server
+ lsocket_sup[["ssh_lsocket_sup
[simple_one_for_one]"]] --> d_sup
+ ssh_lsocket_provider --> lsocket_sup
+ system_sup_s --> d_sup[["sshd_sup
(ssh_app.erl)
[o4o]"]]
+ acceptor_sup --> system_sup_s[["ssh_system_sup
[o4o]
auto_shutdown=all_significant"]]
+ acceptor["ssh_acceptor"] --> acceptor_sup[["ssh_acceptor_sup
[o4o?]
SIGNIFICANT"]]
+
+ connection_sup_s --> system_sup_s
+
+ subgraph connection_s
+ connection_handler_s["ssh_connection_handler
SIGNIFICANT"] --> connection_sup_s[["ssh_connection_sup
[o4a]
auto_shutdown=any_significant
SIGNIFICANT"]]
+ channel_sup_s[["ssh_channel_sup
[o4o]"]] --> connection_sup_s
+ tcpip_forward_acceptor_sup_s[["ssh_tcpip_forward_acceptor_sup
[o4o]"]] --> connection_sup_s
+ ssh_tcpip_forward_acceptor_s["ssh_tcpip_forward_acceptor"] --> tcpip_forward_acceptor_sup_s
+ sftd1["ssh_sftpd"] --> channel_sup_s
+ end
+ end
+```
+
+# SSH supervision tree (client side update since ssh-5.2.3, ssh-5.1.4.3, ssh-4.15.3.7)
+```mermaid
+---
+title: SSH supervision tree
+---
+flowchart RL
+ d_sup --> sup[["ssh_sup
(ssh_app.erl)
[o4o]"]]
+ c_sup --> sup
+
+ subgraph client
+ connection_sup --> c_sup[["sshc_sup
(ssh_app.erl)
[o4o]
auto_shutdown=never"]]
+ subgraph connection_c
+ connection_handler["ssh_connection_handler
SIGNIFICANT"] --> connection_sup[["ssh_connection_sup
[o4a]
auto_shutdown=any_significant"]]
+ channel_sup[["ssh_channel_sup
[o4o]"]] --> connection_sup
+ sftp["ssh_sftp"] --> channel_sup
+ tcpip_forward_acceptor_sup[["ssh_tcpip_forward_acceptor_sup
[o4o]"]] --> connection_sup
ssh_tcpip_forward_acceptor["ssh_tcpip_forward_acceptor"] --> tcpip_forward_acceptor_sup
end
end
subgraph server
- system_sup_s --> d_sup[["sshd_sup\n(ssh_app.erl)\n[o4o]"]]
- acceptor_sup --> system_sup_s[["ssh_system_sup\n[o4o]\nauto_shutdown=all_significant"]]
- acceptor["ssh_acceptor"] --> acceptor_sup[["ssh_acceptor_sup\n[o4o]\nSIGNIFICANT"]]
+ system_sup_s --> d_sup[["sshd_sup
(ssh_app.erl)
[o4o]"]]
+ acceptor_sup --> system_sup_s[["ssh_system_sup
[o4o]
auto_shutdown=all_significant"]]
+ acceptor["ssh_acceptor"] --> acceptor_sup[["ssh_acceptor_sup
[o4o]
SIGNIFICANT"]]
connection_sup_s --> system_sup_s
subgraph connection_s
- connection_handler_s["ssh_connection_handler\nSIGNIFICANT"] --> connection_sup_s[["ssh_connection_sup\n[o4a]\nauto_shutdown=any_significant\nSIGNIFICANT"]]
- channel_sup_s[["ssh_channel_sup\n[o4o]"]] --> connection_sup_s
- tcpip_forward_acceptor_sup_s[["ssh_tcpip_forward_acceptor_sup\n[o4o]"]] --> connection_sup_s
+ connection_handler_s["ssh_connection_handler
SIGNIFICANT"] --> connection_sup_s[["ssh_connection_sup
[o4a]
auto_shutdown=any_significant
SIGNIFICANT"]]
+ channel_sup_s[["ssh_channel_sup
[o4o]"]] --> connection_sup_s
+ tcpip_forward_acceptor_sup_s[["ssh_tcpip_forward_acceptor_sup
[o4o]"]] --> connection_sup_s
ssh_tcpip_forward_acceptor_s["ssh_tcpip_forward_acceptor"] --> tcpip_forward_acceptor_sup_s
sftd1["ssh_sftpd"] --> channel_sup_s
end
@@ -41,33 +80,32 @@ flowchart RL
title: SSH supervision tree (OTP >= 24)
---
flowchart RL
- d_sup --> sup[["ssh_sup\n(ssh_app.erl)\n[o4o]"]]
+ d_sup --> sup[["ssh_sup
(ssh_app.erl)
[o4o]"]]
c_sup --> sup
subgraph client
- system_sup --> c_sup[["sshc_sup\n(ssh_app.erl)\n[o4o]\nauto_shutdown=never"]]
+ system_sup --> c_sup[["sshc_sup
(ssh_app.erl)
[o4o]
auto_shutdown=never"]]
subgraph connection_c
- subsystem_sup --> system_sup[["ssh_system_sup\n[o4o]\nauto_shutdown=all_significant"]]
- connection_handler["ssh_connection_handler\nSIGNIFICANT"] --> subsystem_sup[["ssh_subsystem_sup\n[o4a]\nauto_shutdown=any_significant\nSIGNIFICANT"]]
- channel_sup[["ssh_channel_sup\n[o4o]"]] --> subsystem_sup
+ subsystem_sup --> system_sup[["ssh_system_sup
[o4o]
auto_shutdown=all_significant"]]
+ connection_handler["ssh_connection_handler
SIGNIFICANT"] --> subsystem_sup[["ssh_subsystem_sup
[o4a]
auto_shutdown=any_significant
SIGNIFICANT"]]
+ channel_sup[["ssh_channel_sup
[o4o]"]] --> subsystem_sup
sftp["ssh_sftp"] --> channel_sup
ssh_tcpip_forward_client --> channel_sup
- tcpip_forward_acceptor_sup[["ssh_tcpip_forward_acceptor_sup\n[o4o]"]] --> subsystem_sup
- ssh_tcpip_forward_acceptor["ssh_tcpip_forward_acceptor"] --> tcpip_forward_acceptor_sup
+ tcpip_forward_acceptor_sup[["ssh_tcpip_forward_acceptor_sup
[o4o]"]] --> subsystem_sup
end
end
subgraph server
- system_sup_s --> d_sup[["sshd_sup\n(ssh_app.erl)\n[o4o]"]]
- acceptor_sup --> system_sup_s[["ssh_system_sup\n[o4o]\nauto_shutdown=all_significant"]]
- acceptor["ssh_acceptor"] --> acceptor_sup[["ssh_acceptor_sup\n[o4o]\nSIGNIFICANT"]]
-
+ system_sup_s --> d_sup[["sshd_sup
(ssh_app.erl)
[o4o]"]]
+ acceptor_sup --> system_sup_s[["ssh_system_sup
[o4o]
auto_shutdown=all_significant"]]
+ acceptor["ssh_acceptor"] --> acceptor_sup[["ssh_acceptor_sup
[o4o]
SIGNIFICANT"]]
+ acceptor_worker["acceptor
(parallel_login)"] o-. link .-o acceptor
subsystem_sup_s --> system_sup_s
subgraph connection_s
- connection_handler_s["ssh_connection_handler\nSIGNIFICANT"] --> subsystem_sup_s[["ssh_subsystem_sup\n[o4a]\nauto_shutdown=any_significant\nSIGNIFICANT"]]
- channel_sup_s[["ssh_channel_sup\n[o4o]"]] --> subsystem_sup_s
- tcpip_forward_acceptor_sup_s[["ssh_tcpip_forward_acceptor_sup\n[o4o]"]] --> subsystem_sup_s
+ connection_handler_s["ssh_connection_handler
SIGNIFICANT"] --> subsystem_sup_s[["ssh_subsystem_sup
[o4a]
auto_shutdown=any_significant
SIGNIFICANT"]]
+ channel_sup_s[["ssh_channel_sup
[o4o]"]] --> subsystem_sup_s
+ tcpip_forward_acceptor_sup_s[["ssh_tcpip_forward_acceptor_sup
[o4o]"]] --> subsystem_sup_s
ssh_tcpip_forward_acceptor_s["ssh_tcpip_forward_acceptor"] --> tcpip_forward_acceptor_sup_s
sftd1["ssh_sftpd"] --> channel_sup_s
ssh_tcpip_forward_srv --> channel_sup_s
@@ -83,24 +121,24 @@ flowchart RL
title: SSH supervision tree (OTP-22)
---
flowchart RL
- d_sup --> sup[["ssh_sup\n(ssh_app.erl)\n[o4o]"]]
+ d_sup --> sup[["ssh_sup
(ssh_app.erl)
[o4o]"]]
c_sup --> sup
subgraph client
- connection_handler["ssh_connection_handler\nSIGNIFICANT?"] --> c_sup
+ connection_handler["ssh_connection_handler
SIGNIFICANT?"] --> c_sup
end
subgraph server
- system_sup_s --> d_sup[["sshd_sup\n(ssh_app.erl)\n[o4o]"]]
- acceptor_sup --> system_sup_s[["ssh_system_sup\n[o4o]\nauto_shutdown=all_significant"]]
- acceptor["ssh_acceptor"] --> acceptor_sup[["ssh_acceptor_sup\n[o4o]\nSIGNIFICANT"]]
+ system_sup_s --> d_sup[["sshd_sup
(ssh_app.erl)
[o4o]"]]
+ acceptor_sup --> system_sup_s[["ssh_system_sup
[o4o]
auto_shutdown=all_significant"]]
+ acceptor["ssh_acceptor"] --> acceptor_sup[["ssh_acceptor_sup
[o4o]
SIGNIFICANT"]]
subsystem_sup_s --> system_sup_s
subgraph connection_s
- connection_handler_s["ssh_connection_handler\nSIGNIFICANT"] --> subsystem_sup_s[["ssh_subsystem_sup\n[o4a]\nauto_shutdown=any_significant\nSIGNIFICANT"]]
- channel_sup_s[["ssh_channel_sup\n[o4o]"]] --> subsystem_sup_s
- tcpip_forward_acceptor_sup_s[["ssh_tcpip_forward_acceptor_sup\n[o4o]"]] --> subsystem_sup_s
+ connection_handler_s["ssh_connection_handler
SIGNIFICANT"] --> subsystem_sup_s[["ssh_subsystem_sup
[o4a]
auto_shutdown=any_significant
SIGNIFICANT"]]
+ channel_sup_s[["ssh_channel_sup
[o4o]"]] --> subsystem_sup_s
+ tcpip_forward_acceptor_sup_s[["ssh_tcpip_forward_acceptor_sup
[o4o]"]] --> subsystem_sup_s
sftd1["ssh_sftpd"] --> channel_sup_s
end
end
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index fdff8042ebf8..c651d336fbc0 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -596,12 +596,16 @@ daemon(Host0, Port0, UserOptions0)
case ssh_options:handle_options(server, UserOptions) of
#{} = Options0 ->
case ssh_lsocket:get_lsocket(Host1, Port0, Options0) of
- {ok, LSocketProvider, {ok, LSocket}} ->
- {Host, Port, Options1} = update_lsocket(LSocket, LSocketProvider, Options0),
+ {ok, {LSocketProvider, LSocket}} ->
+ {Host, Port, Options1} =
+ update_lsocket(LSocket, LSocketProvider, Options0),
try
- %% Now Host,Port is what to use for the supervisor to register its name,
- %% and ListenSocket, if provided, is for listening on connections. But
- %% it is still owned by self()...
+ %% Host,Port is what to use for the system
+ %% supervisor to register its name (see
+ %% #address record); LSocket is owned by
+ %% LSocketProvider process. Ownership will be
+ %% transferred once ssh_acceptor_sup is
+ %% started.
%% throws error:Error if no usable hostkey is found
ssh_connection_handler:available_hkey_algorithms(server, Options1),
@@ -610,32 +614,31 @@ daemon(Host0, Port0, UserOptions0)
profile = ?GET_OPT(profile,Options1)},
Options1)
of
- {ok,DaemonRef} ->
- {ok,DaemonRef};
- {error, {already_started, _}} ->
+ {ok, DaemonRef} ->
+ {ok, DaemonRef};
+ {error, {already_started, _}} -> % ssh_system_sup with #address already register
close_listen_socket(LSocket, Options1),
{error, eaddrinuse};
{error, Error} ->
close_listen_socket(LSocket, Options1),
{error, Error}
catch
- error:{shutdown,Err} ->
+ error:{shutdown, Err} -> % no suitable host key
close_listen_socket(LSocket, Options1),
- {error,Err};
- exit:{noproc, _} ->
+ {error, Err};
+ exit:{noproc, _} -> % ssh application not started
close_listen_socket(LSocket, Options1),
{error, ssh_not_started};
error:Error ->
close_listen_socket(LSocket, Options1),
- error(Error);
- exit:Exit ->
- close_listen_socket(LSocket, Options1),
- exit(Exit)
+ {error, Error};
+ _C:_E ->
+ {error,{cannot_start_daemon,_C,_E}}
end;
- Error = {error, _} ->
- Error
+ {error, {_, LSocketError}} ->
+ {error, LSocketError}
end;
- OptionError = {error,_} ->
+ OptionError = {error, _} ->
OptionError
end;
daemon(_, _, _) ->
diff --git a/lib/ssh/src/ssh_lsocket.erl b/lib/ssh/src/ssh_lsocket.erl
index c4d9853c0c67..e92d88bac157 100644
--- a/lib/ssh/src/ssh_lsocket.erl
+++ b/lib/ssh/src/ssh_lsocket.erl
@@ -26,47 +26,53 @@
-moduledoc false.
-include("ssh.hrl").
--export([start_link/4, provide_lsocket/5, get_lsocket/3]).
+-export([start_link/4, provide_lsocket/4, get_lsocket/3]).
-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, ssh_dbg_format/3]).
get_lsocket(Host, Port, Options) ->
- supervisor:start_child(ssh_lsocket_sup, [self(), Host, Port, Options]).
+ try
+ supervisor:start_child(ssh_lsocket_sup, [self(), Host, Port, Options])
+ of
+ {ok, LSocketProvider} ->
+ receive
+ Result = {_, {LSocketProvider, _}} ->
+ Result
+ after
+ ?DEFAULT_TIMEOUT ->
+ {error, LSocketProvider, no_response_from_lsocket_provider}
+ end
+ catch
+ exit:{noproc, _} ->
+ {error, {no_provider_pid, ssh_not_started}}
+ end.
start_link(Caller, Host, Port, Options) ->
- proc_lib:start_link(?MODULE, provide_lsocket,
- [self(), Caller, Host, Port, Options]).
+ {ok, proc_lib:spawn_link(?MODULE, provide_lsocket,
+ [Caller, Host, Port, Options])}.
-provide_lsocket(Parent, _Caller, _Host1, Port0, Options) ->
- OpenResult =
+provide_lsocket(Caller, _Host1, Port0, Options) ->
+ ListenResult =
try
try_listen(Port0, Options, 4)
of
{ok, LSocket} ->
- {ok, LSocket};
- Others ->
- Others
+ {ok, {self(), LSocket}};
+ {error, Details} ->
+ {error, {self(), Details}}
catch
- throw:bad_fd ->
- {error,bad_fd};
- throw:bad_socket ->
- {error,bad_socket};
- error:{badmatch, {error,Error}} ->
- {error,Error};
- error:Error ->
- {error,Error};
- _C:_E ->
- {error,{cannot_start_daemon,_C,_E}}
+ _Class:Exception ->
+ {error, {self(), Exception}}
end,
- case OpenResult of
- {ok, LSocket1} ->
- proc_lib:init_ack(Parent, {ok, self(), OpenResult}),
+ case ListenResult of
+ {ok, {_, LSocket1}} ->
+ Caller ! ListenResult,
wait_for_acceptor_sup(LSocket1, Options),
ok;
- {error, _} ->
- proc_lib:init_fail(Parent, OpenResult, {exit, normal})
+ {error, {_, _}} ->
+ Caller ! ListenResult
end.
wait_for_acceptor_sup(ListenSocket, Options) ->
@@ -118,14 +124,14 @@ ssh_dbg_trace_points() -> [connections].
ssh_dbg_flags(connections) -> [c].
ssh_dbg_on(connections) ->
- dbg:tpl(?MODULE, provide_lsocket, 5, x),
+ dbg:tpl(?MODULE, provide_lsocket, 4, x),
dbg:tpl(?MODULE, controlling_process, 3, x),
dbg:tpl(?MODULE, try_listen, 4, x),
dbg:tpl(?MODULE, wait_for_acceptor_sup, 2, x);
ssh_dbg_on(tcp) -> dbg:tpl(?MODULE, accept, 3, x).
ssh_dbg_off(connections) ->
- dbg:ctpl(?MODULE, provide_lsocket, 5),
+ dbg:ctpl(?MODULE, provide_lsocket, 4),
dbg:ctpl(?MODULE, controlling_process, 3),
dbg:ctpl(?MODULE, try_listen, 4),
dbg:ctpl(?MODULE, wait_for_acceptor_sup, 2);
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index 7aaeb4603dee..6a55954bd0ac 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -229,7 +229,6 @@ handle_options(Role, OptsList0, Opts0) when is_map(Opts0),
%% Enter the user's values into the map; unknown keys are
%% treated as socket options
check_and_save(OptsList2, OptionDefinitions, InitialMap)
-
catch
error:{EO, KV, Reason} when EO == eoptions ; EO == eerl_env ->
if
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index 676c75f27fa6..f6b78d4e738f 100644
--- a/lib/ssh/src/ssh_system_sup.erl
+++ b/lib/ssh/src/ssh_system_sup.erl
@@ -285,12 +285,12 @@ refresh_lsocket(Options0) ->
{_OldLSock, LHost, LPort, _SockOwner} =
?GET_INTERNAL_OPT(lsocket, Options0, lsocket_undefined),
case ssh_lsocket:get_lsocket(LHost, LPort, Options0) of
- {ok, LSocketProvider, {ok, LSocket}} ->
+ {ok, {LSocketProvider, LSocket}} ->
{_Host, _Port, Options} =
ssh:update_lsocket(LSocket, LSocketProvider, Options0),
Options;
- {error, Error} ->
- {error, Error}
+ Error = {error, _} ->
+ Error
end.
%%%################################################################