diff options
Diffstat (limited to 'lib/ssh')
-rw-r--r-- | lib/ssh/doc/src/notes.xml | 95 | ||||
-rw-r--r-- | lib/ssh/doc/src/ssh.xml | 6 | ||||
-rw-r--r-- | lib/ssh/src/ssh.appup.src | 16 | ||||
-rw-r--r-- | lib/ssh/src/ssh.erl | 32 | ||||
-rw-r--r-- | lib/ssh/src/ssh_connection_handler.erl | 28 | ||||
-rw-r--r-- | lib/ssh/src/ssh_io.erl | 2 | ||||
-rw-r--r-- | lib/ssh/src/ssh_message.erl | 27 | ||||
-rw-r--r-- | lib/ssh/test/ssh_basic_SUITE.erl | 246 | ||||
-rw-r--r-- | lib/ssh/vsn.mk | 2 |
9 files changed, 387 insertions, 67 deletions
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml index bce02966ae..60440d3a80 100644 --- a/lib/ssh/doc/src/notes.xml +++ b/lib/ssh/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2004</year><year>2013</year> + <year>2004</year><year>2014</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -29,6 +29,99 @@ <file>notes.xml</file> </header> +<section><title>Ssh 3.0.4</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + When starting an ssh-daemon giving the option + {parallel_login, true}, the timeout for authentication + negotiation ({negotiation_timeout, integer()}) was never + removed.</p> + <p> + This caused the session to always be terminated after the + timeout if parallel_login was set.</p> + <p> + Own Id: OTP-12057 Aux Id: seq12663 </p> + </item> + </list> + </section> + +</section> + +<section><title>Ssh 3.0.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Removed mail address from error reports and corrected + spelling error (Stacktace -> stacktrace)</p> + <p> + Own Id: OTP-11883 Aux Id: seq12586 </p> + </item> + <item> + <p> + Decode/encode fixes in SSH_MSG_IGNORE and + SSH_MSG_UNIMPLEMENTED.</p> + <p> + Own Id: OTP-11983</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Accepts that some older OpenSSH clients sends incorrect + disconnect messages.</p> + <p> + Own Id: OTP-11972</p> + </item> + <item> + <p> + Handle inet and inet6 option correctly</p> + <p> + Own Id: OTP-11976</p> + </item> + </list> + </section> + +</section> + +<section><title>Ssh 3.0.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed timeout bug in ssh:connect.</p> + <p> + Own Id: OTP-11908</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Option <c>max_sessions</c> added to + <c>ssh:daemon/{2,3}</c>. This option, if set, limits the + number of simultaneous connections accepted by the + daemon.</p> + <p> + Own Id: OTP-11885</p> + </item> + </list> + </section> + +</section> + <section><title>Ssh 3.0.1</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml index 5a141ced3c..876eba598a 100644 --- a/lib/ssh/doc/src/ssh.xml +++ b/lib/ssh/doc/src/ssh.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2004</year><year>2013</year> + <year>2004</year><year>2014</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -97,6 +97,8 @@ <seealso marker="ssh_connection#session_channel/2">ssh_connection:session_channel/[2, 4]</seealso>.</p> <p>Options are:</p> <taglist> + <tag><c><![CDATA[{inet, inet | inet6}]]></c></tag> + <item> IP version to use.</item> <tag><c><![CDATA[{user_dir, string()}]]></c></tag> <item> <p>Sets the user directory i.e. the directory containing @@ -230,6 +232,8 @@ port.</p> <p>Options are:</p> <taglist> + <tag><c><![CDATA[{inet, inet | inet6}]]></c></tag> + <item> IP version to use when the host address is specified as <c>any</c>. </item> <tag><c><![CDATA[{subsystems, [subsystem_spec()]]]></c></tag> <item> Provides specifications for handling of subsystems. The diff --git a/lib/ssh/src/ssh.appup.src b/lib/ssh/src/ssh.appup.src index 1917c95f5a..8269f89e40 100644 --- a/lib/ssh/src/ssh.appup.src +++ b/lib/ssh/src/ssh.appup.src @@ -19,9 +19,25 @@ {"%VSN%", [ + {"3.0.2", [{load_module, ssh_message, soft_purge, soft_purge, []}, + {load_module, ssh_connection_handler, soft_purge, soft_purge, []}, + {load_module, ssh_io, soft_purge, soft_purge, []}]}, + {"3.0.1", [{load_module, ssh, soft_purge, soft_purge, []}, + {load_module, ssh_acceptor, soft_purge, soft_purge, []}, + {load_module, ssh_message, soft_purge, soft_purge, []}, + {load_module, ssh_connection_handler, soft_purge, soft_purge, []}, + {load_module, ssh_io, soft_purge, soft_purge, []}]}, {<<".*">>, [{restart_application, ssh}]} ], [ + {"3.0.2", [{load_module, ssh_message, soft_purge, soft_purge, []}, + {load_module, ssh_connection_handler, soft_purge, soft_purge, []}, + {load_module, ssh_io, soft_purge, soft_purge, []}]}, + {"3.0.1", [{load_module, ssh, soft_purge, soft_purge, []}, + {load_module, ssh_acceptor, soft_purge, soft_purge, []}, + {load_module, ssh_message, soft_purge, soft_purge, []}, + {load_module, ssh_connection_handler, soft_purge, soft_purge, []}, + {load_module, ssh_io, soft_purge, soft_purge, []}]}, {<<".*">>, [{restart_application, ssh}]} ] }. diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index 240de69eff..743c01a42c 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -74,8 +74,7 @@ connect(Host, Port, Options, Timeout) -> {_, Transport, _} = TransportOpts = proplists:get_value(transport, Options, {tcp, gen_tcp, tcp_closed}), ConnectionTimeout = proplists:get_value(connect_timeout, Options, infinity), - Inet = proplists:get_value(inet, SshOptions, inet), - try Transport:connect(Host, Port, [ {active, false}, Inet | SocketOptions], ConnectionTimeout) of + try Transport:connect(Host, Port, [ {active, false} | SocketOptions], ConnectionTimeout) of {ok, Socket} -> Opts = [{user_pid, self()}, {host, Host} | fix_idle_time(SshOptions)], ssh_connection_handler:start_connection(client, Socket, Opts, Timeout); @@ -256,8 +255,8 @@ do_start_daemon(Host, Port, Options, SocketOptions) -> handle_options(Opts) -> try handle_option(proplists:unfold(Opts), [], []) of - {_,_} = Options -> - Options + {Inet, Ssh} -> + {handle_ip(Inet), Ssh} catch throw:Error -> Error @@ -433,13 +432,14 @@ handle_ssh_option(Opt) -> throw({error, {eoptions, Opt}}). handle_inet_option({active, _} = Opt) -> - throw({error, {{eoptions, Opt}, "Ssh has built in flow control, " - "and activ is handled internaly user is not allowd" + throw({error, {{eoptions, Opt}, "SSH has built in flow control, " + "and active is handled internally, user is not allowed" "to specify this option"}}); -handle_inet_option({inet, Value} = Opt) when (Value == inet) or (Value == inet6) -> - Opt; + +handle_inet_option({inet, Value}) when (Value == inet) or (Value == inet6) -> + Value; handle_inet_option({reuseaddr, _} = Opt) -> - throw({error, {{eoptions, Opt},"Is set internaly user is not allowd" + throw({error, {{eoptions, Opt},"Is set internally, user is not allowed" "to specify this option"}}); %% Option verified by inet handle_inet_option(Opt) -> @@ -460,3 +460,17 @@ handle_pref_algs([H|T], Acc) -> _ -> false end. + +handle_ip(Inet) -> %% Default to ipv4 + case lists:member(inet, Inet) of + true -> + Inet; + false -> + case lists:member(inet6, Inet) of + true -> + Inet; + false -> + [inet | Inet] + end + end. + diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index 06866392da..86804c4436 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -104,21 +104,11 @@ start_connection(client = Role, Socket, Options, Timeout) -> start_connection(server = Role, Socket, Options, Timeout) -> try - Sups = proplists:get_value(supervisors, Options), - ConnectionSup = proplists:get_value(connection_sup, Sups), - Opts = [{supervisors, Sups}, {user_pid, self()} | proplists:get_value(ssh_opts, Options, [])], - {ok, Pid} = ssh_connection_sup:start_child(ConnectionSup, [Role, Socket, Opts]), - {_, Callback, _} = proplists:get_value(transport, Options, {tcp, gen_tcp, tcp_closed}), - socket_control(Socket, Pid, Callback), - case proplists:get_value(parallel_login, Opts, false) of + case proplists:get_value(parallel_login, Options, false) of true -> - spawn(fun() -> - Ref = erlang:monitor(process, Pid), - handshake(Pid, Ref, Timeout) - end); + spawn(fun() -> start_server_connection(Role, Socket, Options, Timeout) end); false -> - Ref = erlang:monitor(process, Pid), - handshake(Pid, Ref, Timeout) + start_server_connection(Role, Socket, Options, Timeout) end catch exit:{noproc, _} -> @@ -127,6 +117,18 @@ start_connection(server = Role, Socket, Options, Timeout) -> {error, Error} end. + +start_server_connection(server = Role, Socket, Options, Timeout) -> + Sups = proplists:get_value(supervisors, Options), + ConnectionSup = proplists:get_value(connection_sup, Sups), + Opts = [{supervisors, Sups}, {user_pid, self()} | proplists:get_value(ssh_opts, Options, [])], + {ok, Pid} = ssh_connection_sup:start_child(ConnectionSup, [Role, Socket, Opts]), + {_, Callback, _} = proplists:get_value(transport, Options, {tcp, gen_tcp, tcp_closed}), + socket_control(Socket, Pid, Callback), + Ref = erlang:monitor(process, Pid), + handshake(Pid, Ref, Timeout). + + start_link(Role, Socket, Options) -> {ok, proc_lib:spawn_link(?MODULE, init, [[Role, Socket, Options]])}. diff --git a/lib/ssh/src/ssh_io.erl b/lib/ssh/src/ssh_io.erl index 832b144db9..35336bce8b 100644 --- a/lib/ssh/src/ssh_io.erl +++ b/lib/ssh/src/ssh_io.erl @@ -81,6 +81,8 @@ format(Fmt, Args) -> trim(Line) when is_list(Line) -> lists:reverse(trim1(lists:reverse(trim1(Line)))); +trim(Line) when is_binary(Line) -> + trim(unicode:characters_to_list(Line)); trim(Other) -> Other. trim1([$\s|Cs]) -> trim(Cs); diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl index 8d6c77c0ed..76b57cb995 100644 --- a/lib/ssh/src/ssh_message.erl +++ b/lib/ssh/src/ssh_message.erl @@ -255,7 +255,7 @@ encode(#ssh_msg_ignore{data = Data}) -> ssh_bits:encode([?SSH_MSG_IGNORE, Data], [byte, string]); encode(#ssh_msg_unimplemented{sequence = Seq}) -> - ssh_bits:encode([?SSH_MSG_IGNORE, Seq], [byte, uint32]); + ssh_bits:encode([?SSH_MSG_UNIMPLEMENTED, Seq], [byte, uint32]); encode(#ssh_msg_debug{always_display = Bool, message = Msg, @@ -391,13 +391,6 @@ decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_REQUEST), ?UINT32(Len0), Name:Len0/binary, data = Data}; %%% Unhandled message, also masked by same 1:st byte value as ?SSH_MSG_USERAUTH_INFO_REQUEST: -decode(<<?BYTE(?SSH_MSG_USERAUTH_PK_OK), ?UINT32(Len), Alg:Len/binary, KeyBlob/binary>>) -> - #ssh_msg_userauth_pk_ok{ - algorithm_name = Alg, - key_blob = KeyBlob - }; - -%%% Unhandled message, also masked by same 1:st byte value as ?SSH_MSG_USERAUTH_INFO_REQUEST: decode(<<?BYTE(?SSH_MSG_USERAUTH_PASSWD_CHANGEREQ), ?UINT32(Len0), Prompt:Len0/binary, ?UINT32(Len1), Lang:Len1/binary>>) -> #ssh_msg_userauth_passwd_changereq{ @@ -405,6 +398,13 @@ decode(<<?BYTE(?SSH_MSG_USERAUTH_PASSWD_CHANGEREQ), ?UINT32(Len0), Prompt:Len0/b languge = Lang }; +%%% Unhandled message, also masked by same 1:st byte value as ?SSH_MSG_USERAUTH_INFO_REQUEST: +decode(<<?BYTE(?SSH_MSG_USERAUTH_PK_OK), ?UINT32(Len), Alg:Len/binary, KeyBlob/binary>>) -> + #ssh_msg_userauth_pk_ok{ + algorithm_name = Alg, + key_blob = KeyBlob + }; + decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_RESPONSE), ?UINT32(Num), Data/binary>>) -> #ssh_msg_userauth_info_response{ num_responses = Num, @@ -461,10 +461,19 @@ decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code), language = Lang }; +%% Accept bad disconnects from ancient openssh clients that doesn't send language tag. Use english as a work-around. +decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code), + ?UINT32(Len0), Desc:Len0/binary>>) -> + #ssh_msg_disconnect{ + code = Code, + description = unicode:characters_to_list(Desc), + language = <<"en">> + }; + decode(<<?SSH_MSG_NEWKEYS>>) -> #ssh_msg_newkeys{}; -decode(<<?BYTE(?SSH_MSG_IGNORE), Data/binary>>) -> +decode(<<?BYTE(?SSH_MSG_IGNORE), ?UINT32(Len), Data:Len/binary>>) -> #ssh_msg_ignore{data = Data}; decode(<<?BYTE(?SSH_MSG_UNIMPLEMENTED), ?UINT32(Seq)>>) -> diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl index 37a307d783..9242731924 100644 --- a/lib/ssh/test/ssh_basic_SUITE.erl +++ b/lib/ssh/test/ssh_basic_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -49,23 +49,33 @@ all() -> server_userpassword_option, double_close, ssh_connect_timeout, + ssh_connect_arg4_timeout, {group, hardening_tests} ]. -groups() -> +groups() -> [{dsa_key, [], basic_tests()}, {rsa_key, [], basic_tests()}, {dsa_pass_key, [], [pass_phrase]}, {rsa_pass_key, [], [pass_phrase]}, {internal_error, [], [internal_error]}, - {hardening_tests, [], [max_sessions]} + {hardening_tests, [], [ssh_connect_nonegtimeout_connected_parallel, + ssh_connect_nonegtimeout_connected_sequential, + ssh_connect_negtimeout_parallel, + ssh_connect_negtimeout_sequential, + max_sessions_ssh_connect_parallel, + max_sessions_ssh_connect_sequential, + max_sessions_sftp_start_channel_parallel, + max_sessions_sftp_start_channel_sequential + ]} ]. basic_tests() -> [send, close, peername_sockname, exec, exec_compressed, shell, cli, known_hosts, - idle_time, rekey, openssh_zlib_basic_test]. + idle_time, rekey, openssh_zlib_basic_test, + misc_ssh_options, inet_option]. %%-------------------------------------------------------------------- @@ -174,16 +184,47 @@ misc_ssh_options(Config) when is_list(Config) -> SystemDir = filename:join(?config(priv_dir, Config), system), UserDir = ?config(priv_dir, Config), - CMiscOpt0 = [{connecect_timeout, 1000}, {ip_v6_disabled, false}, {user_dir, UserDir}], - CMiscOpt1 = [{connecect_timeout, infinity}, {ip_v6_disabled, true}, {user_dir, UserDir}], - SMiscOpt0 = [{ip_v6_disabled, false}, {user_dir, UserDir}, {system_dir, SystemDir}], - SMiscOpt1 = [{ip_v6_disabled, true}, {user_dir, UserDir}, {system_dir, SystemDir}], + CMiscOpt0 = [{connect_timeout, 1000}, {user_dir, UserDir}], + CMiscOpt1 = [{connect_timeout, infinity}, {user_dir, UserDir}], + SMiscOpt0 = [{user_dir, UserDir}, {system_dir, SystemDir}], + SMiscOpt1 = [{user_dir, UserDir}, {system_dir, SystemDir}], + + basic_test([{client_opts, CMiscOpt0}, {server_opts, SMiscOpt0}]), + basic_test([{client_opts, CMiscOpt1}, {server_opts, SMiscOpt1}]). + +%%-------------------------------------------------------------------- +inet_option() -> + [{doc, "Test configuring IPv4"}]. +inet_option(Config) when is_list(Config) -> + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), + ClientOpts = [{silently_accept_hosts, true}, + {user_dir, UserDir}, + {user_interaction, false}], + ServerOpts = [{system_dir, SystemDir}, + {user_dir, UserDir}, + {failfun, fun ssh_test_lib:failfun/2}], - basic_test([{client_opts, CMiscOpt0 ++ ClientOpts}, {server_opts, SMiscOpt0 ++ ServerOpts}]), - basic_test([{client_opts, CMiscOpt1 ++ ClientOpts}, {server_opts, SMiscOpt1 ++ ServerOpts}]). + basic_test([{client_opts, [{inet, inet} | ClientOpts]}, + {server_opts, [{inet, inet} | ServerOpts]}]). + +%%-------------------------------------------------------------------- +inet6_option() -> + [{doc, "Test configuring IPv6"}]. +inet6_option(Config) when is_list(Config) -> + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + + ClientOpts = [{silently_accept_hosts, true}, + {user_dir, UserDir}, + {user_interaction, false}], + ServerOpts = [{system_dir, SystemDir}, + {user_dir, UserDir}, + {failfun, fun ssh_test_lib:failfun/2}], + + basic_test([{client_opts, [{inet, inet6} | ClientOpts]}, + {server_opts, [{inet, inet6} | ServerOpts]}]). %%-------------------------------------------------------------------- exec() -> @@ -710,6 +751,98 @@ ms_passed(N1={_,_,M1}, N2={_,_,M2}) -> 1000 * (Min*60 + Sec + (M2-M1)/1000000). %%-------------------------------------------------------------------- +ssh_connect_negtimeout_parallel(Config) -> ssh_connect_negtimeout(Config,true). +ssh_connect_negtimeout_sequential(Config) -> ssh_connect_negtimeout(Config,false). + +ssh_connect_negtimeout(Config, Parallel) -> + process_flag(trap_exit, true), + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + NegTimeOut = 2000, % ms + ct:log("Parallel: ~p",[Parallel]), + + {_Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir}, + {parallel_login, Parallel}, + {negotiation_timeout, NegTimeOut}, + {failfun, fun ssh_test_lib:failfun/2}]), + + {ok,Socket} = gen_tcp:connect(Host, Port, []), + ct:pal("And now sleeping 1.2*NegTimeOut (~p ms)...", [round(1.2 * NegTimeOut)]), + receive after round(1.2 * NegTimeOut) -> ok end, + + case inet:sockname(Socket) of + {ok,_} -> ct:fail("Socket not closed"); + {error,_} -> ok + end. + +%%-------------------------------------------------------------------- +ssh_connect_nonegtimeout_connected_parallel() -> + [{doc, "Test that ssh connection does not timeout if the connection is established (parallel)"}]. +ssh_connect_nonegtimeout_connected_parallel(Config) -> + ssh_connect_nonegtimeout_connected(Config, true). + +ssh_connect_nonegtimeout_connected_sequential() -> + [{doc, "Test that ssh connection does not timeout if the connection is established (non-parallel)"}]. +ssh_connect_nonegtimeout_connected_sequential(Config) -> + ssh_connect_nonegtimeout_connected(Config, false). + + +ssh_connect_nonegtimeout_connected(Config, Parallel) -> + process_flag(trap_exit, true), + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + NegTimeOut = 20000, % ms + ct:log("Parallel: ~p",[Parallel]), + + {_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir}, + {parallel_login, Parallel}, + {negotiation_timeout, NegTimeOut}, + {failfun, fun ssh_test_lib:failfun/2}]), + ct:sleep(500), + + IO = ssh_test_lib:start_io_server(), + Shell = ssh_test_lib:start_shell(Port, IO, UserDir), + receive + {'EXIT', _, _} -> + ct:fail(no_ssh_connection); + ErlShellStart -> + ct:pal("---Erlang shell start: ~p~n", [ErlShellStart]), + one_shell_op(IO, NegTimeOut), + one_shell_op(IO, NegTimeOut), + ct:pal("And now sleeping 1.2*NegTimeOut (~p ms)...", [round(1.2 * NegTimeOut)]), + receive after round(1.2 * NegTimeOut) -> ok end, + one_shell_op(IO, NegTimeOut) + end, + exit(Shell, kill). + + +one_shell_op(IO, TimeOut) -> + ct:pal("One shell op: Waiting for prompter"), + receive + ErlPrompt0 -> ct:log("Erlang prompt: ~p~n", [ErlPrompt0]) + after TimeOut -> ct:fail("Timeout waiting for promter") + end, + + IO ! {input, self(), "2*3*7.\r\n"}, + receive + Echo0 -> ct:log("Echo: ~p ~n", [Echo0]) + after TimeOut -> ct:fail("Timeout waiting for echo") + end, + + receive + ?NEWLINE -> ct:log("NEWLINE received", []) + after TimeOut -> + receive Any1 -> ct:log("Bad NEWLINE: ~p",[Any1]) + after 0 -> ct:fail("Timeout waiting for NEWLINE") + end + end, + + receive + Result0 -> ct:log("Result: ~p~n", [Result0]) + after TimeOut -> ct:fail("Timeout waiting for result") + end. + +%%-------------------------------------------------------------------- openssh_zlib_basic_test() -> [{doc, "Test basic connection with openssh_zlib"}]. @@ -730,40 +863,87 @@ openssh_zlib_basic_test(Config) -> %%-------------------------------------------------------------------- -max_sessions(Config) -> +max_sessions_ssh_connect_parallel(Config) -> + max_sessions(Config, true, connect_fun(ssh__connect,Config)). +max_sessions_ssh_connect_sequential(Config) -> + max_sessions(Config, false, connect_fun(ssh__connect,Config)). + +max_sessions_sftp_start_channel_parallel(Config) -> + max_sessions(Config, true, connect_fun(ssh_sftp__start_channel, Config)). +max_sessions_sftp_start_channel_sequential(Config) -> + max_sessions(Config, false, connect_fun(ssh_sftp__start_channel, Config)). + + +%%%---- helpers: +connect_fun(ssh__connect, Config) -> + fun(Host,Port) -> + ssh_test_lib:connect(Host, Port, + [{silently_accept_hosts, true}, + {user_dir, ?config(priv_dir,Config)}, + {user_interaction, false}, + {user, "carni"}, + {password, "meat"} + ]) + %% ssh_test_lib returns R when ssh:connect returns {ok,R} + end; +connect_fun(ssh_sftp__start_channel, _Config) -> + fun(Host,Port) -> + {ok,_Pid,ConnRef} = + ssh_sftp:start_channel(Host, Port, + [{silently_accept_hosts, true}, + {user, "carni"}, + {password, "meat"} + ]), + ConnRef + end. + + +max_sessions(Config, ParallelLogin, Connect) when is_function(Connect,2) -> SystemDir = filename:join(?config(priv_dir, Config), system), UserDir = ?config(priv_dir, Config), - MaxSessions = 2, - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + MaxSessions = 5, + {Pid, Host, Port} = ssh_test_lib:daemon([ + {system_dir, SystemDir}, {user_dir, UserDir}, {user_passwords, [{"carni", "meat"}]}, - {parallel_login, true}, + {parallel_login, ParallelLogin}, {max_sessions, MaxSessions} ]), - Connect = fun() -> - R=ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user_dir, UserDir}, - {user_interaction, false}, - {user, "carni"}, - {password, "meat"} - ]), - ct:log("Connection ~p up",[R]) - end, - - try [Connect() || _ <- lists:seq(1,MaxSessions)] + try [Connect(Host,Port) || _ <- lists:seq(1,MaxSessions)] of - _ -> - ct:pal("Expect Info Report:",[]), - try Connect() + Connections -> + %% Step 1 ok: could set up max_sessions connections + ct:log("Connections up: ~p",[Connections]), + [_|_] = Connections, + + %% Now try one more than alowed: + ct:pal("Info Report might come here...",[]), + try Connect(Host,Port) of - _ConnectionRef -> + _ConnectionRef1 -> ssh:stop_daemon(Pid), {fail,"Too many connections accepted"} catch error:{badmatch,{error,"Connection closed"}} -> - ssh:stop_daemon(Pid), - ok + %% Step 2 ok: could not set up max_sessions+1 connections + %% This is expected + %% Now stop one connection and try to open one more + ok = ssh:close(hd(Connections)), + try Connect(Host,Port) + of + _ConnectionRef1 -> + %% Step 3 ok: could set up one more connection after killing one + %% Thats good. + ssh:stop_daemon(Pid), + ok + catch + error:{badmatch,{error,"Connection closed"}} -> + %% Bad indeed. Could not set up one more connection even after killing + %% one existing. Very bad. + ssh:stop_daemon(Pid), + {fail,"Does not decrease # active sessions"} + end end catch error:{badmatch,{error,"Connection closed"}} -> diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk index c8cac3e852..9bef10a366 100644 --- a/lib/ssh/vsn.mk +++ b/lib/ssh/vsn.mk @@ -1,5 +1,5 @@ #-*-makefile-*- ; force emacs to enter makefile-mode -SSH_VSN = 3.1 +SSH_VSN = 3.0.4 APP_VSN = "ssh-$(SSH_VSN)" |