diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/eldap/doc/src/eldap.xml | 4 | ||||
-rw-r--r-- | lib/eldap/src/eldap.erl | 65 | ||||
-rw-r--r-- | lib/eldap/test/Makefile | 1 | ||||
-rw-r--r-- | lib/eldap/test/eldap_connections_SUITE.erl | 126 | ||||
-rw-r--r-- | lib/eldap/vsn.mk | 3 | ||||
-rw-r--r-- | lib/erl_interface/ebin/.gitignore | 0 | ||||
-rw-r--r-- | lib/erl_interface/src/Makefile.in | 26 | ||||
-rw-r--r-- | lib/erl_interface/src/erl_interface.app.src | 32 | ||||
-rw-r--r-- | lib/jinterface/ebin/.gitignore | 0 | ||||
-rw-r--r-- | lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile | 16 | ||||
-rw-r--r-- | lib/jinterface/java_src/com/ericsson/otp/erlang/jinterface.app.src | 32 | ||||
-rw-r--r-- | lib/ose/doc/src/notes.xml | 44 | ||||
-rw-r--r-- | lib/ssh/src/ssh.erl | 18 | ||||
-rw-r--r-- | lib/ssh/src/ssh_acceptor_sup.erl | 13 | ||||
-rw-r--r-- | lib/ssh/src/ssh_connect.hrl | 3 | ||||
-rw-r--r-- | lib/ssh/src/ssh_connection_handler.erl | 86 | ||||
-rw-r--r-- | lib/ssh/src/ssh_system_sup.erl | 8 | ||||
-rw-r--r-- | lib/ssh/src/ssh_transport.erl | 27 | ||||
-rw-r--r-- | lib/ssh/test/ssh_basic_SUITE.erl | 13 | ||||
-rw-r--r-- | lib/ssh/test/ssh_connection_SUITE.erl | 238 | ||||
-rw-r--r-- | lib/ssh/test/ssh_test_lib.erl | 3 |
21 files changed, 648 insertions, 110 deletions
diff --git a/lib/eldap/doc/src/eldap.xml b/lib/eldap/doc/src/eldap.xml index 8009a8d6a3..dbd478fb17 100644 --- a/lib/eldap/doc/src/eldap.xml +++ b/lib/eldap/doc/src/eldap.xml @@ -75,7 +75,9 @@ filter() See present/1, substrings/2, <p>Setup a connection to an LDAP server, the <c>HOST</c>'s are tried in order.</p> <p>The log function takes three arguments, <c>fun(Level, FormatString, [FormatArg]) end</c>.</p> <p>Timeout set the maximum time in milliseconds that each server request may take.</p> - <p>Currently, the only TCP socket option accepted is <c>inet6</c>. Default is <c>inet</c>.</p> + <p>All TCP socket options are accepted except + <c>active</c>, <c>binary</c>, <c>deliver</c>, <c>list</c>, <c>mode</c> and <c>packet</c> + </p> </desc> </func> <func> diff --git a/lib/eldap/src/eldap.erl b/lib/eldap/src/eldap.erl index 1cd328cde3..416334e365 100644 --- a/lib/eldap/src/eldap.erl +++ b/lib/eldap/src/eldap.erl @@ -12,6 +12,7 @@ -vc('$Id$ '). -export([open/1,open/2,simple_bind/3,controlling_process/2, start_tls/2, start_tls/3, + getopts/2, baseObject/0,singleLevel/0,wholeSubtree/0,close/1, equalityMatch/2,greaterOrEqual/2,lessOrEqual/2, approxMatch/2,search/2,substrings/2,present/1, @@ -92,6 +93,15 @@ start_tls(Handle, TlsOptions, Timeout) -> recv(Handle). %%% -------------------------------------------------------------------- +%%% Ask for option values on the socket. +%%% Warning: This is an undocumented function for testing purposes only. +%%% Use at own risk... +%%% -------------------------------------------------------------------- +getopts(Handle, OptNames) when is_pid(Handle), is_list(OptNames) -> + send(Handle, {getopts, OptNames}), + recv(Handle). + +%%% -------------------------------------------------------------------- %%% Shutdown connection (and process) asynchronous. %%% -------------------------------------------------------------------- @@ -374,24 +384,35 @@ parse_args([{sslopts, Opts}|T], Cpid, Data) when is_list(Opts) -> parse_args([{sslopts, _}|T], Cpid, Data) -> parse_args(T, Cpid, Data); parse_args([{tcpopts, Opts}|T], Cpid, Data) when is_list(Opts) -> - parse_args(T, Cpid, Data#eldap{tcp_opts = inet6_opt(Opts) ++ Data#eldap.tcp_opts}); + parse_args(T, Cpid, Data#eldap{tcp_opts = tcp_opts(Opts,Cpid,Data#eldap.tcp_opts)}); parse_args([{log, F}|T], Cpid, Data) when is_function(F) -> parse_args(T, Cpid, Data#eldap{log = F}); parse_args([{log, _}|T], Cpid, Data) -> parse_args(T, Cpid, Data); parse_args([H|_], Cpid, _) -> send(Cpid, {error,{wrong_option,H}}), + unlink(Cpid), exit(wrong_option); parse_args([], _, Data) -> Data. -inet6_opt(Opts) -> - case proplists:get_value(inet6, Opts) of +tcp_opts([Opt|Opts], Cpid, Acc) -> + Key = if is_atom(Opt) -> Opt; + is_tuple(Opt) -> element(1,Opt) + end, + case lists:member(Key,[active,binary,deliver,list,mode,packet]) of + false -> + tcp_opts(Opts, Cpid, [Opt|Acc]); true -> - [inet6]; - _ -> - [] - end. + tcp_opts_error(Opt, Cpid) + end; +tcp_opts([], _Cpid, Acc) -> Acc. + +tcp_opts_error(Opt, Cpid) -> + send(Cpid, {error, {{forbidden_tcp_option,Opt}, + "This option affects the eldap functionality and can't be set by user"}}), + unlink(Cpid), + exit(forbidden_tcp_option). %%% Try to connect to the hosts in the listed order, %%% and stop with the first one to which a successful @@ -466,6 +487,36 @@ loop(Cpid, Data) -> unlink(Cpid), exit(closed); + {From, {getopts, OptNames}} -> + Result = + try + [case OptName of + port -> {port, Data#eldap.port}; + log -> {log, Data#eldap.log}; + timeout -> {timeout, Data#eldap.timeout}; + ssl -> {ssl, Data#eldap.ldaps}; + {sslopts, SslOptNames} when Data#eldap.using_tls==true -> + case ssl:getopts(Data#eldap.fd, SslOptNames) of + {ok,SslOptVals} -> {sslopts, SslOptVals}; + {error,Reason} -> throw({error,Reason}) + end; + {sslopts, _} -> + throw({error,no_tls}); + {tcpopts, TcpOptNames} -> + case inet:getopts(Data#eldap.fd, TcpOptNames) of + {ok,TcpOptVals} -> {tcpopts, TcpOptVals}; + {error,Posix} -> throw({error,Posix}) + end + end || OptName <- OptNames] + of + OptsList -> {ok,OptsList} + catch + throw:Error -> Error; + Class:Error -> {error,{Class,Error}} + end, + send(From, Result), + ?MODULE:loop(Cpid, Data); + {Cpid, 'EXIT', Reason} -> ?PRINT("Got EXIT from Cpid, reason=~p~n",[Reason]), exit(Reason); diff --git a/lib/eldap/test/Makefile b/lib/eldap/test/Makefile index 3c5810eece..24e71cebaa 100644 --- a/lib/eldap/test/Makefile +++ b/lib/eldap/test/Makefile @@ -28,6 +28,7 @@ INCLUDES= -I. -I ../include # ---------------------------------------------------- MODULES= \ + eldap_connections_SUITE \ eldap_basic_SUITE ERL_FILES= $(MODULES:%=%.erl) diff --git a/lib/eldap/test/eldap_connections_SUITE.erl b/lib/eldap/test/eldap_connections_SUITE.erl new file mode 100644 index 0000000000..4c8aa9c2cf --- /dev/null +++ b/lib/eldap/test/eldap_connections_SUITE.erl @@ -0,0 +1,126 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012-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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(eldap_connections_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +%-include_lib("eldap/include/eldap.hrl"). + + +all() -> + [ + tcp_connection, + tcp_inet6_connection, + tcp_connection_option, + tcp_inet6_connection_option + ]. + + +init_per_suite(Config) -> Config. + +end_per_suite(_Config) -> ok. + + +init_per_testcase(_TestCase, Config) -> + {ok,Sl} = gen_tcp:listen(0,[]), + {ok,Sl6} = gen_tcp:listen(0,[inet6]), + [{listen_socket,Sl}, {listen_socket6,Sl6} | Config]. + +end_per_testcase(_TestCase, Config) -> + catch gen_tcp:close( proplists:get_value(listen_socket, Config) ), + catch gen_tcp:close( proplists:get_value(listen_socket6, Config) ), + ok. + +%%%================================================================ +%%% +%%% Test cases +%%% +%%%---------------------------------------------------------------- +tcp_connection(Config) -> + do_tcp_connection(Config, listen_socket, "localhost", []). + +tcp_inet6_connection(Config) -> + do_tcp_connection(Config, listen_socket6, "::", [{tcpopts,[inet6]}]). + + +do_tcp_connection(Config, SockKey, Host, Opts) -> + Sl = proplists:get_value(SockKey, Config), + {ok,{_,Port}} = inet:sockname(Sl), + case eldap:open([Host], [{port,Port}|Opts]) of + {ok,_H} -> + case gen_tcp:accept(Sl,1000) of + {ok,_S} -> ok; + {error,timeout} -> ct:fail("server side accept timeout",[]) + end; + Other -> ct:fail("eldap:open failed: ~p",[Other]) + end. + +%%%---------------------------------------------------------------- +tcp_connection_option(Config) -> + do_tcp_connection_option(Config, listen_socket, "localhost", []). + +tcp_inet6_connection_option(Config) -> + do_tcp_connection_option(Config, listen_socket6, "::", [{tcpopts,[inet6]}]). + + +do_tcp_connection_option(Config, SockKey, Host, Opts) -> + Sl = proplists:get_value(SockKey, Config), + {ok,{_,Port}} = inet:sockname(Sl), + + %% Make an option value to test. The option must be implemented on all + %% platforms that we test on. Must check what the default value is + %% so we don't happen to choose that particular value. + {ok,[{linger,DefaultLinger}]} = inet:getopts(Sl, [linger]), + TestLinger = case DefaultLinger of + {false,_} -> {true,5}; + {true,_} -> {false,0} + end, + + case catch eldap:open([Host], + [{port,Port},{tcpopts,[{linger,TestLinger}]}|Opts]) of + {ok,H} -> + case gen_tcp:accept(Sl,1000) of + {ok,_} -> + case eldap:getopts(H, [{tcpopts,[linger]}]) of + {ok,[{tcpopts,[{linger,ActualLinger}]}]} -> + case ActualLinger of + TestLinger -> + ok; + DefaultLinger -> + ct:fail("eldap:getopts: 'linger' didn't change," + " got ~p (=default) expected ~p", + [ActualLinger,TestLinger]); + _ -> + ct:fail("eldap:getopts: bad 'linger', got ~p expected ~p", + [ActualLinger,TestLinger]) + end; + Other -> + ct:fail("eldap:getopts: bad result ~p",[Other]) + end; + {error,timeout} -> + ct:fail("server side accept timeout",[]) + end; + + Other -> + ct:fail("eldap:open failed: ~p",[Other]) + end. + +%%%---------------------------------------------------------------- diff --git a/lib/eldap/vsn.mk b/lib/eldap/vsn.mk index efdc30b476..5e32f92fa8 100644 --- a/lib/eldap/vsn.mk +++ b/lib/eldap/vsn.mk @@ -1,2 +1 @@ -ELDAP_VSN = 1.0.3 - +ELDAP_VSN = 1.0.4
\ No newline at end of file diff --git a/lib/erl_interface/ebin/.gitignore b/lib/erl_interface/ebin/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/erl_interface/ebin/.gitignore diff --git a/lib/erl_interface/src/Makefile.in b/lib/erl_interface/src/Makefile.in index e36b39c1fb..7d914a02ca 100644 --- a/lib/erl_interface/src/Makefile.in +++ b/lib/erl_interface/src/Makefile.in @@ -40,6 +40,13 @@ include $(TARGET)/eidefs.mk include $(ERL_TOP)/make/output.mk +EBINDIR=../ebin + +APP_FILE= erl_interface.app + +APP_SRC= $(APP_FILE).src +APP_TARGET= $(EBINDIR)/$(APP_FILE) + USING_MINGW=@MIXED_CYGWIN_MINGW@ USING_MSYS_VC==@MIXED_MSYS_VC@ USING_CYGWIN_VC==@MIXED_MSYS_VC@ @@ -212,7 +219,8 @@ ifeq ($(USING_VC),yes) TARGETS = \ $(OBJ_TARGETS) \ - $(EXE_TARGETS) + $(EXE_TARGETS) \ + $(APP_TARGET) OBJ_TARGETS = \ $(MT_EILIB) \ @@ -241,7 +249,8 @@ else ifeq ($USING_MINGW,yes) TARGETS = \ $(OBJ_TARGETS) \ - $(EXE_TARGETS) + $(EXE_TARGETS) \ + $(APP_TARGET) OBJ_TARGETS = \ $(MD_EILIB) \ @@ -259,7 +268,8 @@ ifdef THR_DEFS TARGETS = \ $(OBJ_TARGETS) \ - $(EXE_TARGETS) + $(EXE_TARGETS) \ + $(APP_TARGET) OBJ_TARGETS = \ $(ST_EILIB) \ @@ -281,7 +291,8 @@ else TARGETS = \ $(OBJ_TARGETS) \ - $(EXE_TARGETS) + $(EXE_TARGETS) \ + $(APP_TARGET) OBJ_TARGETS = \ $(ST_EILIB) \ @@ -597,12 +608,15 @@ $(MDD_OBJDIR)/%.o: %.c # Create directories ########################################################################### -_create_dirs := $(shell mkdir -p $(BINDIR) $(OBJDIR) $(ST_OBJDIR) $(MT_OBJDIR) $(MD_OBJDIR) $(MDD_OBJDIR)) +_create_dirs := $(shell mkdir -p $(EBINDIR) $(BINDIR) $(OBJDIR) $(ST_OBJDIR) $(MT_OBJDIR) $(MD_OBJDIR) $(MDD_OBJDIR)) ########################################################################### # Special rules ########################################################################### +$(APP_TARGET): $(APP_SRC) ../vsn.mk + $(vsn_verbose)sed -e 's;%VSN%;$(ERL_INTERFACE_VSN);' $< > $@ + ifeq ($(TARGET),win32) # Windows archive creation @@ -857,6 +871,7 @@ release: opt $(INSTALL_DIR) "$(RELSYSDIR)/include" $(INSTALL_DIR) "$(RELSYSDIR)/lib" $(INSTALL_DIR) "$(RELSYSDIR)/bin" + $(INSTALL_DIR) "$(RELSYSDIR)/ebin" $(INSTALL_DIR) "$(RELSYSDIR)/src/auxdir" $(INSTALL_DIR) "$(RELSYSDIR)/src/connect" $(INSTALL_DIR) "$(RELSYSDIR)/src/decode" @@ -868,6 +883,7 @@ release: opt $(INSTALL_DIR) "$(RELSYSDIR)/src/registry" $(INSTALL_DIR) "$(RELEASE_PATH)/usr/include" $(INSTALL_DIR) "$(RELEASE_PATH)/usr/lib" + $(INSTALL_DATA) $(APP_TARGET) "$(RELSYSDIR)/ebin/$(APP_FILE)" $(INSTALL_DATA) $(HEADERS) "$(RELSYSDIR)/include" $(INSTALL_DATA) $(HEADERS) "$(RELEASE_PATH)/usr/include" $(INSTALL_DATA) $(OBJ_TARGETS) "$(RELSYSDIR)/lib" diff --git a/lib/erl_interface/src/erl_interface.app.src b/lib/erl_interface/src/erl_interface.app.src new file mode 100644 index 0000000000..11f884c36b --- /dev/null +++ b/lib/erl_interface/src/erl_interface.app.src @@ -0,0 +1,32 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% This is an -*- erlang -*- file. +%% + +{application, erl_interface, + [ + {description, "Erl Interface"}, + {vsn, "%VSN%"}, + {modules, []}, + {registered, []}, + {applications, []}, + {env, []}, + {runtime_dependencies, []} + ] +}. diff --git a/lib/jinterface/ebin/.gitignore b/lib/jinterface/ebin/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/jinterface/ebin/.gitignore diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile b/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile index f476d4594d..8ae1ca0cdc 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile @@ -32,6 +32,15 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk include $(ERL_TOP)/lib/jinterface/vsn.mk VSN=$(JINTERFACE_VSN) +# + +EBINDIR=$(ERL_TOP)/lib/jinterface/ebin + +APP_FILE= jinterface.app + +APP_SRC= $(APP_FILE).src +APP_TARGET= $(EBINDIR)/$(APP_FILE) + # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- @@ -45,7 +54,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/jinterface-$(VSN) # all java sourcefiles listed in common include file include $(ERL_TOP)/lib/jinterface/java_src/$(JAVA_CLASS_SUBDIR)/java_files -TARGET_FILES= $(JAVA_FILES:%=$(JAVA_DEST_ROOT)$(JAVA_CLASS_SUBDIR)%.class) +TARGET_FILES= $(JAVA_FILES:%=$(JAVA_DEST_ROOT)$(JAVA_CLASS_SUBDIR)%.class) $(APP_TARGET) JAVA_SRC= $(JAVA_FILES:%=%.java) JARFILE= OtpErlang.jar @@ -79,6 +88,9 @@ endif # Make Rules # ---------------------------------------------------- +$(APP_TARGET): $(APP_SRC) $(ERL_TOP)/lib/jinterface/vsn.mk + $(vsn_verbose)sed -e 's;%VSN%;$(JINTERFACE_VSN);' $< > $@ + debug opt: make_dirs $(JAVA_DEST_ROOT)$(JARFILE) make_dirs: @@ -106,6 +118,8 @@ release_spec: opt $(V_at)$(INSTALL_DATA) $(JAVA_SRC) "$(RELSYSDIR)/java_src/com/ericsson/otp/erlang" $(V_at)$(INSTALL_DIR) "$(RELSYSDIR)/priv" $(V_at)$(INSTALL_DATA) $(JAVA_DEST_ROOT)$(JARFILE) "$(RELSYSDIR)/priv" + $(V_at)$(INSTALL_DIR) "$(RELSYSDIR)/ebin" + $(V_at)$(INSTALL_DATA) $(APP_TARGET) "$(RELSYSDIR)/ebin/$(APP_FILE)" release_docs_spec: diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/jinterface.app.src b/lib/jinterface/java_src/com/ericsson/otp/erlang/jinterface.app.src new file mode 100644 index 0000000000..d25d9bc142 --- /dev/null +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/jinterface.app.src @@ -0,0 +1,32 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% This is an -*- erlang -*- file. +%% + +{application, jinterface, + [ + {description, "Jinterface"}, + {vsn, "%VSN%"}, + {modules, []}, + {registered, []}, + {applications, []}, + {env, []}, + {runtime_dependencies, []} + ] +}. diff --git a/lib/ose/doc/src/notes.xml b/lib/ose/doc/src/notes.xml index 760b92feed..42d41a7fa1 100644 --- a/lib/ose/doc/src/notes.xml +++ b/lib/ose/doc/src/notes.xml @@ -30,4 +30,48 @@ </header> <p>This document describes the changes made to the OSE application.</p> +<section><title>Ose 1.0.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix some spelling mistakes in documentation</p> + <p> + Own Id: OTP-12152</p> + </item> + </list> + </section> + +</section> + +<section><title>Ose 1.0</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Erlang/OTP has been ported to the realtime operating + system OSE. The port supports both smp and non-smp + emulator. For details around the port and how to started + see the User's Guide in the <seealso + marker="ose:ose_intro">ose</seealso> application. </p> + <p> + Note that not all parts of Erlang/OTP has been ported. </p> + <p> + Notable things that work are: non-smp and smp emulators, + OSE signal interaction, crypto, asn1, run_erl/to_erl, + tcp, epmd, distribution and most if not all non-os + specific functionality of Erlang.</p> + <p> + Notable things that does not work are: udp/sctp, os_mon, + erl_interface, binding of schedulers.</p> + <p> + Own Id: OTP-11334</p> + </item> + </list> + </section> + +</section> + </chapter> diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index 8a8d4bb89e..de047d3c83 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -234,22 +234,26 @@ do_start_daemon(Host, Port, Options, SocketOptions) -> {port, Port}, {role, server}, {socket_opts, SocketOptions}, {ssh_opts, Options}]) of - {ok, SysSup} -> - {ok, SysSup}; {error, {already_started, _}} -> {error, eaddrinuse}; - {error, R} -> - {error, R} + Result = {Code, _} when (Code == ok) or (Code == error) -> + Result catch exit:{noproc, _} -> {error, ssh_not_started} end; Sup -> - case ssh_system_sup:restart_acceptor(Host, Port) of + AccPid = ssh_system_sup:acceptor_supervisor(Sup), + case ssh_acceptor_sup:start_child(AccPid, [{address, Host}, + {port, Port}, {role, server}, + {socket_opts, SocketOptions}, + {ssh_opts, Options}]) of + {error, {already_started, _}} -> + {error, eaddrinuse}; {ok, _} -> {ok, Sup}; - _ -> - {error, eaddrinuse} + Other -> + Other end end. diff --git a/lib/ssh/src/ssh_acceptor_sup.erl b/lib/ssh/src/ssh_acceptor_sup.erl index 2be729d305..46fdef07d0 100644 --- a/lib/ssh/src/ssh_acceptor_sup.erl +++ b/lib/ssh/src/ssh_acceptor_sup.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 @@ -26,7 +26,7 @@ -module(ssh_acceptor_sup). -behaviour(supervisor). --export([start_link/1, start_child/2, stop_child/2]). +-export([start_link/1, start_child/2, stop_child/3]). %% Supervisor callback -export([init/1]). @@ -45,18 +45,17 @@ start_child(AccSup, ServerOpts) -> {error, already_present} -> Address = proplists:get_value(address, ServerOpts), Port = proplists:get_value(port, ServerOpts), - Name = id(Address, Port), - supervisor:delete_child(?MODULE, Name), + stop_child(AccSup, Address, Port), supervisor:start_child(AccSup, Spec); Reply -> Reply end. -stop_child(Address, Port) -> +stop_child(AccSup, Address, Port) -> Name = id(Address, Port), - case supervisor:terminate_child(?MODULE, Name) of + case supervisor:terminate_child(AccSup, Name) of ok -> - supervisor:delete_child(?MODULE, Name); + supervisor:delete_child(AccSup, Name); Error -> Error end. diff --git a/lib/ssh/src/ssh_connect.hrl b/lib/ssh/src/ssh_connect.hrl index 8421b07167..9307dbbad0 100644 --- a/lib/ssh/src/ssh_connect.hrl +++ b/lib/ssh/src/ssh_connect.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2013. All Rights Reserved. +%% Copyright Ericsson AB 2005-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 @@ -26,6 +26,7 @@ -define(DEFAULT_PACKET_SIZE, 32768). -define(DEFAULT_WINDOW_SIZE, 2*?DEFAULT_PACKET_SIZE). -define(DEFAULT_TIMEOUT, 5000). +-define(MAX_PROTO_VERSION, 255). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index 86804c4436..4fbc5d0ae2 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.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 @@ -48,7 +48,7 @@ userauth/2, connected/2]). -export([init/1, handle_event/3, - handle_sync_event/4, handle_info/3, terminate/3, code_change/4]). + handle_sync_event/4, handle_info/3, terminate/3, format_status/2, code_change/4]). -record(state, { role, @@ -71,7 +71,8 @@ connection_queue, address, port, - opts + opts, + recbuf }). -type state_name() :: hello | kexinit | key_exchange | new_keys | userauth | connection. @@ -103,12 +104,22 @@ start_connection(client = Role, Socket, Options, Timeout) -> end; start_connection(server = Role, Socket, Options, Timeout) -> + SSH_Opts = proplists:get_value(ssh_opts, Options, []), try - case proplists:get_value(parallel_login, Options, false) of + case proplists:get_value(parallel_login, SSH_Opts, false) of true -> - spawn(fun() -> start_server_connection(Role, Socket, Options, Timeout) end); + HandshakerPid = + spawn_link(fun() -> + receive + {do_handshake, Pid} -> + handshake(Pid, erlang:monitor(process,Pid), Timeout) + end + end), + ChildPid = start_the_connection_child(HandshakerPid, Role, Socket, Options), + HandshakerPid ! {do_handshake, ChildPid}; false -> - start_server_connection(Role, Socket, Options, Timeout) + ChildPid = start_the_connection_child(self(), Role, Socket, Options), + handshake(ChildPid, erlang:monitor(process,ChildPid), Timeout) end catch exit:{noproc, _} -> @@ -117,16 +128,14 @@ start_connection(server = Role, Socket, Options, Timeout) -> {error, Error} end. - -start_server_connection(server = Role, Socket, Options, Timeout) -> +start_the_connection_child(UserPid, Role, Socket, Options) -> 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, [])], + Opts = [{supervisors, Sups}, {user_pid, UserPid} | 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). + Pid. start_link(Role, Socket, Options) -> @@ -293,28 +302,39 @@ info(ConnectionHandler, ChannelProcess) -> hello(socket_control, #state{socket = Socket, ssh_params = Ssh} = State) -> VsnMsg = ssh_transport:hello_version_msg(string_version(Ssh)), send_msg(VsnMsg, State), - inet:setopts(Socket, [{packet, line}, {active, once}]), - {next_state, hello, State}; + {ok, [{recbuf, Size}]} = inet:getopts(Socket, [recbuf]), + inet:setopts(Socket, [{packet, line}, {active, once}, {recbuf, ?MAX_PROTO_VERSION}]), + {next_state, hello, State#state{recbuf = Size}}; -hello({info_line, _Line},#state{socket = Socket} = State) -> +hello({info_line, _Line},#state{role = client, socket = Socket} = State) -> + %% The server may send info lines before the version_exchange inet:setopts(Socket, [{active, once}]), {next_state, hello, State}; +hello({info_line, _Line},#state{role = server} = State) -> + DisconnectMsg = + #ssh_msg_disconnect{code = + ?SSH_DISCONNECT_PROTOCOL_ERROR, + description = "Did not receive expected protocol version exchange", + language = "en"}, + handle_disconnect(DisconnectMsg, State); + hello({version_exchange, Version}, #state{ssh_params = Ssh0, - socket = Socket} = State) -> + socket = Socket, + recbuf = Size} = State) -> {NumVsn, StrVsn} = ssh_transport:handle_hello_version(Version), case handle_version(NumVsn, StrVsn, Ssh0) of {ok, Ssh1} -> - inet:setopts(Socket, [{packet,0}, {mode,binary}, {active, once}]), + inet:setopts(Socket, [{packet,0}, {mode,binary}, {active, once}, {recbuf, Size}]), {KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(Ssh1), send_msg(SshPacket, State), {next_state, kexinit, next_packet(State#state{ssh_params = Ssh, key_exchange_init_msg = KeyInitMsg})}; not_supported -> - DisconnectMsg = + DisconnectMsg = #ssh_msg_disconnect{code = - ?SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED, + ?SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED, description = "Protocol version " ++ StrVsn ++ " not supported", language = "en"}, @@ -951,6 +971,36 @@ terminate_subsytem(#connection{system_supervisor = SysSup, terminate_subsytem(_) -> ok. +format_status(normal, [_, State]) -> + [{data, [{"StateData", State}]}]; +format_status(terminate, [_, State]) -> + SshParams0 = (State#state.ssh_params), + SshParams = SshParams0#ssh{c_keyinit = "***", + s_keyinit = "***", + send_mac_key = "***", + send_mac_size = "***", + recv_mac_key = "***", + recv_mac_size = "***", + encrypt_keys = "***", + encrypt_ctx = "***", + decrypt_keys = "***", + decrypt_ctx = "***", + compress_ctx = "***", + decompress_ctx = "***", + shared_secret = "***", + exchanged_hash = "***", + session_id = "***", + keyex_key = "***", + keyex_info = "***", + available_host_keys = "***"}, + [{data, [{"StateData", State#state{decoded_data_buffer = "***", + encoded_data_buffer = "***", + key_exchange_init_msg = "***", + opts = "***", + recbuf = "***", + ssh_params = SshParams + }}]}]. + %%-------------------------------------------------------------------- -spec code_change(OldVsn::term(), state_name(), Oldstate::term(), Extra::term()) -> {ok, state_name(), #state{}}. diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl index 848133f838..660fe8bb65 100644 --- a/lib/ssh/src/ssh_system_sup.erl +++ b/lib/ssh/src/ssh_system_sup.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 @@ -173,8 +173,8 @@ ssh_acceptor_sup([_ | Rest]) -> ssh_acceptor_sup(Rest). stop_acceptor(Sup) -> - [Name] = - [SupName || {SupName, _, _, [ssh_acceptor_sup]} <- + [{Name, AcceptorSup}] = + [{SupName, ASup} || {SupName, ASup, _, [ssh_acceptor_sup]} <- supervisor:which_children(Sup)], - supervisor:terminate_child(Sup, Name). + supervisor:terminate_child(AcceptorSup, Name). diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl index ea05c849b7..76fa776113 100644 --- a/lib/ssh/src/ssh_transport.erl +++ b/lib/ssh/src/ssh_transport.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2013. All Rights Reserved. +%% Copyright Ericsson AB 2004-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 @@ -82,16 +82,21 @@ format_version({Major,Minor}) -> integer_to_list(Minor) ++ "-Erlang". handle_hello_version(Version) -> - StrVersion = trim_tail(Version), - case string:tokens(Version, "-") of - [_, "2.0" | _] -> - {{2,0}, StrVersion}; - [_, "1.99" | _] -> - {{2,0}, StrVersion}; - [_, "1.3" | _] -> - {{1,3}, StrVersion}; - [_, "1.5" | _] -> - {{1,5}, StrVersion} + try + StrVersion = trim_tail(Version), + case string:tokens(Version, "-") of + [_, "2.0" | _] -> + {{2,0}, StrVersion}; + [_, "1.99" | _] -> + {{2,0}, StrVersion}; + [_, "1.3" | _] -> + {{1,3}, StrVersion}; + [_, "1.5" | _] -> + {{1,5}, StrVersion} + end + catch + error:_ -> + {undefined, "unknown version"} end. key_exchange_init_msg(Ssh0) -> diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl index 9242731924..415cb9fc9c 100644 --- a/lib/ssh/test/ssh_basic_SUITE.erl +++ b/lib/ssh/test/ssh_basic_SUITE.erl @@ -798,12 +798,14 @@ ssh_connect_nonegtimeout_connected(Config, Parallel) -> {parallel_login, Parallel}, {negotiation_timeout, NegTimeOut}, {failfun, fun ssh_test_lib:failfun/2}]), + ct:pal("~p Listen ~p:~p",[_Pid,_Host,Port]), ct:sleep(500), IO = ssh_test_lib:start_io_server(), Shell = ssh_test_lib:start_shell(Port, IO, UserDir), receive - {'EXIT', _, _} -> + Error = {'EXIT', _, _} -> + ct:pal("~p",[Error]), ct:fail(no_ssh_connection); ErlShellStart -> ct:pal("---Erlang shell start: ~p~n", [ErlShellStart]), @@ -898,7 +900,12 @@ connect_fun(ssh_sftp__start_channel, _Config) -> end. -max_sessions(Config, ParallelLogin, Connect) when is_function(Connect,2) -> +max_sessions(Config, ParallelLogin, Connect0) when is_function(Connect0,2) -> + Connect = fun(Host,Port) -> + R = Connect0(Host,Port), + ct:pal("Connect(~p,~p) -> ~p",[Host,Port,R]), + R + end, SystemDir = filename:join(?config(priv_dir, Config), system), UserDir = ?config(priv_dir, Config), MaxSessions = 5, @@ -909,7 +916,7 @@ max_sessions(Config, ParallelLogin, Connect) when is_function(Connect,2) -> {parallel_login, ParallelLogin}, {max_sessions, MaxSessions} ]), - + ct:pal("~p Listen ~p:~p for max ~p sessions",[Pid,Host,Port,MaxSessions]), try [Connect(Host,Port) || _ <- lists:seq(1,MaxSessions)] of Connections -> diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl index c115ccee5f..9569120cfc 100644 --- a/lib/ssh/test/ssh_connection_SUITE.erl +++ b/lib/ssh/test/ssh_connection_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 @@ -31,8 +31,8 @@ %% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- -suite() -> - [{ct_hooks,[ts_install_cth]}]. +%% suite() -> +%% [{ct_hooks,[ts_install_cth]}]. all() -> [ @@ -40,7 +40,12 @@ all() -> interrupted_send, start_shell, start_shell_exec, - start_shell_exec_fun + start_shell_exec_fun, + gracefull_invalid_version, + gracefull_invalid_start, + gracefull_invalid_long_start, + gracefull_invalid_long_start_no_nl, + stop_listener ]. groups() -> [{openssh_payload, [], [simple_exec, @@ -67,7 +72,7 @@ init_per_group(openssh_payload, _Config) -> {skip,"No openssh deamon"}; {ok, Socket} -> gen_tcp:close(Socket) - end; + end; init_per_group(_, Config) -> Config. @@ -180,10 +185,10 @@ big_cat(Config) when is_list(Config) -> case size(Data) =:= size(Other) of true -> ct:pal("received and sent data are same" - "size but do not match~n",[]); + "size but do not match~n",[]); false -> ct:pal("sent ~p but only received ~p~n", - [size(Data), size(Other)]) + [size(Data), size(Other)]) end, ct:fail(receive_data_mismatch); Else -> @@ -250,10 +255,10 @@ interrupted_send(Config) when is_list(Config) -> {subsystems, [{"echo_n", {ssh_echo_server, [4000000]}}]}]), ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user, "foo"}, - {password, "morot"}, - {user_interaction, false}, - {user_dir, UserDir}]), + {user, "foo"}, + {password, "morot"}, + {user_interaction, false}, + {user_dir, UserDir}]), {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity), @@ -288,24 +293,24 @@ start_shell(Config) when is_list(Config) -> file:make_dir(UserDir), SysDir = ?config(data_dir, Config), {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, - {user_dir, UserDir}, - {password, "morot"}, - {shell, fun(U, H) -> start_our_shell(U, H) end} ]), + {user_dir, UserDir}, + {password, "morot"}, + {shell, fun(U, H) -> start_our_shell(U, H) end} ]), ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user, "foo"}, - {password, "morot"}, - {user_interaction, true}, - {user_dir, UserDir}]), + {user, "foo"}, + {password, "morot"}, + {user_interaction, true}, + {user_dir, UserDir}]), {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity), ok = ssh_connection:shell(ConnectionRef,ChannelId0), receive - {ssh_cm,ConnectionRef, {data, ChannelId, 0, <<"Enter command\r\n">>}} -> - ok + {ssh_cm,ConnectionRef, {data, ChannelId0, 0, <<"Enter command\r\n">>}} -> + ok after 5000 -> - ct:fail("CLI Timeout") + ct:fail("CLI Timeout") end, ssh:close(ConnectionRef), @@ -320,25 +325,25 @@ start_shell_exec(Config) when is_list(Config) -> file:make_dir(UserDir), SysDir = ?config(data_dir, Config), {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, - {user_dir, UserDir}, - {password, "morot"}, - {exec, {?MODULE,ssh_exec,[]}} ]), + {user_dir, UserDir}, + {password, "morot"}, + {exec, {?MODULE,ssh_exec,[]}} ]), ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user, "foo"}, - {password, "morot"}, - {user_interaction, true}, - {user_dir, UserDir}]), + {user, "foo"}, + {password, "morot"}, + {user_interaction, true}, + {user_dir, UserDir}]), {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity), success = ssh_connection:exec(ConnectionRef, ChannelId0, - "testing", infinity), + "testing", infinity), receive {ssh_cm,ConnectionRef, {data, ChannelId, 0, <<"testing\r\n">>}} -> ok after 5000 -> - ct:fail("Exec Timeout") + ct:fail("Exec Timeout") end, ssh:close(ConnectionRef), @@ -354,30 +359,177 @@ start_shell_exec_fun(Config) when is_list(Config) -> file:make_dir(UserDir), SysDir = ?config(data_dir, Config), {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, - {user_dir, UserDir}, - {password, "morot"}, - {exec, fun ssh_exec/1}]), + {user_dir, UserDir}, + {password, "morot"}, + {exec, fun ssh_exec/1}]), ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user, "foo"}, - {password, "morot"}, - {user_interaction, true}, - {user_dir, UserDir}]), + {user, "foo"}, + {password, "morot"}, + {user_interaction, true}, + {user_dir, UserDir}]), {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity), success = ssh_connection:exec(ConnectionRef, ChannelId0, - "testing", infinity), + "testing", infinity), receive {ssh_cm,ConnectionRef, {data, ChannelId, 0, <<"testing\r\n">>}} -> ok after 5000 -> - ct:fail("Exec Timeout") + ct:fail("Exec Timeout") end, ssh:close(ConnectionRef), ssh:stop_daemon(Pid). + +%%-------------------------------------------------------------------- + +gracefull_invalid_version(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), + + {_Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir}, + {password, "morot"}]), + + {ok, S} = gen_tcp:connect(Host, Port, []), + ok = gen_tcp:send(S, ["SSH-8.-1","\r\n"]), + receive + Verstring -> + ct:pal("Server version: ~p~n", [Verstring]), + receive + {tcp_closed, S} -> + ok + end + end. + +gracefull_invalid_start(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), + {_Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir}, + {password, "morot"}]), + + {ok, S} = gen_tcp:connect(Host, Port, []), + ok = gen_tcp:send(S, ["foobar","\r\n"]), + receive + Verstring -> + ct:pal("Server version: ~p~n", [Verstring]), + receive + {tcp_closed, S} -> + ok + end + end. + +gracefull_invalid_long_start(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), + {_Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir}, + {password, "morot"}]), + + {ok, S} = gen_tcp:connect(Host, Port, []), + ok = gen_tcp:send(S, [lists:duplicate(257, $a), "\r\n"]), + receive + Verstring -> + ct:pal("Server version: ~p~n", [Verstring]), + receive + {tcp_closed, S} -> + ok + end + end. + + +gracefull_invalid_long_start_no_nl(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), + {_Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir}, + {password, "morot"}]), + + {ok, S} = gen_tcp:connect(Host, Port, []), + ok = gen_tcp:send(S, [lists:duplicate(257, $a), "\r\n"]), + receive + Verstring -> + ct:pal("Server version: ~p~n", [Verstring]), + receive + {tcp_closed, S} -> + ok + end + end. + +stop_listener() -> + [{doc, "start ssh daemon, setup connections, stop listener, restart listner"}]. + +stop_listener(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), + + {Pid0, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir}, + {password, "morot"}, + {exec, fun ssh_exec/1}]), + + ConnectionRef0 = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "morot"}, + {user_interaction, true}, + {user_dir, UserDir}]), + + {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef0, infinity), + + ssh:stop_listener(Host, Port), + + {error, _} = ssh:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "morot"}, + {user_interaction, true}, + {user_dir, UserDir}]), + success = ssh_connection:exec(ConnectionRef0, ChannelId0, + "testing", infinity), + receive + {ssh_cm, ConnectionRef0, {data, ChannelId0, 0, <<"testing\r\n">>}} -> + ok + after 5000 -> + ct:fail("Exec Timeout") + end, + + {ok, HostAddr} = inet:getaddr(Host, inet), + case ssh_test_lib:daemon(HostAddr, Port, [{system_dir, SysDir}, + {user_dir, UserDir}, + {password, "potatis"}, + {exec, fun ssh_exec/1}]) of + {Pid1, HostAddr, Port} -> + ConnectionRef1 = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "potatis"}, + {user_interaction, true}, + {user_dir, UserDir}]), + {error, _} = ssh:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "morot"}, + {user_interaction, true}, + {user_dir, UserDir}]), + ssh:close(ConnectionRef0), + ssh:close(ConnectionRef1), + ssh:stop_daemon(Pid0), + ssh:stop_daemon(Pid1); + Error -> + ct:fail({unexpected, Error}) + end. + %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- @@ -413,14 +565,14 @@ collect_data(ConnectionRef, ChannelId, Acc) -> end. %%%------------------------------------------------------------------- -% This is taken from the ssh example code. +%% This is taken from the ssh example code. start_our_shell(_User, _Peer) -> spawn(fun() -> - io:format("Enter command\n") - %% Don't actually loop, just exit + io:format("Enter command\n") + %% Don't actually loop, just exit end). ssh_exec(Cmd) -> spawn(fun() -> - io:format(Cmd ++ "\n") + io:format(Cmd ++ "\n") end). diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl index 00c25bf394..b8abf5e80e 100644 --- a/lib/ssh/test/ssh_test_lib.erl +++ b/lib/ssh/test/ssh_test_lib.erl @@ -113,6 +113,9 @@ io_request({put_chars, Chars}, TestCase, _, _, Buff) -> io_request({put_chars, unicode, Chars}, TestCase, _, _, Buff) when is_binary(Chars) -> reply(TestCase, Chars), {ok, ok, Buff}; +io_request({put_chars, unicode, io_lib, format, [Fmt,Args]}, TestCase, _, _, Buff) -> + reply(TestCase, io_lib:format(Fmt,Args)), + {ok, ok, Buff}; io_request({put_chars, Enc, Chars}, TestCase, _, _, Buff) -> reply(TestCase, unicode:characters_to_binary(Chars,Enc,latin1)), {ok, ok, Buff}; |