diff options
author | Hans Nilsson <hans@erlang.org> | 2021-12-29 15:47:59 +0100 |
---|---|---|
committer | Hans Nilsson <hans@erlang.org> | 2022-02-24 11:27:09 +0100 |
commit | 96311781a4cf934fa9ed8ecbd72741602a5966d5 (patch) | |
tree | 1de6ae1368e19edb1f442ed9115b8810eda64c3e /lib | |
parent | 7bf7f01683acf9b8f09bd8c7331854a9abc17f7d (diff) | |
download | erlang-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.erl | 92 | ||||
-rw-r--r-- | lib/ssh/src/ssh_connection_handler.erl | 5 |
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), |