diff options
Diffstat (limited to 'lib/ssh/test/ssh_test_lib.erl')
-rw-r--r-- | lib/ssh/test/ssh_test_lib.erl | 220 |
1 files changed, 182 insertions, 38 deletions
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl index ed76f4f795..6fd401d182 100644 --- a/lib/ssh/test/ssh_test_lib.erl +++ b/lib/ssh/test/ssh_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2015. All Rights Reserved. +%% Copyright Ericsson AB 2004-2016. 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. @@ -32,15 +32,8 @@ -define(TIMEOUT, 50000). -connect(Options) -> - connect(hostname(), inet_port(), Options). - connect(Port, Options) when is_integer(Port) -> - connect(hostname(), Port, Options); -connect(any, Options) -> - connect(hostname(), inet_port(), Options); -connect(Host, Options) -> - connect(Host, inet_port(), Options). + connect(hostname(), Port, Options). connect(any, Port, Options) -> connect(hostname(), Port, Options); @@ -49,26 +42,36 @@ connect(Host, Port, Options) -> ConnectionRef. daemon(Options) -> - daemon(any, inet_port(), Options). + daemon(any, 0, Options). daemon(Port, Options) when is_integer(Port) -> daemon(any, Port, Options); daemon(Host, Options) -> - daemon(Host, inet_port(), Options). + daemon(Host, 0, Options). + daemon(Host, Port, Options) -> + ct:log("~p:~p Calling ssh:daemon(~p, ~p, ~p)",[?MODULE,?LINE,Host,Port,Options]), case ssh:daemon(Host, Port, Options) of {ok, Pid} when Host == any -> - {Pid, hostname(), Port}; + ct:log("ssh:daemon ok (1)",[]), + {Pid, hostname(), daemon_port(Port,Pid)}; {ok, Pid} -> - {Pid, Host, Port}; + ct:log("ssh:daemon ok (2)",[]), + {Pid, Host, daemon_port(Port,Pid)}; Error -> + ct:log("ssh:daemon error ~p",[Error]), Error end. +daemon_port(0, Pid) -> {ok,Dinf} = ssh:daemon_info(Pid), + proplists:get_value(port, Dinf); +daemon_port(Port, _) -> Port. + + std_daemon(Config, ExtraOpts) -> - PrivDir = ?config(priv_dir, Config), + PrivDir = proplists:get_value(priv_dir, Config), UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth file:make_dir(UserDir), std_daemon1(Config, @@ -77,13 +80,13 @@ std_daemon(Config, ExtraOpts) -> {user_passwords, [{"usr1","pwd1"}]}]). std_daemon1(Config, ExtraOpts) -> - SystemDir = ?config(data_dir, Config), + SystemDir = proplists:get_value(data_dir, Config), {_Server, _Host, _Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, {failfun, fun ssh_test_lib:failfun/2} | ExtraOpts]). std_connect(Config, Host, Port, ExtraOpts) -> - UserDir = ?config(priv_dir, Config), + UserDir = proplists:get_value(priv_dir, Config), _ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, {user_dir, UserDir}, @@ -96,11 +99,11 @@ std_simple_sftp(Host, Port, Config) -> std_simple_sftp(Host, Port, Config, []). std_simple_sftp(Host, Port, Config, Opts) -> - UserDir = ?config(priv_dir, Config), + UserDir = proplists:get_value(priv_dir, Config), DataFile = filename:join(UserDir, "test.data"), ConnectionRef = ssh_test_lib:std_connect(Config, Host, Port, Opts), {ok, ChannelRef} = ssh_sftp:start_channel(ConnectionRef), - Data = crypto:rand_bytes(proplists:get_value(std_simple_sftp_size,Config,10)), + Data = crypto:strong_rand_bytes(proplists:get_value(std_simple_sftp_size,Config,10)), ok = ssh_sftp:write_file(ChannelRef, DataFile, Data), {ok,ReadData} = file:read_file(DataFile), ok = ssh:close(ConnectionRef), @@ -120,7 +123,8 @@ std_simple_exec(Host, Port, Config, Opts) -> Other -> ct:fail(Other) end, - ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId). + ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId), + ssh:close(ConnectionRef). start_shell(Port, IOServer, UserDir) -> @@ -154,14 +158,12 @@ loop_io_server(TestCase, Buff0) -> {input, TestCase, Line} -> loop_io_server(TestCase, Buff0 ++ [Line]); {io_request, From, ReplyAs, Request} -> -%%ct:log("~p",[{io_request, From, ReplyAs, Request}]), {ok, Reply, Buff} = io_request(Request, TestCase, From, ReplyAs, Buff0), -%%ct:log("io_request(~p)-->~p",[Request,{ok, Reply, Buff}]), io_reply(From, ReplyAs, Reply), loop_io_server(TestCase, Buff); - {'EXIT',_, _} -> - erlang:display('ssh_test_lib:loop_io_server/2 EXIT'), + {'EXIT',_, _} = _Exit -> +%% ct:log("ssh_test_lib:loop_io_server/2 got ~p",[_Exit]), ok after 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) @@ -202,6 +204,45 @@ reply(TestCase, Result) -> %%ct:log("reply ~p sending ~p ! ~p",[self(), TestCase, Result]), TestCase ! Result. + + +rcv_expected(Expect, SshPort, Timeout) -> + receive + {SshPort, Recvd} when is_function(Expect) -> + case Expect(Recvd) of + true -> + ct:log("Got expected ~p from ~p",[Recvd,SshPort]), + catch port_close(SshPort), + rcv_lingering(50); + false -> + ct:log("Got UNEXPECTED ~p~n",[Recvd]), + rcv_expected(Expect, SshPort, Timeout) + end; + {SshPort, Expect} -> + ct:log("Got expected ~p from ~p",[Expect,SshPort]), + catch port_close(SshPort), + rcv_lingering(50); + Other -> + ct:log("Got UNEXPECTED ~p~nExpect ~p",[Other, {SshPort,Expect}]), + rcv_expected(Expect, SshPort, Timeout) + + after Timeout -> + catch port_close(SshPort), + ct:fail("Did not receive answer") + end. + +rcv_lingering(Timeout) -> + receive + Msg -> + ct:log("Got LINGERING ~p",[Msg]), + rcv_lingering(Timeout) + + after Timeout -> + ct:log("No more lingering messages",[]), + ok + end. + + receive_exec_result(Msg) -> ct:log("Expect data! ~p", [Msg]), receive @@ -355,7 +396,7 @@ setup_rsa_pass_pharse(DataDir, UserDir, Phrase) -> setup_pass_pharse(KeyBin, OutFile, Phrase) -> [{KeyType, _,_} = Entry0] = public_key:pem_decode(KeyBin), Key = public_key:pem_entry_decode(Entry0), - Salt = crypto:rand_bytes(8), + Salt = crypto:strong_rand_bytes(8), Entry = public_key:pem_entry_encode(KeyType, Key, {{"DES-CBC", Salt}, Phrase}), Pem = public_key:pem_encode([Entry]), @@ -471,8 +512,9 @@ openssh_supports(ClientOrServer, Tag, Alg) when ClientOrServer == sshc ; %% Check if we have a "newer" ssh client that supports these test cases ssh_client_supports_Q() -> - ErlPort = open_port({spawn, "ssh -Q cipher"}, [exit_status, stderr_to_stdout]), - 0 == check_ssh_client_support2(ErlPort). + 0 == check_ssh_client_support2( + ?MODULE:open_port({spawn, "ssh -Q cipher"}) + ). check_ssh_client_support2(P) -> receive @@ -541,7 +583,6 @@ default_algorithms(sshc, DaemonOptions) -> ct:fail("No server respons 2") end. - run_fake_ssh({ok,InitialState}) -> KexInitPattern = #ssh_msg_kexinit{ @@ -583,6 +624,40 @@ run_fake_ssh({ok,InitialState}) -> {server2client, to_atoms(CompS2C)}]}]. +%%%---------------------------------------------------------------- +extract_algos(Spec) -> + [{Tag,get_atoms(List)} || {Tag,List} <- Spec]. + +get_atoms(L) -> + lists:usort( + [ A || X <- L, + A <- case X of + {_,L1} when is_list(L1) -> L1; + Y when is_atom(Y) -> [Y] + end]). + + +intersection(AlgoSpec1, AlgoSpec2) -> intersect(sort_spec(AlgoSpec1), sort_spec(AlgoSpec2)). + +intersect([{Tag,S1}|Ss1], [{Tag,S2}|Ss2]) -> + [{Tag,intersect(S1,S2)} | intersect(Ss1,Ss2)]; +intersect(L1=[A1|_], L2=[A2|_]) when is_atom(A1),is_atom(A2) -> + Diff = L1 -- L2, + L1 -- Diff; +intersect(_, _) -> + []. + +intersect_bi_dir([{Tag,[{client2server,L1},{server2client,L2}]}|T]) -> + [{Tag,intersect(L1,L2)} | intersect_bi_dir(T)]; +intersect_bi_dir([H={_,[A|_]}|T]) when is_atom(A) -> + [H | intersect_bi_dir(T)]; +intersect_bi_dir([]) -> + []. + + +sort_spec(L = [{_,_}|_] ) -> [{Tag,sort_spec(Es)} || {Tag,Es} <- L]; +sort_spec(L) -> lists:usort(L). + %%-------------------------------------------------------------------- sshc(Tag) -> to_atoms( @@ -590,17 +665,48 @@ sshc(Tag) -> ). ssh_type() -> - case os:find_executable("ssh") of - false -> not_found; - _ -> - case os:cmd("ssh -V") of - "OpenSSH" ++ _ -> - openSSH; - Str -> - ct:log("ssh client ~p is unknown",[Str]), - unknown - end - end. + Parent = self(), + Pid = spawn(fun() -> + Parent ! {ssh_type,self(),ssh_type1()} + end), + MonitorRef = monitor(process, Pid), + receive + {ssh_type, Pid, Result} -> + demonitor(MonitorRef), + Result; + {'DOWN', MonitorRef, process, Pid, _Info} -> + ct:log("~p:~p Process DOWN",[?MODULE,?LINE]), + not_found + after + 10000 -> + ct:log("~p:~p Timeout",[?MODULE,?LINE]), + demonitor(MonitorRef), + not_found + end. + + +ssh_type1() -> + try + case os:find_executable("ssh") of + false -> + ct:log("~p:~p Executable \"ssh\" not found",[?MODULE,?LINE]), + not_found; + _ -> + case os:cmd("ssh -V") of + "OpenSSH" ++ _ -> + openSSH; + Str -> + ct:log("ssh client ~p is unknown",[Str]), + unknown + end + end + catch + Class:Exception -> + ct:log("~p:~p Exception ~p:~p",[?MODULE,?LINE,Class,Exception]), + not_found + end. + + algo_intersection([], _) -> []; algo_intersection(_, []) -> []; @@ -658,3 +764,41 @@ has_inet6_address() -> catch throw:6 -> true end. + +%%%---------------------------------------------------------------- +open_port(Arg1) -> + ?MODULE:open_port(Arg1, []). + +open_port(Arg1, ExtraOpts) -> + erlang:open_port(Arg1, + [binary, + stderr_to_stdout, + exit_status, + use_stdio, + overlapped_io, hide %only affects windows + | ExtraOpts]). + +%%%---------------------------------------------------------------- +%%% Sleeping + +%%% Milli sec +sleep_millisec(Nms) -> receive after Nms -> ok end. + +%%% Micro sec +sleep_microsec(Nus) -> + busy_wait(Nus, erlang:system_time(microsecond)). + +busy_wait(Nus, T0) -> + T = erlang:system_time(microsecond) - T0, + Tleft = Nus - T, + if + Tleft > 2000 -> + sleep_millisec((Tleft-1500) div 1000), % μs -> ms + busy_wait(Nus,T0); + Tleft > 1 -> + busy_wait(Nus, T0); + true -> + T + end. + +%%%---------------------------------------------------------------- |