summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorHans Nilsson <hans@erlang.org>2021-12-29 15:47:59 +0100
committerHans Nilsson <hans@erlang.org>2022-02-24 11:27:09 +0100
commit96311781a4cf934fa9ed8ecbd72741602a5966d5 (patch)
tree1de6ae1368e19edb1f442ed9115b8810eda64c3e /lib
parent7bf7f01683acf9b8f09bd8c7331854a9abc17f7d (diff)
downloaderlang-96311781a4cf934fa9ed8ecbd72741602a5966d5.tar.gz
ssh: Fix parallel_login option and an intermediate controlling proc
This option was erroneously not implemented when the state machine was re-strutctured for the OTP-24.0 release. The intermedite process is needed when parallel login is allowed. Otherwise all logins would be handled sequentially.
Diffstat (limited to 'lib')
-rw-r--r--lib/ssh/src/ssh_acceptor.erl92
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl5
2 files changed, 63 insertions, 34 deletions
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index faa27583b0..00587eecba 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -133,47 +133,73 @@ acceptor_loop(Port, Address, Opts, ListenSocket, AcceptTimeout, SystemSup) ->
try
case accept(ListenSocket, AcceptTimeout, Opts) of
{ok,Socket} ->
- case inet:peername(Socket) of
- {ok, {FromIP,FromPort}} ->
- case handle_connection(SystemSup, Address, Port, Opts, Socket) of
- {error,Error} ->
- catch close(Socket, Opts),
- handle_error(Error, Address, Port, FromIP, FromPort);
- _ ->
- ok
- end;
+ PeerName = inet:peername(Socket),
+ MaxSessions = ?GET_OPT(max_sessions, Opts),
+ NumSessions = number_of_connections(SystemSup),
+ ParallelLogin = ?GET_OPT(parallel_login, Opts),
+ case handle_connection(Address, Port, PeerName, Opts, Socket, MaxSessions, NumSessions, ParallelLogin) of
{error,Error} ->
- handle_error(Error, Address, Port)
+ catch close(Socket, Opts),
+ handle_error(Error, Address, Port, PeerName);
+ _ ->
+ ok
end;
{error,Error} ->
- handle_error(Error, Address, Port)
+ handle_error(Error, Address, Port, undefined)
end
catch
Class:Err:Stack ->
- handle_error({error, {unhandled,Class,Err,Stack}}, Address, Port)
+ handle_error({error, {unhandled,Class,Err,Stack}}, Address, Port, undefined)
end,
?MODULE:acceptor_loop(Port, Address, Opts, ListenSocket, AcceptTimeout, SystemSup).
%%%----------------------------------------------------------------
-handle_connection(SystemSup, Address, Port, Options0, Socket) ->
- MaxSessions = ?GET_OPT(max_sessions, Options0),
- case number_of_connections(SystemSup) < MaxSessions of
- true ->
- 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.
+handle_connection(_Address, _Port, _Peer, _Options, _Socket, MaxSessions, NumSessions, _ParallelLogin)
+ when NumSessions >= MaxSessions->
+ {error,{max_sessions,MaxSessions}};
+
+handle_connection(_Address, _Port, {error,Error}, _Options, _Socket, _MaxSessions, _NumSessions, _ParallelLogin) ->
+ {error,Error};
+
+handle_connection(Address, Port, _Peer, Options, Socket, _MaxSessions, _NumSessions, ParallelLogin)
+ when ParallelLogin == false ->
+ handle_connection(Address, Port, Options, Socket);
+
+handle_connection(Address, Port, _Peer, Options, Socket, _MaxSessions, _NumSessions, ParallelLogin)
+ when ParallelLogin == true ->
+ Ref = make_ref(),
+ Pid = spawn_link(
+ fun() ->
+ process_flag(trap_exit, true),
+ receive
+ {start,Ref} ->
+ handle_connection(Address, Port, Options, Socket)
+ after 10000 ->
+ {error, timeout2}
+ end
+ end),
+ catch gen_tcp:controlling_process(Socket, Pid),
+ Pid ! {start,Ref},
+ ok.
+
+
+
+handle_connection(Address, Port, Options0, Socket) ->
+ 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).
%%%----------------------------------------------------------------
-handle_error(Reason, ToAddress, ToPort) ->
+handle_error(Reason, ToAddress, ToPort, {ok, {FromIP,FromPort}}) ->
+ handle_error(Reason, ToAddress, ToPort, FromIP, FromPort);
+
+handle_error(Reason, ToAddress, ToPort, _) ->
handle_error(Reason, ToAddress, ToPort, undefined, undefined).
@@ -236,14 +262,14 @@ ssh_dbg_on(tcp) -> dbg:tp(?MODULE, listen, 2, x),
dbg:tpl(?MODULE, close, 2, x);
ssh_dbg_on(connections) -> dbg:tp(?MODULE, acceptor_init, 4, x),
- dbg:tpl(?MODULE, handle_connection, 5, x).
+ dbg:tpl(?MODULE, handle_connection, 4, x).
ssh_dbg_off(tcp) -> dbg:ctpg(?MODULE, listen, 2),
dbg:ctpl(?MODULE, accept, 3),
dbg:ctpl(?MODULE, close, 2);
ssh_dbg_off(connections) -> dbg:ctp(?MODULE, acceptor_init, 4),
- dbg:ctp(?MODULE, handle_connection, 5).
+ dbg:ctp(?MODULE, handle_connection, 4).
ssh_dbg_format(tcp, {call, {?MODULE,listen, [Port,_Opts]}}, Stack) ->
{skip, [{port,Port}|Stack]};
@@ -287,9 +313,9 @@ ssh_dbg_format(connections, {call, {?MODULE,acceptor_init, [_Parent, _SysSup, Ad
ssh_dbg_format(connections, {return_from, {?MODULE,acceptor_init,4}, _Ret}) ->
skip;
-ssh_dbg_format(connections, {call, {?MODULE,handle_connection,[_SystemSup,_Address,_Port,_Options,_Sock]}}) ->
+ssh_dbg_format(connections, {call, {?MODULE,handle_connection,[_Address,_Port,_Options,_Sock]}}) ->
skip;
-ssh_dbg_format(connections, {return_from, {?MODULE,handle_connection,5}, {error,Error}}) ->
+ssh_dbg_format(connections, {return_from, {?MODULE,handle_connection,4}, {error,Error}}) ->
["Starting connection to server failed:\n",
io_lib:format("Error = ~p", [Error])
].
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 886f31bf4b..fd647213dc 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -514,7 +514,10 @@ handshake(Pid, Ref, Timeout) ->
{'DOWN', Ref, process, Pid, {shutdown, Reason}} ->
{error, Reason};
{'DOWN', Ref, process, Pid, Reason} ->
- {error, Reason}
+ {error, Reason};
+ {'EXIT',_,Reason} ->
+ stop(Pid),
+ {error, {exit,Reason}}
after Timeout ->
erlang:demonitor(Ref, [flush]),
ssh_connection_handler:stop(Pid),