aboutsummaryrefslogtreecommitdiff
path: root/lang/erlang-runtime17
diff options
context:
space:
mode:
authorJimmy Olgeni <olgeni@FreeBSD.org>2015-06-02 12:26:03 +0000
committerJimmy Olgeni <olgeni@FreeBSD.org>2015-06-02 12:26:03 +0000
commit704b15243f53c4f34a5afbb8ff4cda592a8abd04 (patch)
treea9aed0153c3deec93b596f98935399baf574811a /lang/erlang-runtime17
parente0471dcdf8bdbbd18edbc5da972212c25691a520 (diff)
downloadports-704b15243f53c4f34a5afbb8ff4cda592a8abd04.tar.gz
ports-704b15243f53c4f34a5afbb8ff4cda592a8abd04.zip
Upgrade to version 17.5.6.
- Use PATCHFILES for revision patches, because upstream basically stopped rolling tarballs for minor updates. - Rebuild local patch files to make portlint happier.
Notes
Notes: svn path=/head/; revision=388324
Diffstat (limited to 'lang/erlang-runtime17')
-rw-r--r--lang/erlang-runtime17/Makefile21
-rw-r--r--lang/erlang-runtime17/distinfo12
-rw-r--r--lang/erlang-runtime17/files/patch-erts_emulator_drivers_common_efile__drv.c4
-rw-r--r--lang/erlang-runtime17/files/patch-erts_etc_unix_run__erl.c4
-rw-r--r--lang/erlang-runtime17/files/patch-lib_erl__interface_src_connect_ei__resolve.c4
-rw-r--r--lang/erlang-runtime17/files/patch-lib_stdlib_src_calendar.erl8
-rw-r--r--lang/erlang-runtime17/files/patch-otp-17.5.1826
-rw-r--r--lang/erlang-runtime17/files/patch-otp-17.5.2427
-rw-r--r--lang/erlang-runtime17/files/patch-otp-17.5.33738
-rw-r--r--lang/erlang-runtime17/files/patch-otp-17.5.4306
10 files changed, 37 insertions, 5313 deletions
diff --git a/lang/erlang-runtime17/Makefile b/lang/erlang-runtime17/Makefile
index 5fe400e7dab4..e0c843d5a254 100644
--- a/lang/erlang-runtime17/Makefile
+++ b/lang/erlang-runtime17/Makefile
@@ -2,7 +2,7 @@
# $FreeBSD$
PORTNAME= erlang
-PORTVERSION= 17.5.4
+PORTVERSION= 17.5.6
CATEGORIES= lang parallel java
MASTER_SITES= http://www.erlang.org/download/:erlangorg \
http://erlang.stacken.kth.se/download/:erlangorg \
@@ -14,6 +14,11 @@ DISTFILES= ${DISTNAME}${EXTRACT_SUFX}:erlangorg \
DIST_SUBDIR= erlang
EXTRACT_ONLY= ${DISTNAME}${EXTRACT_SUFX}
+PATCH_SITES= http://olgeni.olgeni.com/~olgeni/distfiles/ \
+ LOCAL/olgeni
+PATCHFILES= patch-otp-17.5.1 patch-otp-17.5.2 patch-otp-17.5.3 \
+ patch-otp-17.5.4 patch-otp-17.5.5 patch-otp-17.5.6
+
MAINTAINER= olgeni@FreeBSD.org
COMMENT= Functional programming language from Ericsson
@@ -158,7 +163,7 @@ MAKE_ARGS+= ARCH=x86
.if ${ARCH} == armv6
MAKE_ARGS+= ARCH=arm
-.endif
+.endif
# The man-pages are put (in spite of FreeBSD's port convention) in a private
# subdir. This is to avoid cluttering up the man page name space. Also the
@@ -199,11 +204,11 @@ post-install:
${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/erts-6.4
${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/inets-5.10.6/* \
- ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/inets-5.10.8
+ ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/inets-5.10.9
${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/inets-5.10.6
${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/ssh-3.2/* \
- ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/ssh-3.2.3
+ ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/ssh-3.2.4
${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/ssh-3.2
${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/common_test-1.10/* \
@@ -211,7 +216,7 @@ post-install:
${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/common_test-1.10
${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/diameter-1.9/* \
- ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/diameter-1.9.1
+ ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/diameter-1.9.2
${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/diameter-1.9
${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/snmp-5.1.1/* \
@@ -219,9 +224,13 @@ post-install:
${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/snmp-5.1.1
${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/test_server-3.8/* \
- ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/test_server-3.8.1
+ ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/test_server-3.8.1
${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/test_server-3.8
+ ${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/ssl-6.0/* \
+ ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/ssl-6.0.1
+ ${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/ssl-6.0
+
${INSTALL_DATA} ${WRKSRC}/lib/dialyzer/doc/*.txt \
${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/dialyzer-*/doc/
.endif
diff --git a/lang/erlang-runtime17/distinfo b/lang/erlang-runtime17/distinfo
index 503f40d69fda..5f0c010eaa89 100644
--- a/lang/erlang-runtime17/distinfo
+++ b/lang/erlang-runtime17/distinfo
@@ -4,3 +4,15 @@ SHA256 (erlang/otp_doc_man_17.5.tar.gz) = 85b1b2a1011fc01af550f1fe9e5a599a4c5f2a
SIZE (erlang/otp_doc_man_17.5.tar.gz) = 1363320
SHA256 (erlang/otp_doc_html_17.5.tar.gz) = baba1d373c1faacf4a1a6ec1220d57d0cb2b977edb74f32cd58dc786361c6cf5
SIZE (erlang/otp_doc_html_17.5.tar.gz) = 33510258
+SHA256 (erlang/patch-otp-17.5.1) = e95b17b539b84b2408cbdd8af68ea96ad239a1b38117243d21ebb809ab3ca1c3
+SIZE (erlang/patch-otp-17.5.1) = 36012
+SHA256 (erlang/patch-otp-17.5.2) = 9c70e90c3b040ab1e136738f355f0925f64afd5a4b28f1c9a6f4035f2bf03b1b
+SIZE (erlang/patch-otp-17.5.2) = 17821
+SHA256 (erlang/patch-otp-17.5.3) = fd2879176733c34c002123da9d9b96ac3cf1857c7422a061711be818aecc9e13
+SIZE (erlang/patch-otp-17.5.3) = 135959
+SHA256 (erlang/patch-otp-17.5.4) = dce1130adfabe4fdecd1e5e700bea70a5e9ba7886b51c81a7a2371e204d725ca
+SIZE (erlang/patch-otp-17.5.4) = 14618
+SHA256 (erlang/patch-otp-17.5.5) = 78f81dc17c52b73d45819de50fc11df3a19ff0593a6d5c6d105b5875c1e654f6
+SIZE (erlang/patch-otp-17.5.5) = 44523
+SHA256 (erlang/patch-otp-17.5.6) = 25461538cf79af56ee64019cfb76764bc5c2ac7cc9d3f9061ef01dd93d46ef36
+SIZE (erlang/patch-otp-17.5.6) = 57264
diff --git a/lang/erlang-runtime17/files/patch-erts_emulator_drivers_common_efile__drv.c b/lang/erlang-runtime17/files/patch-erts_emulator_drivers_common_efile__drv.c
index bc3c37541f66..a6447f81c7d2 100644
--- a/lang/erlang-runtime17/files/patch-erts_emulator_drivers_common_efile__drv.c
+++ b/lang/erlang-runtime17/files/patch-erts_emulator_drivers_common_efile__drv.c
@@ -1,6 +1,6 @@
---- erts/emulator/drivers/common/efile_drv.c.orig
+--- erts/emulator/drivers/common/efile_drv.c.orig 2015-03-31 12:32:52 UTC
+++ erts/emulator/drivers/common/efile_drv.c
-@@ -1938,6 +1938,8 @@
+@@ -1938,6 +1938,8 @@ static void invoke_sendfile(void *data)
d->result_ok = 1;
if (d->c.sendfile.nbytes != 0)
d->c.sendfile.nbytes -= nbytes;
diff --git a/lang/erlang-runtime17/files/patch-erts_etc_unix_run__erl.c b/lang/erlang-runtime17/files/patch-erts_etc_unix_run__erl.c
index 1a1306e79a21..b76c5127d2a8 100644
--- a/lang/erlang-runtime17/files/patch-erts_etc_unix_run__erl.c
+++ b/lang/erlang-runtime17/files/patch-erts_etc_unix_run__erl.c
@@ -1,6 +1,6 @@
---- erts/etc/unix/run_erl.c.orig
+--- erts/etc/unix/run_erl.c.orig 2015-03-31 12:32:52 UTC
+++ erts/etc/unix/run_erl.c
-@@ -69,9 +69,6 @@
+@@ -73,9 +73,6 @@
#ifdef HAVE_UTMP_H
# include <utmp.h>
#endif
diff --git a/lang/erlang-runtime17/files/patch-lib_erl__interface_src_connect_ei__resolve.c b/lang/erlang-runtime17/files/patch-lib_erl__interface_src_connect_ei__resolve.c
index a39b391e06f0..16046e8e4934 100644
--- a/lang/erlang-runtime17/files/patch-lib_erl__interface_src_connect_ei__resolve.c
+++ b/lang/erlang-runtime17/files/patch-lib_erl__interface_src_connect_ei__resolve.c
@@ -1,6 +1,6 @@
---- lib/erl_interface/src/connect/ei_resolve.c.orig
+--- lib/erl_interface/src/connect/ei_resolve.c.orig 2015-03-31 12:32:52 UTC
+++ lib/erl_interface/src/connect/ei_resolve.c
-@@ -621,7 +621,8 @@
+@@ -649,7 +649,8 @@ struct hostent *ei_gethostbyname_r(const
return result;
#else
diff --git a/lang/erlang-runtime17/files/patch-lib_stdlib_src_calendar.erl b/lang/erlang-runtime17/files/patch-lib_stdlib_src_calendar.erl
index 0af0683acb27..34b753d85b27 100644
--- a/lang/erlang-runtime17/files/patch-lib_stdlib_src_calendar.erl
+++ b/lang/erlang-runtime17/files/patch-lib_stdlib_src_calendar.erl
@@ -1,8 +1,8 @@
---- lib/stdlib/src/calendar.erl.orig
+--- lib/stdlib/src/calendar.erl.orig 2015-03-31 12:32:52 UTC
+++ lib/stdlib/src/calendar.erl
-@@ -215,11 +215,19 @@
-
- -spec local_time_to_universal_time_dst(t_datetime1970()) -> [t_datetime1970()].
+@@ -279,11 +279,19 @@ local_time_to_universal_time(DateTime, I
+ DateTime1 :: datetime1970(),
+ DateTime :: datetime1970().
local_time_to_universal_time_dst(DateTime) ->
- UtDst = erlang:localtime_to_universaltime(DateTime, true),
- Ut = erlang:localtime_to_universaltime(DateTime, false),
diff --git a/lang/erlang-runtime17/files/patch-otp-17.5.1 b/lang/erlang-runtime17/files/patch-otp-17.5.1
deleted file mode 100644
index 296b344a47cb..000000000000
--- a/lang/erlang-runtime17/files/patch-otp-17.5.1
+++ /dev/null
@@ -1,826 +0,0 @@
-diff --git OTP_VERSION OTP_VERSION
-index 6060b96..9cbaf23 100644
---- OTP_VERSION
-+++ OTP_VERSION
-@@ -1 +1 @@
--17.5
-+17.5.1
-diff --git lib/ssh/doc/src/notes.xml lib/ssh/doc/src/notes.xml
-index f22bca3..acbf312 100644
---- lib/ssh/doc/src/notes.xml
-+++ lib/ssh/doc/src/notes.xml
-@@ -29,6 +29,28 @@
- <file>notes.xml</file>
- </header>
-
-+<section><title>Ssh 3.2.1</title>
-+
-+ <section><title>Fixed Bugs and Malfunctions</title>
-+ <list>
-+ <item>
-+ <p>
-+ Ssh crashed if a message was sent on a channel with
-+ packet_size = 0.</p>
-+ <p>
-+ A new option for ssh:daemon is also introduced:
-+ <c>minimal_remote_max_packet_size</c>. This option sets
-+ the least max packet size declaration that the daemon
-+ will accept from a client. The default value is 0 to
-+ maintain compatibility with OpenSSH and the rfc:s.</p>
-+ <p>
-+ Own Id: OTP-12645 Aux Id: seq12816 </p>
-+ </item>
-+ </list>
-+ </section>
-+
-+</section>
-+
- <section><title>Ssh 3.2</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
-diff --git lib/ssh/doc/src/ssh.xml lib/ssh/doc/src/ssh.xml
-index d481a75..0e7e384 100644
---- lib/ssh/doc/src/ssh.xml
-+++ lib/ssh/doc/src/ssh.xml
-@@ -338,6 +338,12 @@
- </warning>
- </item>
-
-+ <tag><c><![CDATA[{minimal_remote_max_packet_size, non_negative_integer()}]]></c></tag>
-+ <item>
-+ <p>The least maximum packet size that the daemon will accept in channel open requests from the client. The default value is 0.
-+ </p>
-+ </item>
-+
- <tag><c><![CDATA[{key_cb, atom()}]]></c></tag>
- <item>
- <p>Module implementing the behaviour <seealso marker="ssh_server_key_api">ssh_server_key_api</seealso>.
-diff --git lib/ssh/src/ssh.appup.src lib/ssh/src/ssh.appup.src
-index b2b2994..e76c110 100644
---- lib/ssh/src/ssh.appup.src
-+++ lib/ssh/src/ssh.appup.src
-@@ -1,7 +1,7 @@
- %% -*- erlang -*-
- %% %CopyrightBegin%
- %%
--%% Copyright Ericsson AB 2004-2014. All Rights Reserved.
-+%% Copyright Ericsson AB 2004-2015. 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
-@@ -19,61 +19,9 @@
-
- {"%VSN%",
- [
-- {"3.0.8", [{load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_sftp, soft_purge, soft_purge, [ssh_xfer]},
-- {load_module, ssh_connection_handler, soft_purge, soft_purge, []},
-- {load_module, ssh, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_xfer, soft_purge, soft_purge, []}
-- ]},
-- {"3.0.7", [{load_module, ssh_auth, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_acceptor, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_channel, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_connection_handler, soft_purge, soft_purge, []},
-- {load_module, ssh_info, soft_purge, soft_purge, []},
-- {load_module, ssh_message, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_io, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_sftp, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_xfer, soft_purge, soft_purge, [ssh_connection_handler]}]},
-- {"3.0.6", [{load_module, ssh_auth, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_acceptor, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_channel, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_connection_handler, soft_purge, soft_purge, []},
-- {load_module, ssh_info, soft_purge, soft_purge, []},
-- {load_module, ssh_message, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_io, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_sftp, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_xfer, soft_purge, soft_purge, [ssh_connection_handler]}]},
- {<<".*">>, [{restart_application, ssh}]}
- ],
- [
-- {"3.0.8", [{load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_sftp, soft_purge, soft_purge, []},
-- {load_module, ssh_connection_handler, soft_purge, soft_purge, []},
-- {load_module, ssh, soft_purge, soft_purge, []},
-- {load_module, ssh_xfer, soft_purge, soft_purge, []}
-- ]},
-- {"3.0.7", [{load_module, ssh_auth, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_acceptor, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_channel, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_connection_handler, soft_purge, soft_purge, []},
-- {load_module, ssh_info, soft_purge, soft_purge, []},
-- {load_module, ssh_message, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_io, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_sftp, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_xfer, soft_purge, soft_purge, [ssh_connection_handler]}]},
-- {"3.0.6", [{load_module, ssh_auth, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_acceptor, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_channel, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_connection_handler, soft_purge, soft_purge, []},
-- {load_module, ssh_info, soft_purge, soft_purge, []},
-- {load_module, ssh_message, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_io, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_sftp, soft_purge, soft_purge, [ssh_connection_handler]},
-- {load_module, ssh_xfer, soft_purge, soft_purge, [ssh_connection_handler]}]},
- {<<".*">>, [{restart_application, ssh}]}
- ]
- }.
-diff --git lib/ssh/src/ssh.erl lib/ssh/src/ssh.erl
-index eae33e3..51ad691 100644
---- lib/ssh/src/ssh.erl
-+++ lib/ssh/src/ssh.erl
-@@ -345,9 +345,14 @@ handle_option([{parallel_login, _} = Opt|Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
- handle_option([parallel_login|Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option({parallel_login,true}) | SshOptions]);
-+handle_option([{minimal_remote_max_packet_size, _} = Opt|Rest], SocketOptions, SshOptions) ->
-+ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
- handle_option([Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, [handle_inet_option(Opt) | SocketOptions], SshOptions).
-
-+
-+handle_ssh_option({minimal_remote_max_packet_size, Value} = Opt) when is_integer(Value), Value >=0 ->
-+ Opt;
- handle_ssh_option({system_dir, Value} = Opt) when is_list(Value) ->
- Opt;
- handle_ssh_option({user_dir, Value} = Opt) when is_list(Value) ->
-diff --git lib/ssh/src/ssh_acceptor.erl lib/ssh/src/ssh_acceptor.erl
-index 6c443ee..34988f1 100644
---- lib/ssh/src/ssh_acceptor.erl
-+++ lib/ssh/src/ssh_acceptor.erl
-@@ -1,7 +1,7 @@
- %%
- %% %CopyrightBegin%
- %%
--%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
-+%% Copyright Ericsson AB 2008-2015. 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
-@@ -43,7 +43,7 @@ start_link(Port, Address, SockOpts, Opts, AcceptTimeout) ->
- acceptor_init(Parent, Port, Address, SockOpts, Opts, AcceptTimeout) ->
- {_, Callback, _} =
- proplists:get_value(transport, Opts, {tcp, gen_tcp, tcp_closed}),
-- case (catch do_socket_listen(Callback, Port, SockOpts)) of
-+ case (catch do_socket_listen(Callback, Port, [{active, false} | SockOpts])) of
- {ok, ListenSocket} ->
- proc_lib:init_ack(Parent, {ok, self()}),
- acceptor_loop(Callback,
-diff --git lib/ssh/src/ssh_connection.erl lib/ssh/src/ssh_connection.erl
-index c66f810..654b9d4 100644
---- lib/ssh/src/ssh_connection.erl
-+++ lib/ssh/src/ssh_connection.erl
-@@ -1,7 +1,7 @@
- %%
- %% %CopyrightBegin%
- %%
--%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
-+%% Copyright Ericsson AB 2008-2015. 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
-@@ -326,9 +326,7 @@ channel_data(ChannelId, DataType, Data,
- SendDataType,
- SendData)}
- end, SendList),
-- FlowCtrlMsgs = flow_control(Replies,
-- Channel,
-- Cache),
-+ FlowCtrlMsgs = flow_control(Replies, Channel, Cache),
- {{replies, Replies ++ FlowCtrlMsgs}, Connection};
- _ ->
- gen_fsm:reply(From, {error, closed}),
-@@ -470,18 +468,31 @@ handle_msg(#ssh_msg_channel_window_adjust{recipient_channel = ChannelId,
- handle_msg(#ssh_msg_channel_open{channel_type = "session" = Type,
- sender_channel = RemoteId,
- initial_window_size = WindowSz,
-- maximum_packet_size = PacketSz}, Connection0, server) ->
--
-- try setup_session(Connection0, RemoteId,
-- Type, WindowSz, PacketSz) of
-- Result ->
-- Result
-- catch _:_ ->
-+ maximum_packet_size = PacketSz},
-+ #connection{options = SSHopts} = Connection0,
-+ server) ->
-+ MinAcceptedPackSz = proplists:get_value(minimal_remote_max_packet_size, SSHopts, 0),
-+
-+ if
-+ MinAcceptedPackSz =< PacketSz ->
-+ try setup_session(Connection0, RemoteId,
-+ Type, WindowSz, PacketSz) of
-+ Result ->
-+ Result
-+ catch _:_ ->
-+ FailMsg = channel_open_failure_msg(RemoteId,
-+ ?SSH_OPEN_CONNECT_FAILED,
-+ "Connection refused", "en"),
-+ {{replies, [{connection_reply, FailMsg}]},
-+ Connection0}
-+ end;
-+
-+ MinAcceptedPackSz > PacketSz ->
- FailMsg = channel_open_failure_msg(RemoteId,
-- ?SSH_OPEN_CONNECT_FAILED,
-- "Connection refused", "en"),
-- {{replies, [{connection_reply, FailMsg}]},
-- Connection0}
-+ ?SSH_OPEN_ADMINISTRATIVELY_PROHIBITED,
-+ lists:concat(["Maximum packet size below ",MinAcceptedPackSz,
-+ " not supported"]), "en"),
-+ {{replies, [{connection_reply, FailMsg}]}, Connection0}
- end;
-
- handle_msg(#ssh_msg_channel_open{channel_type = "session",
-@@ -501,41 +512,57 @@ handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip" = Type,
- initial_window_size = RWindowSz,
- maximum_packet_size = RPacketSz,
- data = Data},
-- #connection{channel_cache = Cache} = Connection0, server) ->
-+ #connection{channel_cache = Cache,
-+ options = SSHopts} = Connection0, server) ->
- <<?UINT32(ALen), Address:ALen/binary, ?UINT32(Port),
- ?UINT32(OLen), Orig:OLen/binary, ?UINT32(OrigPort)>> = Data,
-
-- case bound_channel(Address, Port, Connection0) of
-- undefined ->
-+ MinAcceptedPackSz = proplists:get_value(minimal_remote_max_packet_size, SSHopts, 0),
-+
-+ if
-+ MinAcceptedPackSz =< RPacketSz ->
-+ case bound_channel(Address, Port, Connection0) of
-+ undefined ->
-+ FailMsg = channel_open_failure_msg(RemoteId,
-+ ?SSH_OPEN_CONNECT_FAILED,
-+ "Connection refused", "en"),
-+ {{replies,
-+ [{connection_reply, FailMsg}]}, Connection0};
-+ ChannelPid ->
-+ {ChannelId, Connection1} = new_channel_id(Connection0),
-+ LWindowSz = ?DEFAULT_WINDOW_SIZE,
-+ LPacketSz = ?DEFAULT_PACKET_SIZE,
-+ Channel = #channel{type = Type,
-+ sys = "none",
-+ user = ChannelPid,
-+ local_id = ChannelId,
-+ recv_window_size = LWindowSz,
-+ recv_packet_size = LPacketSz,
-+ send_window_size = RWindowSz,
-+ send_packet_size = RPacketSz,
-+ send_buf = queue:new()
-+ },
-+ ssh_channel:cache_update(Cache, Channel),
-+ OpenConfMsg = channel_open_confirmation_msg(RemoteId, ChannelId,
-+ LWindowSz, LPacketSz),
-+ {OpenMsg, Connection} =
-+ reply_msg(Channel, Connection1,
-+ {open, Channel, {forwarded_tcpip,
-+ decode_ip(Address), Port,
-+ decode_ip(Orig), OrigPort}}),
-+ {{replies, [{connection_reply, OpenConfMsg},
-+ OpenMsg]}, Connection}
-+ end;
-+
-+ MinAcceptedPackSz > RPacketSz ->
- FailMsg = channel_open_failure_msg(RemoteId,
-- ?SSH_OPEN_CONNECT_FAILED,
-- "Connection refused", "en"),
-- {{replies,
-- [{connection_reply, FailMsg}]}, Connection0};
-- ChannelPid ->
-- {ChannelId, Connection1} = new_channel_id(Connection0),
-- LWindowSz = ?DEFAULT_WINDOW_SIZE,
-- LPacketSz = ?DEFAULT_PACKET_SIZE,
-- Channel = #channel{type = Type,
-- sys = "none",
-- user = ChannelPid,
-- local_id = ChannelId,
-- recv_window_size = LWindowSz,
-- recv_packet_size = LPacketSz,
-- send_window_size = RWindowSz,
-- send_packet_size = RPacketSz},
-- ssh_channel:cache_update(Cache, Channel),
-- OpenConfMsg = channel_open_confirmation_msg(RemoteId, ChannelId,
-- LWindowSz, LPacketSz),
-- {OpenMsg, Connection} =
-- reply_msg(Channel, Connection1,
-- {open, Channel, {forwarded_tcpip,
-- decode_ip(Address), Port,
-- decode_ip(Orig), OrigPort}}),
-- {{replies, [{connection_reply, OpenConfMsg},
-- OpenMsg]}, Connection}
-+ ?SSH_OPEN_ADMINISTRATIVELY_PROHIBITED,
-+ lists:concat(["Maximum packet size below ",MinAcceptedPackSz,
-+ " not supported"]), "en"),
-+ {{replies, [{connection_reply, FailMsg}]}, Connection0}
- end;
-
-+
- handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip",
- sender_channel = RemoteId},
- Connection, client) ->
-@@ -917,7 +944,8 @@ start_channel(Cb, Id, Args, SubSysSup, Exec) ->
- %%--------------------------------------------------------------------
- %%% Internal functions
- %%--------------------------------------------------------------------
--setup_session(#connection{channel_cache = Cache} = Connection0,
-+setup_session(#connection{channel_cache = Cache
-+ } = Connection0,
- RemoteId,
- Type, WindowSize, PacketSize) ->
- {ChannelId, Connection} = new_channel_id(Connection0),
-@@ -929,6 +957,7 @@ setup_session(#connection{channel_cache = Cache} = Connection0,
- recv_packet_size = ?DEFAULT_PACKET_SIZE,
- send_window_size = WindowSize,
- send_packet_size = PacketSize,
-+ send_buf = queue:new(),
- remote_id = RemoteId
- },
- ssh_channel:cache_update(Cache, Channel),
-@@ -1024,63 +1053,74 @@ request_reply_or_data(#channel{local_id = ChannelId, user = ChannelPid},
-
- update_send_window(Channel, _, undefined,
- #connection{channel_cache = Cache}) ->
-- do_update_send_window(Channel, Channel#channel.send_buf, Cache);
-+ do_update_send_window(Channel, Cache);
-
--update_send_window(Channel, DataType, Data,
-+update_send_window(#channel{send_buf = SendBuffer} = Channel, DataType, Data,
- #connection{channel_cache = Cache}) ->
-- do_update_send_window(Channel, Channel#channel.send_buf ++ [{DataType, Data}], Cache).
-+ do_update_send_window(Channel#channel{send_buf = queue:in({DataType, Data}, SendBuffer)},
-+ Cache).
-
--do_update_send_window(Channel0, Buf0, Cache) ->
-- {Buf1, NewSz, Buf2} = get_window(Buf0,
-- Channel0#channel.send_packet_size,
-- Channel0#channel.send_window_size),
--
-- Channel = Channel0#channel{send_window_size = NewSz, send_buf = Buf2},
-+do_update_send_window(Channel0, Cache) ->
-+ {SendMsgs, Channel} = get_window(Channel0, []),
- ssh_channel:cache_update(Cache, Channel),
-- {Buf1, Channel}.
-+ {SendMsgs, Channel}.
-
--get_window(Bs, PSz, WSz) ->
-- get_window(Bs, PSz, WSz, []).
--
--get_window(Bs, _PSz, 0, Acc) ->
-- {lists:reverse(Acc), 0, Bs};
--get_window([B0 = {DataType, Bin} | Bs], PSz, WSz, Acc) ->
-- BSz = size(Bin),
-- if BSz =< WSz -> %% will fit into window
-- if BSz =< PSz -> %% will fit into a packet
-- get_window(Bs, PSz, WSz-BSz, [B0|Acc]);
-- true -> %% split into packet size
-- <<Bin1:PSz/binary, Bin2/binary>> = Bin,
-- get_window([setelement(2, B0, Bin2) | Bs],
-- PSz, WSz-PSz,
-- [{DataType, Bin1}|Acc])
-+get_window(#channel{send_window_size = 0
-+ } = Channel, Acc) ->
-+ {lists:reverse(Acc), Channel};
-+get_window(#channel{send_packet_size = 0
-+ } = Channel, Acc) ->
-+ {lists:reverse(Acc), Channel};
-+get_window(#channel{send_buf = Buffer,
-+ send_packet_size = PacketSize,
-+ send_window_size = WindowSize0
-+ } = Channel, Acc0) ->
-+ case queue:out(Buffer) of
-+ {{value, {_, Data} = Msg}, NewBuffer} ->
-+ case handle_send_window(Msg, size(Data), PacketSize, WindowSize0, Acc0) of
-+ {WindowSize, Acc, {_, <<>>}} ->
-+ {lists:reverse(Acc), Channel#channel{send_window_size = WindowSize,
-+ send_buf = NewBuffer}};
-+ {WindowSize, Acc, Rest} ->
-+ get_window(Channel#channel{send_window_size = WindowSize,
-+ send_buf = queue:in_r(Rest, NewBuffer)}, Acc)
- end;
-- WSz =< PSz -> %% use rest of window
-- <<Bin1:WSz/binary, Bin2/binary>> = Bin,
-- get_window([setelement(2, B0, Bin2) | Bs],
-- PSz, WSz-WSz,
-- [{DataType, Bin1}|Acc]);
-- true -> %% use packet size
-- <<Bin1:PSz/binary, Bin2/binary>> = Bin,
-- get_window([setelement(2, B0, Bin2) | Bs],
-- PSz, WSz-PSz,
-- [{DataType, Bin1}|Acc])
-+ {empty, NewBuffer} ->
-+ {[], Channel#channel{send_buf = NewBuffer}}
-+ end.
-+
-+handle_send_window(Msg = {Type, Data}, Size, PacketSize, WindowSize, Acc) when Size =< WindowSize ->
-+ case Size =< PacketSize of
-+ true ->
-+ {WindowSize - Size, [Msg | Acc], {Type, <<>>}};
-+ false ->
-+ <<Msg1:PacketSize/binary, Msg2/binary>> = Data,
-+ {WindowSize - PacketSize, [{Type, Msg1} | Acc], {Type, Msg2}}
- end;
--get_window([], _PSz, WSz, Acc) ->
-- {lists:reverse(Acc), WSz, []}.
-+handle_send_window({Type, Data}, _, PacketSize, WindowSize, Acc) when WindowSize =< PacketSize ->
-+ <<Msg1:WindowSize/binary, Msg2/binary>> = Data,
-+ {WindowSize - WindowSize, [{Type, Msg1} | Acc], {Type, Msg2}};
-+handle_send_window({Type, Data}, _, PacketSize, WindowSize, Acc) ->
-+ <<Msg1:PacketSize/binary, Msg2/binary>> = Data,
-+ {WindowSize - PacketSize, [{Type, Msg1} | Acc], {Type, Msg2}}.
-
- flow_control(Channel, Cache) ->
- flow_control([window_adjusted], Channel, Cache).
--
-+
- flow_control([], Channel, Cache) ->
- ssh_channel:cache_update(Cache, Channel),
- [];
--
- flow_control([_|_], #channel{flow_control = From,
-- send_buf = []} = Channel, Cache) when From =/= undefined ->
-- [{flow_control, Cache, Channel, From, ok}];
-+ send_buf = Buffer} = Channel, Cache) when From =/= undefined ->
-+ case queue:is_empty(Buffer) of
-+ true ->
-+ ssh_channel:cache_update(Cache, Channel#channel{flow_control = undefined}),
-+ [{flow_control, Cache, Channel, From, ok}];
-+ false ->
-+ []
-+ end;
- flow_control(_,_,_) ->
-- [].
-+ [].
-
- pty_req(ConnectionHandler, Channel, Term, Width, Height,
- PixWidth, PixHeight, PtyOpts, TimeOut) ->
-diff --git lib/ssh/src/ssh_connection_handler.erl lib/ssh/src/ssh_connection_handler.erl
-index 68523aa..e1f2e05 100644
---- lib/ssh/src/ssh_connection_handler.erl
-+++ lib/ssh/src/ssh_connection_handler.erl
-@@ -1,7 +1,7 @@
- %%
- %% %CopyrightBegin%
- %%
--%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
-+%% Copyright Ericsson AB 2008-2015. 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
-@@ -751,7 +751,9 @@ handle_sync_event({open, ChannelPid, Type, InitialWindowSize, MaxPacketSize, Dat
- user = ChannelPid,
- local_id = ChannelId,
- recv_window_size = InitialWindowSize,
-- recv_packet_size = MaxPacketSize},
-+ recv_packet_size = MaxPacketSize,
-+ send_buf = queue:new()
-+ },
- ssh_channel:cache_update(Cache, Channel),
- State = add_request(true, ChannelId, From, State2),
- start_timeout(ChannelId, From, Timeout),
-@@ -1241,10 +1243,9 @@ event(Event, StateName, State) ->
- handle_disconnect(DisconnectMsg, State);
- throw:{ErrorToDisplay, #ssh_msg_disconnect{} = DisconnectMsg} ->
- handle_disconnect(DisconnectMsg, State, ErrorToDisplay);
-- _:Error ->
-- log_error(Error),
-+ _:_ ->
- handle_disconnect(#ssh_msg_disconnect{code = error_code(StateName),
-- description = "Internal error",
-+ description = "Invalid state",
- language = "en"}, State)
- end.
- error_code(key_exchange) ->
-diff --git lib/ssh/src/ssh_info.erl lib/ssh/src/ssh_info.erl
-index 9a91875..30df32c 100644
---- lib/ssh/src/ssh_info.erl
-+++ lib/ssh/src/ssh_info.erl
-@@ -27,18 +27,21 @@
- -compile(export_all).
-
- print() ->
-+ print(user).
-+
-+print(D) ->
- try supervisor:which_children(ssh_sup)
- of
- _ ->
-- io:nl(),
-- print_general(),
-- io:nl(),
-- underline("Client part", $=),
-- print_clients(),
-- io:nl(),
-- underline("Server part", $=),
-- print_servers(),
-- io:nl(),
-+ io:nl(D),
-+ print_general(D),
-+ io:nl(D),
-+ underline(D, "Client part", $=),
-+ print_clients(D),
-+ io:nl(D),
-+ underline(D, "Server part", $=),
-+ print_servers(D),
-+ io:nl(D),
- %% case os:type() of
- %% {unix,_} ->
- %% io:nl(),
-@@ -50,90 +53,95 @@ print() ->
- %% catch io:format(os:cmd("netstat -tpn"));
- %% _ -> ok
- %% end,
-- underline("Supervisors", $=),
-- walk_sups(ssh_sup),
-- io:nl()
-+ underline(D, "Supervisors", $=),
-+ walk_sups(D, ssh_sup),
-+ io:nl(D)
- catch
- _:_ ->
-- io:format("Ssh not found~n",[])
-+ io:format(D,"Ssh not found~n",[])
- end.
-
- %%%================================================================
--print_general() ->
-+print_general(D) ->
- {_Name, Slogan, Ver} = lists:keyfind(ssh,1,application:which_applications()),
-- underline(io_lib:format("~s ~s", [Slogan, Ver]), $=),
-- io:format('This printout is generated ~s. ~n',[datetime()]).
-+ underline(D, io_lib:format("~s ~s", [Slogan, Ver]), $=),
-+ io:format(D, 'This printout is generated ~s. ~n',[datetime()]).
-
- %%%================================================================
--print_clients() ->
-+print_clients(D) ->
-+ PrintClient = fun(X) -> print_client(D,X) end,
- try
-- lists:foreach(fun print_client/1, supervisor:which_children(sshc_sup))
-+ lists:foreach(PrintClient, supervisor:which_children(sshc_sup))
- catch
- C:E ->
-- io:format('***FAILED: ~p:~p~n',[C,E])
-+ io:format(D, '***FAILED: ~p:~p~n',[C,E])
- end.
-
--print_client({undefined,Pid,supervisor,[ssh_connection_handler]}) ->
-+print_client(D, {undefined,Pid,supervisor,[ssh_connection_handler]}) ->
- {{Local,Remote},_Str} = ssh_connection_handler:get_print_info(Pid),
-- io:format(" Local=~s Remote=~s~n",[fmt_host_port(Local),fmt_host_port(Remote)]);
--print_client(Other) ->
-- io:format(" [[Other 1: ~p]]~n",[Other]).
-+ io:format(D, " Local=~s Remote=~s~n",[fmt_host_port(Local),fmt_host_port(Remote)]);
-+print_client(D, Other) ->
-+ io:format(D, " [[Other 1: ~p]]~n",[Other]).
-
-
- %%%================================================================
--print_servers() ->
-+print_servers(D) ->
-+ PrintServer = fun(X) -> print_server(D,X) end,
- try
-- lists:foreach(fun print_server/1, supervisor:which_children(sshd_sup))
-+ lists:foreach(PrintServer, supervisor:which_children(sshd_sup))
- catch
- C:E ->
-- io:format('***FAILED: ~p:~p~n',[C,E])
-+ io:format(D, '***FAILED: ~p:~p~n',[C,E])
- end.
-
--print_server({{server,ssh_system_sup,LocalHost,LocalPort},Pid,supervisor,[ssh_system_sup]}) when is_pid(Pid) ->
-- io:format('Local=~s (~p children)~n',[fmt_host_port({LocalHost,LocalPort}),
-- ssh_acceptor:number_of_connections(Pid)]),
-- lists:foreach(fun print_system_sup/1, supervisor:which_children(Pid));
--print_server(Other) ->
-- io:format(" [[Other 2: ~p]]~n",[Other]).
-+print_server(D, {{server,ssh_system_sup,LocalHost,LocalPort},Pid,supervisor,[ssh_system_sup]}) when is_pid(Pid) ->
-+ io:format(D, 'Local=~s (~p children)~n',[fmt_host_port({LocalHost,LocalPort}),
-+ ssh_acceptor:number_of_connections(Pid)]),
-+ PrintSystemSup = fun(X) -> print_system_sup(D,X) end,
-+ lists:foreach(PrintSystemSup, supervisor:which_children(Pid));
-+print_server(D, Other) ->
-+ io:format(D, " [[Other 2: ~p]]~n",[Other]).
-
--print_system_sup({Ref,Pid,supervisor,[ssh_subsystem_sup]}) when is_reference(Ref),
-+print_system_sup(D, {Ref,Pid,supervisor,[ssh_subsystem_sup]}) when is_reference(Ref),
- is_pid(Pid) ->
-- lists:foreach(fun print_channels/1, supervisor:which_children(Pid));
--print_system_sup({{ssh_acceptor_sup,LocalHost,LocalPort}, Pid,supervisor, [ssh_acceptor_sup]}) when is_pid(Pid) ->
-- io:format(" [Acceptor for ~s]~n",[fmt_host_port({LocalHost,LocalPort})]);
--print_system_sup(Other) ->
-- io:format(" [[Other 3: ~p]]~n",[Other]).
-+ PrintChannels = fun(X) -> print_channels(D,X) end,
-+ lists:foreach(PrintChannels, supervisor:which_children(Pid));
-+print_system_sup(D, {{ssh_acceptor_sup,LocalHost,LocalPort}, Pid,supervisor, [ssh_acceptor_sup]}) when is_pid(Pid) ->
-+ io:format(D, " [Acceptor for ~s]~n",[fmt_host_port({LocalHost,LocalPort})]);
-+print_system_sup(D, Other) ->
-+ io:format(D, " [[Other 3: ~p]]~n",[Other]).
-
--print_channels({{server,ssh_channel_sup,_,_},Pid,supervisor,[ssh_channel_sup]}) when is_pid(Pid) ->
-- lists:foreach(fun print_channel/1, supervisor:which_children(Pid));
--print_channels(Other) ->
-- io:format(" [[Other 4: ~p]]~n",[Other]).
-+print_channels(D, {{server,ssh_channel_sup,_,_},Pid,supervisor,[ssh_channel_sup]}) when is_pid(Pid) ->
-+ PrintChannel = fun(X) -> print_channel(D,X) end,
-+ lists:foreach(PrintChannel, supervisor:which_children(Pid));
-+print_channels(D, Other) ->
-+ io:format(D, " [[Other 4: ~p]]~n",[Other]).
-
-
--print_channel({Ref,Pid,worker,[ssh_channel]}) when is_reference(Ref),
-- is_pid(Pid) ->
-+print_channel(D, {Ref,Pid,worker,[ssh_channel]}) when is_reference(Ref),
-+ is_pid(Pid) ->
- {{ConnManager,ChannelID}, Str} = ssh_channel:get_print_info(Pid),
- {{Local,Remote},StrM} = ssh_connection_handler:get_print_info(ConnManager),
-- io:format(' ch ~p: ~s ~s',[ChannelID, StrM, Str]),
-- io:format(" Local=~s Remote=~s~n",[fmt_host_port(Local),fmt_host_port(Remote)]);
--print_channel(Other) ->
-- io:format(" [[Other 5: ~p]]~n",[Other]).
-+ io:format(D, ' ch ~p: ~s ~s',[ChannelID, StrM, Str]),
-+ io:format(D, " Local=~s Remote=~s~n",[fmt_host_port(Local),fmt_host_port(Remote)]);
-+print_channel(D, Other) ->
-+ io:format(D, " [[Other 5: ~p]]~n",[Other]).
-
- %%%================================================================
- -define(inc(N), (N+4)).
-
--walk_sups(StartPid) ->
-- io:format("Start at ~p, ~s.~n",[StartPid,dead_or_alive(StartPid)]),
-- walk_sups(children(StartPid), _Indent=?inc(0)).
-+walk_sups(D, StartPid) ->
-+ io:format(D, "Start at ~p, ~s.~n",[StartPid,dead_or_alive(StartPid)]),
-+ walk_sups(D, children(StartPid), _Indent=?inc(0)).
-
--walk_sups([H={_,Pid,SupOrWorker,_}|T], Indent) ->
-- indent(Indent), io:format('~200p ~p is ~s~n',[H,Pid,dead_or_alive(Pid)]),
-+walk_sups(D, [H={_,Pid,SupOrWorker,_}|T], Indent) ->
-+ indent(D, Indent), io:format(D, '~200p ~p is ~s~n',[H,Pid,dead_or_alive(Pid)]),
- case SupOrWorker of
-- supervisor -> walk_sups(children(Pid), ?inc(Indent));
-+ supervisor -> walk_sups(D, children(Pid), ?inc(Indent));
- _ -> ok
- end,
-- walk_sups(T, Indent);
--walk_sups([], _) ->
-+ walk_sups(D, T, Indent);
-+walk_sups(_D, [], _) ->
- ok.
-
- dead_or_alive(Name) when is_atom(Name) ->
-@@ -149,7 +157,7 @@ dead_or_alive(Pid) when is_pid(Pid) ->
- _ -> "alive"
- end.
-
--indent(I) -> io:format('~*c',[I,$ ]).
-+indent(D, I) -> io:format(D,'~*c',[I,$ ]).
-
- children(Pid) ->
- Parent = self(),
-@@ -166,16 +174,16 @@ children(Pid) ->
- end.
-
- %%%================================================================
--underline(Str) ->
-- underline(Str, $-).
-+underline(D, Str) ->
-+ underline(D, Str, $-).
-
--underline(Str, LineChar) ->
-+underline(D, Str, LineChar) ->
- Len = lists:flatlength(Str),
-- io:format('~s~n',[Str]),
-- line(Len,LineChar).
-+ io:format(D, '~s~n',[Str]),
-+ line(D,Len,LineChar).
-
--line(Len, Char) ->
-- io:format('~*c~n', [Len,Char]).
-+line(D, Len, Char) ->
-+ io:format(D, '~*c~n', [Len,Char]).
-
-
- datetime() ->
-@@ -188,6 +196,6 @@ fmt_host_port({Host,Port}) -> io_lib:format('~s:~p',[Host,Port]).
-
-
-
--nyi() ->
-- io:format('Not yet implemented~n',[]),
-+nyi(D) ->
-+ io:format(D,'Not yet implemented~n',[]),
- nyi.
-diff --git lib/ssh/test/ssh_basic_SUITE.erl lib/ssh/test/ssh_basic_SUITE.erl
-index 45c0303..81c7b5c 100644
---- lib/ssh/test/ssh_basic_SUITE.erl
-+++ lib/ssh/test/ssh_basic_SUITE.erl
-@@ -50,6 +50,8 @@ all() ->
- double_close,
- ssh_connect_timeout,
- ssh_connect_arg4_timeout,
-+ packet_size_zero,
-+ ssh_daemon_minimal_remote_max_packet_size_option,
- {group, hardening_tests}
- ].
-
-@@ -757,6 +759,64 @@ ms_passed(N1={_,_,M1}, N2={_,_,M2}) ->
- 1000 * (Min*60 + Sec + (M2-M1)/1000000).
-
- %%--------------------------------------------------------------------
-+packet_size_zero(Config) ->
-+ SystemDir = ?config(data_dir, 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),
-+
-+ {Server, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
-+ {user_dir, UserDir},
-+ {user_passwords, [{"vego", "morot"}]}]),
-+ Conn =
-+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
-+ {user_dir, UserDir},
-+ {user_interaction, false},
-+ {user, "vego"},
-+ {password, "morot"}]),
-+
-+ {ok,Chan} = ssh_connection:session_channel(Conn, 1000, _MaxPacketSize=0, 60000),
-+ ok = ssh_connection:shell(Conn, Chan),
-+
-+ ssh:close(Conn),
-+ ssh:stop_daemon(Server),
-+
-+ receive
-+ {ssh_cm,Conn,{data,Chan,_Type,_Msg1}} = M ->
-+ ct:pal("Got ~p",[M]),
-+ ct:fail(doesnt_obey_max_packet_size_0)
-+ after 5000 ->
-+ ok
-+ end.
-+
-+%%--------------------------------------------------------------------
-+ssh_daemon_minimal_remote_max_packet_size_option(Config) ->
-+ SystemDir = ?config(data_dir, 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),
-+
-+ {Server, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
-+ {user_dir, UserDir},
-+ {user_passwords, [{"vego", "morot"}]},
-+ {failfun, fun ssh_test_lib:failfun/2},
-+ {minimal_remote_max_packet_size, 14}]),
-+ Conn =
-+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
-+ {user_dir, UserDir},
-+ {user_interaction, false},
-+ {user, "vego"},
-+ {password, "morot"}]),
-+
-+ %% Try the limits of the minimal_remote_max_packet_size:
-+ {ok, _ChannelId} = ssh_connection:session_channel(Conn, 100, 14, infinity),
-+ {open_error,_,"Maximum packet size below 14 not supported",_} =
-+ ssh_connection:session_channel(Conn, 100, 13, infinity),
-+
-+ ssh:close(Conn),
-+ ssh:stop_daemon(Server).
-+
-+%%--------------------------------------------------------------------
- ssh_connect_negtimeout_parallel(Config) -> ssh_connect_negtimeout(Config,true).
- ssh_connect_negtimeout_sequential(Config) -> ssh_connect_negtimeout(Config,false).
-
-@@ -970,7 +1030,7 @@ max_sessions(Config, ParallelLogin, Connect0) when is_function(Connect0,2) ->
-
- %% Due to timing the error message may or may not be delivered to
- %% the "tcp-application" before the socket closed message is recived
--check_error("Internal error") ->
-+check_error("Invalid state") ->
- ok;
- check_error("Connection closed") ->
- ok;
-diff --git lib/ssh/vsn.mk lib/ssh/vsn.mk
-index 0d90278..fec8dac 100644
---- lib/ssh/vsn.mk
-+++ lib/ssh/vsn.mk
-@@ -1,5 +1,4 @@
- #-*-makefile-*- ; force emacs to enter makefile-mode
-
--SSH_VSN = 3.2
-+SSH_VSN = 3.2.1
- APP_VSN = "ssh-$(SSH_VSN)"
--
-diff --git otp_versions.table otp_versions.table
-index 64ffd82..a82f535 100644
---- otp_versions.table
-+++ otp_versions.table
-@@ -1,3 +1,4 @@
-+OTP-17.5.1 : ssh-3.2.1 # asn1-3.0.4 common_test-1.10 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.6 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.1 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
- OTP-17.5 : asn1-3.0.4 common_test-1.10 compiler-5.0.4 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9 eldap-1.1.1 erts-6.4 hipe-3.11.3 inets-5.10.6 kernel-3.2 mnesia-4.12.5 observer-2.0.4 os_mon-2.3.1 public_key-0.23 runtime_tools-1.8.16 ssh-3.2 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8 tools-2.7.2 wx-1.3.3 # cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 edoc-0.7.16 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 ic-4.3.6 jinterface-1.5.12 megaco-3.17.3 odbc-2.10.22 orber-3.7.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 reltool-0.6.6 sasl-2.4.1 snmp-5.1.1 typer-0.9.8 webtool-0.8.10 xmerl-1.3.7 :
- OTP-17.4.1 : erts-6.3.1 inets-5.10.5 # asn1-3.0.3 common_test-1.9 compiler-5.0.3 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.4.2 debugger-4.0.2 dialyzer-2.7.3 diameter-1.8 edoc-0.7.16 eldap-1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.2 ic-4.3.6 jinterface-1.5.12 kernel-3.1 megaco-3.17.3 mnesia-4.12.4 observer-2.0.3 odbc-2.10.22 orber-3.7.1 os_mon-2.3 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.22.1 reltool-0.6.6 runtime_tools-1.8.15 sasl-2.4.1 snmp-5.1.1 ssh-3.1 ssl-5.3.8 stdlib-2.3 syntax_tools-1.6.17 test_server-3.7.2 tools-2.7.1 typer-0.9.8 webtool-0.8.10 wx-1.3.2 xmerl-1.3.7 :
- OTP-17.4 : asn1-3.0.3 common_test-1.9 compiler-5.0.3 crypto-3.4.2 debugger-4.0.2 dialyzer-2.7.3 diameter-1.8 edoc-0.7.16 eldap-1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.3 eunit-2.2.9 hipe-3.11.2 inets-5.10.4 jinterface-1.5.12 kernel-3.1 megaco-3.17.3 mnesia-4.12.4 observer-2.0.3 odbc-2.10.22 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 runtime_tools-1.8.15 snmp-5.1.1 ssh-3.1 ssl-5.3.8 stdlib-2.3 syntax_tools-1.6.17 test_server-3.7.2 tools-2.7.1 wx-1.3.2 # cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 et-1.5 gs-1.5.16 ic-4.3.6 orber-3.7.1 os_mon-2.3 ose-1.0.2 public_key-0.22.1 reltool-0.6.6 sasl-2.4.1 typer-0.9.8 webtool-0.8.10 xmerl-1.3.7 :
diff --git a/lang/erlang-runtime17/files/patch-otp-17.5.2 b/lang/erlang-runtime17/files/patch-otp-17.5.2
deleted file mode 100644
index 3be7ef0060d0..000000000000
--- a/lang/erlang-runtime17/files/patch-otp-17.5.2
+++ /dev/null
@@ -1,427 +0,0 @@
-diff --git OTP_VERSION OTP_VERSION
-index 9cbaf23..808ab16 100644
---- OTP_VERSION
-+++ OTP_VERSION
-@@ -1 +1 @@
--17.5.1
-+17.5.2
-diff --git lib/inets/doc/src/httpd.xml lib/inets/doc/src/httpd.xml
-index 20c8a6b..e40660a 100644
---- lib/inets/doc/src/httpd.xml
-+++ lib/inets/doc/src/httpd.xml
-@@ -315,7 +315,7 @@ text/plain asc txt
- </item>
-
- <marker id="prop_server_tokens"></marker>
-- <tag>{server_tokens, prod|major|minor|minimal|os|full|{private, string()}}</tag>
-+ <tag>{server_tokens, none|prod|major|minor|minimal|os|full|{private, string()}}</tag>
- <item>
- <p>ServerTokens defines how the value of the server header
- should look. </p>
-@@ -323,6 +323,7 @@ text/plain asc txt
- here is what the server header string could look like for
- the different values of server-tokens: </p>
- <pre>
-+none "" % A Server: header will not be generated
- prod "inets"
- major "inets/5"
- minor "inets/5.8"
-diff --git lib/inets/doc/src/notes.xml lib/inets/doc/src/notes.xml
-index 2c3ee79..12bbc2b 100644
---- lib/inets/doc/src/notes.xml
-+++ lib/inets/doc/src/notes.xml
-@@ -32,7 +32,28 @@
- <file>notes.xml</file>
- </header>
-
-- <section><title>Inets 5.10.6</title>
-+ <section><title>Inets 5.10.7</title>
-+
-+ <section><title>Improvements and New Features</title>
-+ <list>
-+ <item>
-+ <p>
-+ New value in <c>server_tokens</c> config for limiting
-+ banner grabbing attempts. </p>
-+ <p>
-+ By setting <c>{server_tokens, none}</c> in
-+ <c>ServiceConfig</c> for <c>inets:start(httpd,
-+ ServiceConfig)</c>, the "Server:" header will not be set
-+ in messages from the server.</p>
-+ <p>
-+ Own Id: OTP-12661 Aux Id: seq12840 </p>
-+ </item>
-+ </list>
-+ </section>
-+
-+</section>
-+
-+<section><title>Inets 5.10.6</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
-diff --git lib/inets/src/http_server/httpd_conf.erl lib/inets/src/http_server/httpd_conf.erl
-index 78dda79..dbdc1be 100644
---- lib/inets/src/http_server/httpd_conf.erl
-+++ lib/inets/src/http_server/httpd_conf.erl
-@@ -219,14 +219,14 @@ load("ServerName " ++ ServerName, []) ->
-
- load("ServerTokens " ++ ServerTokens, []) ->
- %% These are the valid *plain* server tokens:
-- %% sprod, major, minor, minimum, os, full
-+ %% none, prod, major, minor, minimum, os, full
- %% It can also be a "private" server token: private:<any string>
- case string:tokens(ServerTokens, [$:]) of
- ["private", Private] ->
- {ok,[], {server_tokens, clean(Private)}};
- [TokStr] ->
- Tok = list_to_atom(clean(TokStr)),
-- case lists:member(Tok, [prod, major, minor, minimum, os, full]) of
-+ case lists:member(Tok, [none, prod, major, minor, minimum, os, full]) of
- true ->
- {ok,[], {server_tokens, Tok}};
- false ->
-@@ -850,6 +850,8 @@ server(full = _ServerTokens) ->
- OS = os_info(full),
- lists:flatten(
- io_lib:format("~s ~s OTP/~s", [?SERVER_SOFTWARE, OS, OTPRelease]));
-+server(none = _ServerTokens) ->
-+ "";
- server({private, Server} = _ServerTokens) when is_list(Server) ->
- %% The user provide its own
- Server;
-@@ -1299,7 +1301,7 @@ ssl_ca_certificate_file(ConfigDB) ->
- end.
-
- plain_server_tokens() ->
-- [prod, major, minor, minimum, os, full].
-+ [none, prod, major, minor, minimum, os, full].
-
- error_report(Where,M,F,Error) ->
- error_logger:error_report([{?MODULE, Where},
-diff --git lib/inets/src/http_server/httpd_response.erl lib/inets/src/http_server/httpd_response.erl
-index 0895729..2fa91d4 100644
---- lib/inets/src/http_server/httpd_response.erl
-+++ lib/inets/src/http_server/httpd_response.erl
-@@ -287,8 +287,11 @@ create_header(ConfigDb, KeyValueTupleHeaders) ->
- ContentType = "text/html",
- Server = server(ConfigDb),
- NewHeaders = add_default_headers([{"date", Date},
-- {"content-type", ContentType},
-- {"server", Server}],
-+ {"content-type", ContentType}
-+ | if Server=="" -> [];
-+ true -> [{"server", Server}]
-+ end
-+ ],
- KeyValueTupleHeaders),
- lists:map(fun fix_header/1, NewHeaders).
-
-diff --git lib/inets/vsn.mk lib/inets/vsn.mk
-index e5b63a6..e9ecb26 100644
---- lib/inets/vsn.mk
-+++ lib/inets/vsn.mk
-@@ -18,6 +18,6 @@
- # %CopyrightEnd%
-
- APPLICATION = inets
--INETS_VSN = 5.10.6
-+INETS_VSN = 5.10.7
- PRE_VSN =
- APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
-diff --git lib/ssh/doc/src/notes.xml lib/ssh/doc/src/notes.xml
-index acbf312..41885c6 100644
---- lib/ssh/doc/src/notes.xml
-+++ lib/ssh/doc/src/notes.xml
-@@ -29,6 +29,27 @@
- <file>notes.xml</file>
- </header>
-
-+<section><title>Ssh 3.2.2</title>
-+
-+ <section><title>Improvements and New Features</title>
-+ <list>
-+ <item>
-+ <p>
-+ New option <c>id_string</c> for <c>ssh:daemon</c> and
-+ <c>ssh:connect</c> for limiting banner grabbing attempts.</p>
-+ <p>
-+ The possible values are: <c>{id_string,string()}</c> and
-+ <c>{id_string,random}</c>. The latter will make ssh
-+ generate a random nonsence id-string for each new
-+ connection.</p>
-+ <p>
-+ Own Id: OTP-12659</p>
-+ </item>
-+ </list>
-+ </section>
-+
-+</section>
-+
- <section><title>Ssh 3.2.1</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
-diff --git lib/ssh/doc/src/ssh.xml lib/ssh/doc/src/ssh.xml
-index 0e7e384..72dafc0 100644
---- lib/ssh/doc/src/ssh.xml
-+++ lib/ssh/doc/src/ssh.xml
-@@ -180,6 +180,15 @@
- <item>
- <p>If true, the client will not print out anything on authorization.</p>
- </item>
-+
-+ <tag><c><![CDATA[{id_string, random | string()}]]></c></tag>
-+ <item>
-+ <p>The string that the client presents to a connected server initially. The default value is "Erlang/VSN" where VSN is the ssh application version number.
-+ </p>
-+ <p>The value <c>random</c> will cause a random string to be created at each connection attempt. This is to make it a bit more difficult for a malicious peer to find the ssh software brand and version.
-+ </p>
-+ </item>
-+
- <tag><c><![CDATA[{fd, file_descriptor()}]]></c></tag>
- <item>
- <p>Allow an existing file descriptor to be used
-@@ -344,6 +353,14 @@
- </p>
- </item>
-
-+ <tag><c><![CDATA[{id_string, random | string()}]]></c></tag>
-+ <item>
-+ <p>The string the daemon will present to a connecting peer initially. The default value is "Erlang/VSN" where VSN is the ssh application version number.
-+ </p>
-+ <p>The value <c>random</c> will cause a random string to be created at each connection attempt. This is to make it a bit more difficult for a malicious peer to find the ssh software brand and version.
-+ </p>
-+ </item>
-+
- <tag><c><![CDATA[{key_cb, atom()}]]></c></tag>
- <item>
- <p>Module implementing the behaviour <seealso marker="ssh_server_key_api">ssh_server_key_api</seealso>.
-diff --git lib/ssh/src/ssh.erl lib/ssh/src/ssh.erl
-index 51ad691..d4b02a0 100644
---- lib/ssh/src/ssh.erl
-+++ lib/ssh/src/ssh.erl
-@@ -347,6 +347,8 @@ handle_option([parallel_login|Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option({parallel_login,true}) | SshOptions]);
- handle_option([{minimal_remote_max_packet_size, _} = Opt|Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-+handle_option([{id_string, _ID} = Opt|Rest], SocketOptions, SshOptions) ->
-+ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
- handle_option([Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, [handle_inet_option(Opt) | SocketOptions], SshOptions).
-
-@@ -439,6 +441,10 @@ handle_ssh_option({idle_time, Value} = Opt) when is_integer(Value), Value > 0 ->
- Opt;
- handle_ssh_option({rekey_limit, Value} = Opt) when is_integer(Value) ->
- Opt;
-+handle_ssh_option({id_string, random}) ->
-+ {id_string, {random,2,5}}; %% 2 - 5 random characters
-+handle_ssh_option({id_string, ID} = Opt) when is_list(ID) ->
-+ Opt;
- handle_ssh_option(Opt) ->
- throw({error, {eoptions, Opt}}).
-
-diff --git lib/ssh/src/ssh_transport.erl lib/ssh/src/ssh_transport.erl
-index 76fa776..8669be5 100644
---- lib/ssh/src/ssh_transport.erl
-+++ lib/ssh/src/ssh_transport.erl
-@@ -44,12 +44,34 @@
-
- versions(client, Options)->
- Vsn = proplists:get_value(vsn, Options, ?DEFAULT_CLIENT_VERSION),
-- Version = format_version(Vsn),
-- {Vsn, Version};
-+ {Vsn, format_version(Vsn, software_version(Options))};
- versions(server, Options) ->
- Vsn = proplists:get_value(vsn, Options, ?DEFAULT_SERVER_VERSION),
-- Version = format_version(Vsn),
-- {Vsn, Version}.
-+ {Vsn, format_version(Vsn, software_version(Options))}.
-+
-+software_version(Options) ->
-+ case proplists:get_value(id_string, Options) of
-+ undefined ->
-+ "Erlang"++ssh_vsn();
-+ {random,Nlo,Nup} ->
-+ random_id(Nlo,Nup);
-+ ID ->
-+ ID
-+ end.
-+
-+ssh_vsn() ->
-+ try {ok,L} = application:get_all_key(ssh),
-+ proplists:get_value(vsn,L,"")
-+ of
-+ "" -> "";
-+ VSN when is_list(VSN) -> "/" ++ VSN;
-+ _ -> ""
-+ catch
-+ _:_ -> ""
-+ end.
-+
-+random_id(Nlo, Nup) ->
-+ [crypto:rand_uniform($a,$z+1) || _<- lists:duplicate(crypto:rand_uniform(Nlo,Nup+1),x) ].
-
- hello_version_msg(Data) ->
- [Data,"\r\n"].
-@@ -77,9 +99,9 @@ is_valid_mac(Mac, Data, #ssh{recv_mac = Algorithm,
- yes_no(Ssh, Prompt) ->
- (Ssh#ssh.io_cb):yes_no(Prompt, Ssh).
-
--format_version({Major,Minor}) ->
-+format_version({Major,Minor}, SoftwareVersion) ->
- "SSH-" ++ integer_to_list(Major) ++ "." ++
-- integer_to_list(Minor) ++ "-Erlang".
-+ integer_to_list(Minor) ++ "-" ++ SoftwareVersion.
-
- handle_hello_version(Version) ->
- try
-diff --git lib/ssh/test/ssh_basic_SUITE.erl lib/ssh/test/ssh_basic_SUITE.erl
-index 81c7b5c..f5f8991 100644
---- lib/ssh/test/ssh_basic_SUITE.erl
-+++ lib/ssh/test/ssh_basic_SUITE.erl
-@@ -52,6 +52,12 @@ all() ->
- ssh_connect_arg4_timeout,
- packet_size_zero,
- ssh_daemon_minimal_remote_max_packet_size_option,
-+ id_string_no_opt_client,
-+ id_string_own_string_client,
-+ id_string_random_client,
-+ id_string_no_opt_server,
-+ id_string_own_string_server,
-+ id_string_random_server,
- {group, hardening_tests}
- ].
-
-@@ -817,6 +823,66 @@ ssh_daemon_minimal_remote_max_packet_size_option(Config) ->
- ssh:stop_daemon(Server).
-
- %%--------------------------------------------------------------------
-+id_string_no_opt_client(Config) ->
-+ {Server, Host, Port} = fake_daemon(Config),
-+ {error,_} = ssh:connect(Host, Port, []),
-+ receive
-+ {id,Server,"SSH-2.0-Erlang/"++Vsn} ->
-+ true = expected_ssh_vsn(Vsn);
-+ {id,Server,Other} ->
-+ ct:fail("Unexpected id: ~s.",[Other])
-+ end.
-+
-+%%--------------------------------------------------------------------
-+id_string_own_string_client(Config) ->
-+ {Server, Host, Port} = fake_daemon(Config),
-+ {error,_} = ssh:connect(Host, Port, [{id_string,"Pelle"}]),
-+ receive
-+ {id,Server,"SSH-2.0-Pelle\r\n"} ->
-+ ok;
-+ {id,Server,Other} ->
-+ ct:fail("Unexpected id: ~s.",[Other])
-+ end.
-+
-+%%--------------------------------------------------------------------
-+id_string_random_client(Config) ->
-+ {Server, Host, Port} = fake_daemon(Config),
-+ {error,_} = ssh:connect(Host, Port, [{id_string,random}]),
-+ receive
-+ {id,Server,Id="SSH-2.0-Erlang"++_} ->
-+ ct:fail("Unexpected id: ~s.",[Id]);
-+ {id,Server,Rnd="SSH-2.0-"++_} ->
-+ ct:log("Got ~s.",[Rnd]);
-+ {id,Server,Id} ->
-+ ct:fail("Unexpected id: ~s.",[Id])
-+ end.
-+
-+%%--------------------------------------------------------------------
-+id_string_no_opt_server(Config) ->
-+ {_Server, Host, Port} = std_daemon(Config, []),
-+ {ok,S1}=gen_tcp:connect(Host,Port,[{active,false}]),
-+ {ok,"SSH-2.0-Erlang/"++Vsn} = gen_tcp:recv(S1, 0, 2000),
-+ true = expected_ssh_vsn(Vsn).
-+
-+%%--------------------------------------------------------------------
-+id_string_own_string_server(Config) ->
-+ {_Server, Host, Port} = std_daemon(Config, [{id_string,"Olle"}]),
-+ {ok,S1}=gen_tcp:connect(Host,Port,[{active,false}]),
-+ {ok,"SSH-2.0-Olle\r\n"} = gen_tcp:recv(S1, 0, 2000).
-+
-+%%--------------------------------------------------------------------
-+id_string_random_server(Config) ->
-+ {_Server, Host, Port} = std_daemon(Config, [{id_string,random}]),
-+ {ok,S1}=gen_tcp:connect(Host,Port,[{active,false}]),
-+ {ok,"SSH-2.0-"++Rnd} = gen_tcp:recv(S1, 0, 2000),
-+ case Rnd of
-+ "Erlang"++_ -> ct:log("Id=~p",[Rnd]),
-+ {fail,got_default_id};
-+ "Olle\r\n" -> {fail,got_previous_tests_value};
-+ _ -> ct:log("Got ~s.",[Rnd])
-+ end.
-+
-+%%--------------------------------------------------------------------
- ssh_connect_negtimeout_parallel(Config) -> ssh_connect_negtimeout(Config,true).
- ssh_connect_negtimeout_sequential(Config) -> ssh_connect_negtimeout(Config,false).
-
-@@ -1095,3 +1161,46 @@ do_shell(IO, Shell) ->
- %% {'EXIT', Shell, killed} ->
- %% ok
- %% end.
-+
-+
-+std_daemon(Config, ExtraOpts) ->
-+ SystemDir = ?config(data_dir, 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),
-+ {_Server, _Host, _Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
-+ {user_dir, UserDir},
-+ {failfun, fun ssh_test_lib:failfun/2} | ExtraOpts]).
-+
-+expected_ssh_vsn(Str) ->
-+ try
-+ {ok,L} = application:get_all_key(ssh),
-+ proplists:get_value(vsn,L,"")++"\r\n"
-+ of
-+ Str -> true;
-+ "\r\n" -> true;
-+ _ -> false
-+ catch
-+ _:_ -> true %% ssh not started so we dont't know
-+ end.
-+
-+
-+fake_daemon(_Config) ->
-+ Parent = self(),
-+ %% start the server
-+ Server = spawn(fun() ->
-+ {ok,Sl} = gen_tcp:listen(0,[]),
-+ {ok,{Host,Port}} = inet:sockname(Sl),
-+ Parent ! {sockname,self(),Host,Port},
-+ Rsa = gen_tcp:accept(Sl),
-+ ct:log("Server gen_tcp:accept got ~p",[Rsa]),
-+ {ok,S} = Rsa,
-+ receive
-+ {tcp, S, Id} -> Parent ! {id,self(),Id}
-+ end
-+ end),
-+ %% Get listening host and port
-+ receive
-+ {sockname,Server,ServerHost,ServerPort} -> {Server, ServerHost, ServerPort}
-+ end.
-+
-diff --git lib/ssh/vsn.mk lib/ssh/vsn.mk
-index fec8dac..b2b85a7 100644
---- lib/ssh/vsn.mk
-+++ lib/ssh/vsn.mk
-@@ -1,4 +1,4 @@
- #-*-makefile-*- ; force emacs to enter makefile-mode
-
--SSH_VSN = 3.2.1
-+SSH_VSN = 3.2.2
- APP_VSN = "ssh-$(SSH_VSN)"
-diff --git otp_versions.table otp_versions.table
-index a82f535..4bf6cb9 100644
---- otp_versions.table
-+++ otp_versions.table
-@@ -1,3 +1,4 @@
-+OTP-17.5.2 : inets-5.10.7 ssh-3.2.2 # asn1-3.0.4 common_test-1.10 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.1 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
- OTP-17.5.1 : ssh-3.2.1 # asn1-3.0.4 common_test-1.10 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.6 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.1 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
- OTP-17.5 : asn1-3.0.4 common_test-1.10 compiler-5.0.4 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9 eldap-1.1.1 erts-6.4 hipe-3.11.3 inets-5.10.6 kernel-3.2 mnesia-4.12.5 observer-2.0.4 os_mon-2.3.1 public_key-0.23 runtime_tools-1.8.16 ssh-3.2 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8 tools-2.7.2 wx-1.3.3 # cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 edoc-0.7.16 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 ic-4.3.6 jinterface-1.5.12 megaco-3.17.3 odbc-2.10.22 orber-3.7.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 reltool-0.6.6 sasl-2.4.1 snmp-5.1.1 typer-0.9.8 webtool-0.8.10 xmerl-1.3.7 :
- OTP-17.4.1 : erts-6.3.1 inets-5.10.5 # asn1-3.0.3 common_test-1.9 compiler-5.0.3 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.4.2 debugger-4.0.2 dialyzer-2.7.3 diameter-1.8 edoc-0.7.16 eldap-1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.2 ic-4.3.6 jinterface-1.5.12 kernel-3.1 megaco-3.17.3 mnesia-4.12.4 observer-2.0.3 odbc-2.10.22 orber-3.7.1 os_mon-2.3 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.22.1 reltool-0.6.6 runtime_tools-1.8.15 sasl-2.4.1 snmp-5.1.1 ssh-3.1 ssl-5.3.8 stdlib-2.3 syntax_tools-1.6.17 test_server-3.7.2 tools-2.7.1 typer-0.9.8 webtool-0.8.10 wx-1.3.2 xmerl-1.3.7 :
diff --git a/lang/erlang-runtime17/files/patch-otp-17.5.3 b/lang/erlang-runtime17/files/patch-otp-17.5.3
deleted file mode 100644
index f9ed64007fd2..000000000000
--- a/lang/erlang-runtime17/files/patch-otp-17.5.3
+++ /dev/null
@@ -1,3738 +0,0 @@
-diff --git OTP_VERSION OTP_VERSION
-index 808ab16..f32d20d 100644
---- OTP_VERSION
-+++ OTP_VERSION
-@@ -1 +1 @@
--17.5.2
-+17.5.3
-diff --git erts/doc/src/notes.xml erts/doc/src/notes.xml
-index a2b4ae4..35e6e55 100644
---- erts/doc/src/notes.xml
-+++ erts/doc/src/notes.xml
-@@ -30,6 +30,22 @@
- </header>
- <p>This document describes the changes made to the ERTS application.</p>
-
-+<section><title>Erts 6.4.1</title>
-+
-+ <section><title>Fixed Bugs and Malfunctions</title>
-+ <list>
-+ <item>
-+ <p>
-+ The VTS mode in Common Test has been modified to use a
-+ private version of the Webtool application (ct_webtool).</p>
-+ <p>
-+ Own Id: OTP-12704 Aux Id: OTP-10922 </p>
-+ </item>
-+ </list>
-+ </section>
-+
-+</section>
-+
- <section><title>Erts 6.4</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
-diff --git erts/etc/common/ct_run.c erts/etc/common/ct_run.c
-index bb59b93..9e67b94 100644
---- erts/etc/common/ct_run.c
-+++ erts/etc/common/ct_run.c
-@@ -239,7 +239,7 @@ int main(int argc, char** argv)
- */
-
- if (ct_mode == VTS_MODE) {
-- PUSH4("-s", "webtool", "script_start", "vts");
-+ PUSH4("-s", "ct_webtool", "script_start", "vts");
- if (browser[0] != '\0') PUSH(browser);
- PUSH3("-s", "ct_run", "script_start");
- }
-diff --git erts/vsn.mk erts/vsn.mk
-index abc9c0b..9e5aa99 100644
---- erts/vsn.mk
-+++ erts/vsn.mk
-@@ -17,7 +17,7 @@
- # %CopyrightEnd%
- #
-
--VSN = 6.4
-+VSN = 6.4.1
-
- # Port number 4365 in 4.2
- # Port number 4366 in 4.3
-diff --git lib/common_test/doc/src/notes.xml lib/common_test/doc/src/notes.xml
-index 822ebf1..472e3b7 100644
---- lib/common_test/doc/src/notes.xml
-+++ lib/common_test/doc/src/notes.xml
-@@ -32,6 +32,66 @@
- <file>notes.xml</file>
- </header>
-
-+<section><title>Common_Test 1.10.1</title>
-+
-+ <section><title>Fixed Bugs and Malfunctions</title>
-+ <list>
-+ <item>
-+ <p>
-+ A fault in the Common Test logger process, that caused
-+ the application to crash when running on a long name
-+ node, has been corrected.</p>
-+ <p>
-+ Own Id: OTP-12643</p>
-+ </item>
-+ <item>
-+ <p>
-+ A 'wait_for_prompt' option in ct_telnet:expect/3 has been
-+ introduced which forces the function to not return until
-+ a prompt string has been received, even if other expect
-+ patterns have already been found.</p>
-+ <p>
-+ Own Id: OTP-12688 Aux Id: seq12818 </p>
-+ </item>
-+ <item>
-+ <p>
-+ If the last expression in a test case causes a timetrap
-+ timeout, the stack trace is ignored and not printed to
-+ the test case log file. This happens because the
-+ {Suite,TestCase,Line} info is not available in the stack
-+ trace in this scenario, due to tail call elimination.
-+ Common Test has been modified to handle this situation by
-+ inserting a {Suite,TestCase,last_expr} tuple in the
-+ correct place and printing the stack trace as expected.</p>
-+ <p>
-+ Own Id: OTP-12697 Aux Id: seq12848 </p>
-+ </item>
-+ <item>
-+ <p>
-+ Fixed a buffer problem in ct_netconfc which could cause
-+ that some messages where buffered forever.</p>
-+ <p>
-+ Own Id: OTP-12698 Aux Id: seq12844 </p>
-+ </item>
-+ <item>
-+ <p>
-+ The VTS mode in Common Test has been modified to use a
-+ private version of the Webtool application (ct_webtool).</p>
-+ <p>
-+ Own Id: OTP-12704 Aux Id: OTP-10922 </p>
-+ </item>
-+ <item>
-+ <p>
-+ Add possibility to add user capabilities in
-+ <c>ct_netconfc:hello/3</c>.</p>
-+ <p>
-+ Own Id: OTP-12707 Aux Id: seq12846 </p>
-+ </item>
-+ </list>
-+ </section>
-+
-+</section>
-+
- <section><title>Common_Test 1.10</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
-diff --git lib/common_test/src/Makefile lib/common_test/src/Makefile
-index 8d74546..449cba6 100644
---- lib/common_test/src/Makefile
-+++ lib/common_test/src/Makefile
-@@ -62,6 +62,8 @@ MODULES= \
- ct_telnet_client \
- ct_make \
- vts \
-+ ct_webtool \
-+ ct_webtool_sup \
- unix_telnet \
- ct_config \
- ct_config_plain \
-diff --git lib/common_test/src/ct_logs.erl lib/common_test/src/ct_logs.erl
-index dc118ed..fa55a97 100644
---- lib/common_test/src/ct_logs.erl
-+++ lib/common_test/src/ct_logs.erl
-@@ -1908,13 +1908,14 @@ sort_all_runs(Dirs) ->
- sort_ct_runs(Dirs) ->
- %% Directory naming: <Prefix>.NodeName.Date_Time[/...]
- %% Sort on Date_Time string: "YYYY-MM-DD_HH.MM.SS"
-- lists:sort(fun(Dir1,Dir2) ->
-- [_Prefix,_Node1,DateHH1,MM1,SS1] =
-- string:tokens(filename:dirname(Dir1),[$.]),
-- [_Prefix,_Node2,DateHH2,MM2,SS2] =
-- string:tokens(filename:dirname(Dir2),[$.]),
-- {DateHH1,MM1,SS1} =< {DateHH2,MM2,SS2}
-- end, Dirs).
-+ lists:sort(
-+ fun(Dir1,Dir2) ->
-+ [SS1,MM1,DateHH1 | _] =
-+ lists:reverse(string:tokens(filename:dirname(Dir1),[$.])),
-+ [SS2,MM2,DateHH2 | _] =
-+ lists:reverse(string:tokens(filename:dirname(Dir2),[$.])),
-+ {DateHH1,MM1,SS1} =< {DateHH2,MM2,SS2}
-+ end, Dirs).
-
- dir_diff_all_runs(Dirs, LogCache) ->
- case LogCache#log_cache.all_runs of
-diff --git lib/common_test/src/ct_netconfc.erl lib/common_test/src/ct_netconfc.erl
-index 85fb1ea..80ffb51 100644
---- lib/common_test/src/ct_netconfc.erl
-+++ lib/common_test/src/ct_netconfc.erl
-@@ -172,6 +172,7 @@
- only_open/2,
- hello/1,
- hello/2,
-+ hello/3,
- close_session/1,
- close_session/2,
- kill_session/2,
-@@ -456,23 +457,35 @@ only_open(KeyOrName, ExtraOpts) ->
-
- %%----------------------------------------------------------------------
- %% @spec hello(Client) -> Result
--%% @equiv hello(Client, infinity)
-+%% @equiv hello(Client, [], infinity)
- hello(Client) ->
-- hello(Client,?DEFAULT_TIMEOUT).
-+ hello(Client,[],?DEFAULT_TIMEOUT).
-
- %%----------------------------------------------------------------------
- -spec hello(Client,Timeout) -> Result when
- Client :: handle(),
- Timeout :: timeout(),
- Result :: ok | {error,error_reason()}.
--%% @doc Exchange `hello' messages with the server.
--%%
--%% Sends a `hello' message to the server and waits for the return.
--%%
--%% @end
--%%----------------------------------------------------------------------
-+%% @spec hello(Client, Timeout) -> Result
-+%% @equiv hello(Client, [], Timeout)
- hello(Client,Timeout) ->
-- call(Client, {hello, Timeout}).
-+ hello(Client,[],Timeout).
-+
-+%%----------------------------------------------------------------------
-+-spec hello(Client,Options,Timeout) -> Result when
-+ Client :: handle(),
-+ Options :: [{capability, [string()]}],
-+ Timeout :: timeout(),
-+ Result :: ok | {error,error_reason()}.
-+%% @doc Exchange `hello' messages with the server.
-+%%
-+%% Adds optional capabilities and sends a `hello' message to the
-+%% server and waits for the return.
-+%% @end
-+%%----------------------------------------------------------------------
-+hello(Client,Options,Timeout) ->
-+ call(Client, {hello, Options, Timeout}).
-+
-
- %%----------------------------------------------------------------------
- %% @spec get_session_id(Client) -> Result
-@@ -1040,9 +1053,9 @@ terminate(_, #state{connection=Connection}) ->
- ok.
-
- %% @private
--handle_msg({hello,Timeout}, From,
-+handle_msg({hello, Options, Timeout}, From,
- #state{connection=Connection,hello_status=HelloStatus} = State) ->
-- case do_send(Connection, client_hello()) of
-+ case do_send(Connection, client_hello(Options)) of
- ok ->
- case HelloStatus of
- undefined ->
-@@ -1118,7 +1131,9 @@ handle_msg({Ref,timeout},#state{pending=Pending} = State) ->
- close_session -> stop;
- _ -> noreply
- end,
-- {R,State#state{pending=Pending1}}.
-+ %% Halfhearted try to get in correct state, this matches
-+ %% the implementation before this patch
-+ {R,State#state{pending=Pending1, buff= <<>>}}.
-
- %% @private
- %% Called by ct_util_server to close registered connections before terminate.
-@@ -1222,10 +1237,14 @@ set_request_timer(T) ->
-
-
- %%%-----------------------------------------------------------------
--client_hello() ->
-+client_hello(Options) when is_list(Options) ->
-+ UserCaps = [{capability, UserCap} ||
-+ {capability, UserCap} <- Options,
-+ is_list(hd(UserCap))],
- {hello, ?NETCONF_NAMESPACE_ATTR,
- [{capabilities,
-- [{capability,[?NETCONF_BASE_CAP++?NETCONF_BASE_CAP_VSN]}]}]}.
-+ [{capability,[?NETCONF_BASE_CAP++?NETCONF_BASE_CAP_VSN]}|
-+ UserCaps]}]}.
-
- %%%-----------------------------------------------------------------
-
-@@ -1308,72 +1327,54 @@ to_xml_doc(Simple) ->
-
- %%%-----------------------------------------------------------------
- %%% Parse and handle received XML data
--handle_data(NewData,#state{connection=Connection,buff=Buff} = State) ->
-+handle_data(NewData,#state{connection=Connection,buff=Buff0} = State0) ->
- log(Connection,recv,NewData),
-- Data = <<Buff/binary,NewData/binary>>,
-- case xmerl_sax_parser:stream(<<>>,
-- [{continuation_fun,fun sax_cont/1},
-- {continuation_state,{Data,Connection,false}},
-- {event_fun,fun sax_event/3},
-- {event_state,[]}]) of
-- {ok, Simple, Rest} ->
-- decode(Simple,State#state{buff=Rest});
-- {fatal_error,_Loc,Reason,_EndTags,_EventState} ->
-- ?error(Connection#connection.name,[{parse_error,Reason},
-- {buffer,Buff},
-- {new_data,NewData}]),
-- case Reason of
-- {could_not_fetch_data,Msg} ->
-- handle_msg(Msg,State#state{buff = <<>>});
-- _Other ->
-- Pending1 =
-- case State#state.pending of
-- [] ->
-- [];
-- Pending ->
-- %% Assuming the first request gets the
-- %% first answer
-- P=#pending{tref=TRef,caller=Caller} =
-- lists:last(Pending),
-- _ = timer:cancel(TRef),
-- Reason1 = {failed_to_parse_received_data,Reason},
-- ct_gen_conn:return(Caller,{error,Reason1}),
-- lists:delete(P,Pending)
-- end,
-- {noreply,State#state{pending=Pending1,buff = <<>>}}
-- end
-- end.
--
--%%%-----------------------------------------------------------------
--%%% Parsing of XML data
--%% Contiuation function for the sax parser
--sax_cont(done) ->
-- {<<>>,done};
--sax_cont({Data,Connection,false}) ->
-+ Data = append_wo_initial_nl(Buff0,NewData),
- case binary:split(Data,[?END_TAG],[]) of
-- [All] ->
-- %% No end tag found. Remove what could be a part
-- %% of an end tag from the data and save for next
-- %% iteration
-- SafeSize = size(All)-5,
-- <<New:SafeSize/binary,Save:5/binary>> = All,
-- {New,{Save,Connection,true}};
-- [_Msg,_Rest]=Msgs ->
-- %% We have at least one full message. Any excess data will
-- %% be returned from xmerl_sax_parser:stream/2 in the Rest
-- %% parameter.
-- {list_to_binary(Msgs),done}
-- end;
--sax_cont({Data,Connection,true}) ->
-- case ssh_receive_data() of
-- {ok,Bin} ->
-- log(Connection,recv,Bin),
-- sax_cont({<<Data/binary,Bin/binary>>,Connection,false});
-- {error,Reason} ->
-- throw({could_not_fetch_data,Reason})
-+ [_NoEndTagFound] ->
-+ {noreply, State0#state{buff=Data}};
-+ [FirstMsg,Buff1] ->
-+ SaxArgs = [{event_fun,fun sax_event/3}, {event_state,[]}],
-+ case xmerl_sax_parser:stream(FirstMsg, SaxArgs) of
-+ {ok, Simple, _Thrash} ->
-+ case decode(Simple, State0#state{buff=Buff1}) of
-+ {noreply, #state{buff=Buff} = State} when Buff =/= <<>> ->
-+ %% Recurse if we have more data in buffer
-+ handle_data(<<>>, State);
-+ Other ->
-+ Other
-+ end;
-+ {fatal_error,_Loc,Reason,_EndTags,_EventState} ->
-+ ?error(Connection#connection.name,
-+ [{parse_error,Reason},
-+ {buffer, Buff0},
-+ {new_data,NewData}]),
-+ handle_error(Reason, State0#state{buff= <<>>})
-+ end
- end.
-
-+%% xml does not accept a leading nl and some netconf server add a nl after
-+%% each ?END_TAG, ignore them
-+append_wo_initial_nl(<<>>,NewData) -> NewData;
-+append_wo_initial_nl(<<"\n", Data/binary>>, NewData) ->
-+ append_wo_initial_nl(Data, NewData);
-+append_wo_initial_nl(Data, NewData) ->
-+ <<Data/binary, NewData/binary>>.
-
-+handle_error(Reason, State) ->
-+ Pending1 = case State#state.pending of
-+ [] -> [];
-+ Pending ->
-+ %% Assuming the first request gets the
-+ %% first answer
-+ P=#pending{tref=TRef,caller=Caller} =
-+ lists:last(Pending),
-+ _ = timer:cancel(TRef),
-+ Reason1 = {failed_to_parse_received_data,Reason},
-+ ct_gen_conn:return(Caller,{error,Reason1}),
-+ lists:delete(P,Pending)
-+ end,
-+ {noreply, State#state{pending=Pending1}}.
-
- %% Event function for the sax parser. It builds a simple XML structure.
- %% Care is taken to keep namespace attributes and prefixes as in the original XML.
-@@ -1836,16 +1837,6 @@ get_tag([]) ->
-
- %%%-----------------------------------------------------------------
- %%% SSH stuff
--ssh_receive_data() ->
-- receive
-- {ssh_cm, CM, {data, Ch, _Type, Data}} ->
-- ssh_connection:adjust_window(CM,Ch,size(Data)),
-- {ok, Data};
-- {ssh_cm, _CM, {Closed, _Ch}} = X when Closed == closed; Closed == eof ->
-- {error,X};
-- {_Ref,timeout} = X ->
-- {error,X}
-- end.
-
- ssh_open(#options{host=Host,timeout=Timeout,port=Port,ssh=SshOpts,name=Name}) ->
- case ssh:connect(Host, Port,
-diff --git lib/common_test/src/ct_run.erl lib/common_test/src/ct_run.erl
-index 4a12481..be547b4 100644
---- lib/common_test/src/ct_run.erl
-+++ lib/common_test/src/ct_run.erl
-@@ -225,18 +225,24 @@ finish(Tracing, ExitStatus, Args) ->
- if ExitStatus == interactive_mode ->
- interactive_mode;
- true ->
-- %% it's possible to tell CT to finish execution with a call
-- %% to a different function than the normal halt/1 BIF
-- %% (meant to be used mainly for reading the CT exit status)
-- case get_start_opt(halt_with,
-- fun([HaltMod,HaltFunc]) ->
-- {list_to_atom(HaltMod),
-- list_to_atom(HaltFunc)} end,
-- Args) of
-- undefined ->
-- halt(ExitStatus);
-- {M,F} ->
-- apply(M, F, [ExitStatus])
-+ case get_start_opt(vts, true, Args) of
-+ true ->
-+ %% VTS mode, don't halt the node
-+ ok;
-+ _ ->
-+ %% it's possible to tell CT to finish execution with a call
-+ %% to a different function than the normal halt/1 BIF
-+ %% (meant to be used mainly for reading the CT exit status)
-+ case get_start_opt(halt_with,
-+ fun([HaltMod,HaltFunc]) ->
-+ {list_to_atom(HaltMod),
-+ list_to_atom(HaltFunc)} end,
-+ Args) of
-+ undefined ->
-+ halt(ExitStatus);
-+ {M,F} ->
-+ apply(M, F, [ExitStatus])
-+ end
- end
- end.
-
-@@ -244,7 +250,7 @@ script_start1(Parent, Args) ->
- %% read general start flags
- Label = get_start_opt(label, fun([Lbl]) -> Lbl end, Args),
- Profile = get_start_opt(profile, fun([Prof]) -> Prof end, Args),
-- Vts = get_start_opt(vts, true, Args),
-+ Vts = get_start_opt(vts, true, undefined, Args),
- Shell = get_start_opt(shell, true, Args),
- Cover = get_start_opt(cover, fun([CoverFile]) -> ?abs(CoverFile) end, Args),
- CoverStop = get_start_opt(cover_stop,
-@@ -330,8 +336,8 @@ script_start1(Parent, Args) ->
- Stylesheet = get_start_opt(stylesheet,
- fun([SS]) -> ?abs(SS) end, Args),
- %% basic_html - used by ct_logs
-- BasicHtml = case proplists:get_value(basic_html, Args) of
-- undefined ->
-+ BasicHtml = case {Vts,proplists:get_value(basic_html, Args)} of
-+ {undefined,undefined} ->
- application:set_env(common_test, basic_html, false),
- undefined;
- _ ->
-@@ -364,9 +370,10 @@ script_start1(Parent, Args) ->
- scale_timetraps = ScaleTT,
- create_priv_dir = CreatePrivDir,
- starter = script},
--
-+
- %% check if log files should be refreshed or go on to run tests...
- Result = run_or_refresh(Opts, Args),
-+
- %% send final results to starting process waiting in script_start/0
- Parent ! {self(), Result}.
-
-@@ -757,21 +764,6 @@ script_start4(Opts = #opts{tests = Tests}, Args) ->
- %%% @doc Print usage information for <code>ct_run</code>.
- script_usage() ->
- io:format("\n\nUsage:\n\n"),
-- io:format("Run tests in web based GUI:\n\n"
-- "\tct_run -vts [-browser Browser]"
-- "\n\t[-config ConfigFile1 ConfigFile2 .. ConfigFileN]"
-- "\n\t[-decrypt_key Key] | [-decrypt_file KeyFile]"
-- "\n\t[-dir TestDir1 TestDir2 .. TestDirN] |"
-- "\n\t[-suite Suite [-case Case]]"
-- "\n\t[-logopts LogOpt1 LogOpt2 .. LogOptN]"
-- "\n\t[-verbosity GenVLvl | [CategoryVLvl1 .. CategoryVLvlN]]"
-- "\n\t[-include InclDir1 InclDir2 .. InclDirN]"
-- "\n\t[-no_auto_compile]"
-- "\n\t[-abort_if_missing_suites]"
-- "\n\t[-multiply_timetraps N]"
-- "\n\t[-scale_timetraps]"
-- "\n\t[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]"
-- "\n\t[-basic_html]\n\n"),
- io:format("Run tests from command line:\n\n"
- "\tct_run [-dir TestDir1 TestDir2 .. TestDirN] |"
- "\n\t[[-dir TestDir] -suite Suite1 Suite2 .. SuiteN"
-@@ -831,7 +823,22 @@ script_usage() ->
- io:format("Run CT in interactive mode:\n\n"
- "\tct_run -shell"
- "\n\t[-config ConfigFile1 ConfigFile2 .. ConfigFileN]"
-- "\n\t[-decrypt_key Key] | [-decrypt_file KeyFile]\n\n").
-+ "\n\t[-decrypt_key Key] | [-decrypt_file KeyFile]\n\n"),
-+ io:format("Run tests in web based GUI:\n\n"
-+ "\tct_run -vts [-browser Browser]"
-+ "\n\t[-config ConfigFile1 ConfigFile2 .. ConfigFileN]"
-+ "\n\t[-decrypt_key Key] | [-decrypt_file KeyFile]"
-+ "\n\t[-dir TestDir1 TestDir2 .. TestDirN] |"
-+ "\n\t[-suite Suite [-case Case]]"
-+ "\n\t[-logopts LogOpt1 LogOpt2 .. LogOptN]"
-+ "\n\t[-verbosity GenVLvl | [CategoryVLvl1 .. CategoryVLvlN]]"
-+ "\n\t[-include InclDir1 InclDir2 .. InclDirN]"
-+ "\n\t[-no_auto_compile]"
-+ "\n\t[-abort_if_missing_suites]"
-+ "\n\t[-multiply_timetraps N]"
-+ "\n\t[-scale_timetraps]"
-+ "\n\t[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]"
-+ "\n\t[-basic_html]\n\n").
-
- %%%-----------------------------------------------------------------
- %%% @hidden
-diff --git lib/common_test/src/ct_telnet.erl lib/common_test/src/ct_telnet.erl
-index d906a26..844f537 100644
---- lib/common_test/src/ct_telnet.erl
-+++ lib/common_test/src/ct_telnet.erl
-@@ -486,7 +486,8 @@ expect(Connection,Patterns) ->
- %%% Opts = [Opt]
- %%% Opt = {idle_timeout,IdleTimeout} | {total_timeout,TotalTimeout} |
- %%% repeat | {repeat,N} | sequence | {halt,HaltPatterns} |
--%%% ignore_prompt | no_prompt_check
-+%%% ignore_prompt | no_prompt_check | wait_for_prompt |
-+%%% {wait_for_prompt,Prompt}
- %%% IdleTimeout = infinity | integer()
- %%% TotalTimeout = infinity | integer()
- %%% N = integer()
-@@ -499,9 +500,9 @@ expect(Connection,Patterns) ->
- %%%
- %%% @doc Get data from telnet and wait for the expected pattern.
- %%%
--%%% <p><code>Pattern</code> can be a POSIX regular expression. If more
--%%% than one pattern is given, the function returns when the first
--%%% match is found.</p>
-+%%% <p><code>Pattern</code> can be a POSIX regular expression. The function
-+%%% returns as soon as a pattern has been successfully matched (at least one,
-+%%% in the case of multiple patterns).</p>
- %%%
- %%% <p><code>RxMatch</code> is a list of matched strings. It looks
- %%% like this: <code>[FullMatch, SubMatch1, SubMatch2, ...]</code>
-@@ -524,10 +525,13 @@ expect(Connection,Patterns) ->
- %%% milliseconds, <code>{error,timeout}</code> is returned. The default
- %%% value is <code>infinity</code> (i.e. no time limit).</p>
- %%%
--%%% <p>The function will always return when a prompt is found, unless
--%%% any of the <code>ignore_prompt</code> or
--%%% <code>no_prompt_check</code> options are used, in which case it
--%%% will return when a match is found or after a timeout.</p>
-+%%% <p>The function will return when a prompt is received, even if no
-+%%% pattern has yet been matched. In this event,
-+%%% <code>{error,{prompt,Prompt}}</code> is returned.
-+%%% However, this behaviour may be modified with the
-+%%% <code>ignore_prompt</code> or <code>no_prompt_check</code> option, which
-+%%% tells <code>expect</code> to return only when a match is found or after a
-+%%% timeout.</p>
- %%%
- %%% <p>If the <code>ignore_prompt</code> option is used,
- %%% <code>ct_telnet</code> will ignore any prompt found. This option
-@@ -541,6 +545,13 @@ expect(Connection,Patterns) ->
- %%% is useful if, for instance, the <code>Pattern</code> itself
- %%% matches the prompt.</p>
- %%%
-+%%% <p>The <code>wait_for_prompt</code> option forces <code>ct_telnet</code>
-+%%% to wait until the prompt string has been received before returning
-+%%% (even if a pattern has already been matched). This is equal to calling:
-+%%% <code>expect(Conn, Patterns++[{prompt,Prompt}], [sequence|Opts])</code>.
-+%%% Note that <code>idle_timeout</code> and <code>total_timeout</code>
-+%%% may abort the operation of waiting for prompt.</p>
-+%%%
- %%% <p>The <code>repeat</code> option indicates that the pattern(s)
- %%% shall be matched multiple times. If <code>N</code> is given, the
- %%% pattern(s) will be matched <code>N</code> times, and the function
-@@ -653,18 +664,21 @@ handle_msg({cmd,Cmd,Opts},State) ->
- start_gen_log(heading(cmd,State#state.name)),
- log(State,cmd,"Cmd: ~p",[Cmd]),
-
-+ %% whatever is in the buffer from previous operations
-+ %% will be ignored as we go ahead with this telnet cmd
-+
- debug_cont_gen_log("Throwing Buffer:",[]),
- debug_log_lines(State#state.buffer),
-
- case {State#state.type,State#state.prompt} of
-- {ts,_} ->
-+ {ts,_} ->
- silent_teln_expect(State#state.name,
- State#state.teln_pid,
- State#state.buffer,
- prompt,
- State#state.prx,
- [{idle_timeout,2000}]);
-- {ip,false} ->
-+ {ip,false} ->
- silent_teln_expect(State#state.name,
- State#state.teln_pid,
- State#state.buffer,
-@@ -1029,10 +1043,12 @@ teln_expect(Name,Pid,Data,Pattern0,Prx,Opts) ->
- end,
-
- PromptCheck = get_prompt_check(Opts),
-- Seq = get_seq(Opts),
-- Pattern = convert_pattern(Pattern0,Seq),
-
-- {IdleTimeout,TotalTimeout} = get_timeouts(Opts),
-+ {WaitForPrompt,Pattern1,Opts1} = wait_for_prompt(Pattern0,Opts),
-+
-+ Seq = get_seq(Opts1),
-+ Pattern2 = convert_pattern(Pattern1,Seq),
-+ {IdleTimeout,TotalTimeout} = get_timeouts(Opts1),
-
- EO = #eo{teln_pid=Pid,
- prx=Prx,
-@@ -1042,9 +1058,16 @@ teln_expect(Name,Pid,Data,Pattern0,Prx,Opts) ->
- haltpatterns=HaltPatterns,
- prompt_check=PromptCheck},
-
-- case get_repeat(Opts) of
-+ case get_repeat(Opts1) of
- false ->
-- case teln_expect1(Name,Pid,Data,Pattern,[],EO) of
-+ case teln_expect1(Name,Pid,Data,Pattern2,[],EO) of
-+ {ok,Matched,Rest} when WaitForPrompt ->
-+ case lists:reverse(Matched) of
-+ [{prompt,_},Matched1] ->
-+ {ok,Matched1,Rest};
-+ [{prompt,_}|Matched1] ->
-+ {ok,lists:reverse(Matched1),Rest}
-+ end;
- {ok,Matched,Rest} ->
- {ok,Matched,Rest};
- {halt,Why,Rest} ->
-@@ -1054,7 +1077,7 @@ teln_expect(Name,Pid,Data,Pattern0,Prx,Opts) ->
- end;
- N ->
- EO1 = EO#eo{repeat=N},
-- repeat_expect(Name,Pid,Data,Pattern,[],EO1)
-+ repeat_expect(Name,Pid,Data,Pattern2,[],EO1)
- end.
-
- convert_pattern(Pattern,Seq)
-@@ -1118,6 +1141,40 @@ get_ignore_prompt(Opts) ->
- get_prompt_check(Opts) ->
- not lists:member(no_prompt_check,Opts).
-
-+wait_for_prompt(Pattern, Opts) ->
-+ case lists:member(wait_for_prompt, Opts) of
-+ true ->
-+ wait_for_prompt1(prompt, Pattern,
-+ lists:delete(wait_for_prompt,Opts));
-+ false ->
-+ case proplists:get_value(wait_for_prompt, Opts) of
-+ undefined ->
-+ {false,Pattern,Opts};
-+ PromptStr ->
-+ wait_for_prompt1({prompt,PromptStr}, Pattern,
-+ proplists:delete(wait_for_prompt,Opts))
-+ end
-+ end.
-+
-+wait_for_prompt1(Prompt, [Ch|_] = Pattern, Opts) when is_integer(Ch) ->
-+ wait_for_prompt2(Prompt, [Pattern], Opts);
-+wait_for_prompt1(Prompt, Pattern, Opts) when is_list(Pattern) ->
-+ wait_for_prompt2(Prompt, Pattern, Opts);
-+wait_for_prompt1(Prompt, Pattern, Opts) ->
-+ wait_for_prompt2(Prompt, [Pattern], Opts).
-+
-+wait_for_prompt2(Prompt, Pattern, Opts) ->
-+ Pattern1 = case lists:reverse(Pattern) of
-+ [prompt|_] -> Pattern;
-+ [{prompt,_}|_] -> Pattern;
-+ _ -> Pattern ++ [Prompt]
-+ end,
-+ Opts1 = case lists:member(sequence, Opts) of
-+ true -> Opts;
-+ false -> [sequence|Opts]
-+ end,
-+ {true,Pattern1,Opts1}.
-+
- %% Repeat either single or sequence. All match results are accumulated
- %% and returned when a halt condition is fulllfilled.
- repeat_expect(_Name,_Pid,Rest,_Pattern,Acc,#eo{repeat=0}) ->
-@@ -1210,7 +1267,7 @@ get_data1(Pid) ->
- %% 1) Single expect.
- %% First the whole data chunk is searched for a prompt (to avoid doing
- %% a regexp match for the prompt at each line).
--%% If we are searching for anyting else, the datachunk is split into
-+%% If we are searching for anything else, the datachunk is split into
- %% lines and each line is matched against each pattern.
-
- %% one_expect: split data chunk at prompts
-@@ -1227,7 +1284,7 @@ one_expect(Name,Pid,Data,Pattern,EO) ->
- log(name_or_pid(Name,Pid),"PROMPT: ~ts",[PromptType]),
- {match,{prompt,PromptType},Rest};
- [{prompt,_OtherPromptType}] ->
-- %% Only searching for one specific prompt, not thisone
-+ %% Only searching for one specific prompt, not this one
- log_lines(Name,Pid,UptoPrompt),
- {nomatch,Rest};
- _ ->
-diff --git lib/common_test/src/ct_webtool.erl lib/common_test/src/ct_webtool.erl
-new file mode 100644
-index 0000000..b67a7c2
---- /dev/null
-+++ lib/common_test/src/ct_webtool.erl
-@@ -0,0 +1,1207 @@
-+%%
-+%% %CopyrightBegin%
-+%%
-+%% Copyright Ericsson AB 2001-2010. 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(ct_webtool).
-+-behaviour(gen_server).
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%% %%
-+%% The general idea is: %%
-+%% %%
-+%% %%
-+%% 1. Scan through the path for *.tool files and find all the web %%
-+%% based tools. Query each tool for configuration data. %%
-+%% 2. Add Alias for Erlscript and html for each tool to %%
-+%% the webserver configuration data. %%
-+%% 3. Start the webserver. %%
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+
-+%% API functions
-+-export([start/0, start/2, stop/0]).
-+
-+%% Starting Webtool from a shell script
-+-export([script_start/0, script_start/1]).
-+
-+%% Web api
-+-export([started_tools/2, toolbar/2, start_tools/2, stop_tools/2]).
-+
-+%% API against other tools
-+-export([is_localhost/0]).
-+
-+%% Debug export s
-+-export([get_tools1/1]).
-+-export([debug/1, stop_debug/0, debug_app/1]).
-+
-+%% gen_server callbacks
-+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
-+ terminate/2, code_change/3]).
-+
-+-include_lib("kernel/include/file.hrl").
-+-include_lib("stdlib/include/ms_transform.hrl").
-+
-+-record(state,{priv_dir,app_data,supvis,web_data,started=[]}).
-+
-+-define(MAX_NUMBER_OF_WEBTOOLS,256).
-+-define(DEFAULT_PORT,8888).% must be >1024 or the user must be root on unix
-+-define(DEFAULT_ADDR,{127,0,0,1}).
-+
-+-define(WEBTOOL_ALIAS,{ct_webtool,[{alias,{erl_alias,"/ct_webtool",[ct_webtool]}}]}).
-+-define(HEADER,"Pragma:no-cache\r\n Content-type: text/html\r\n\r\n").
-+-define(HTML_HEADER,"<HTML>\r\n<HEAD>\r\n<TITLE>WebTool</TITLE>\r\n</HEAD>\r\n<BODY BGCOLOR=\"#FFFFFF\">\r\n").
-+-define(HTML_HEADER_RELOAD,"<HTML>\r\n<HEAD>\r\n<TITLE>WebTool
-+ </TITLE>\r\n</HEAD>\r\n
-+ <BODY BGCOLOR=\"#FFFFFF\" onLoad=reloadCompiledList()>\r\n").
-+
-+-define(HTML_END,"</BODY></HTML>").
-+
-+-define(SEND_URL_TIMEOUT,5000).
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%% %%
-+%% For debugging only. %%
-+%% %%
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%% Start tracing with
-+%% debug(Functions).
-+%% Functions = local | global | FunctionList
-+%% FunctionList = [Function]
-+%% Function = {FunctionName,Arity} | FunctionName |
-+%% {Module, FunctionName, Arity} | {Module,FunctionName}
-+debug(F) ->
-+ ttb:tracer(all,[{file,"webtool.trc"}]), % tracing all nodes
-+ ttb:p(all,[call,timestamp]),
-+ MS = [{'_',[],[{return_trace},{message,{caller}}]}],
-+ tp(F,MS),
-+ ttb:ctp(?MODULE,stop_debug), % don't want tracing of the stop_debug func
-+ ok.
-+tp(local,MS) -> % all functions
-+ ttb:tpl(?MODULE,MS);
-+tp(global,MS) -> % all exported functions
-+ ttb:tp(?MODULE,MS);
-+tp([{M,F,A}|T],MS) -> % Other module
-+ ttb:tpl(M,F,A,MS),
-+ tp(T,MS);
-+tp([{M,F}|T],MS) when is_atom(F) -> % Other module
-+ ttb:tpl(M,F,MS),
-+ tp(T,MS);
-+tp([{F,A}|T],MS) -> % function/arity
-+ ttb:tpl(?MODULE,F,A,MS),
-+ tp(T,MS);
-+tp([F|T],MS) -> % function
-+ ttb:tpl(?MODULE,F,MS),
-+ tp(T,MS);
-+tp([],_MS) ->
-+ ok.
-+stop_debug() ->
-+ ttb:stop([format]).
-+
-+debug_app(Mod) ->
-+ ttb:tracer(all,[{file,"webtool_app.trc"},{handler,{fun out/4,true}}]),
-+ ttb:p(all,[call,timestamp]),
-+ MS = [{'_',[],[{return_trace},{message,{caller}}]}],
-+ ttb:tp(Mod,MS),
-+ ok.
-+
-+out(_,{trace_ts,Pid,call,MFA={M,F,A},{W,_,_},TS},_,S)
-+ when W==webtool;W==mod_esi->
-+ io:format("~w: (~p)~ncall ~s~n", [TS,Pid,ffunc(MFA)]),
-+ [{M,F,length(A)}|S];
-+out(_,{trace_ts,Pid,return_from,MFA,R,TS},_,[MFA|S]) ->
-+ io:format("~w: (~p)~nreturned from ~s -> ~p~n", [TS,Pid,ffunc(MFA),R]),
-+ S;
-+out(_,_,_,_) ->
-+ ok.
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%% %%
-+%% Functions called via script. %%
-+%% %%
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+script_start() ->
-+ usage(),
-+ halt().
-+script_start([App]) ->
-+ DefaultBrowser =
-+ case os:type() of
-+ {win32,_} -> iexplore;
-+ _ -> firefox
-+ end,
-+ script_start([App,DefaultBrowser]);
-+script_start([App,Browser]) ->
-+ io:format("Starting webtool...\n"),
-+ start(),
-+ AvailableApps = get_applications(),
-+ {OSType,_} = os:type(),
-+ case lists:keysearch(App,1,AvailableApps) of
-+ {value,{App,StartPage}} ->
-+ io:format("Starting ~w...\n",[App]),
-+ start_tools([],"app=" ++ atom_to_list(App)),
-+ PortStr = integer_to_list(get_port()),
-+ Url = case StartPage of
-+ "/" ++ Page ->
-+ "http://localhost:" ++ PortStr ++ "/" ++ Page;
-+ _ ->
-+ "http://localhost:" ++ PortStr ++ "/" ++ StartPage
-+ end,
-+ case Browser of
-+ none ->
-+ ok;
-+ iexplore when OSType == win32->
-+ io:format("Starting internet explorer...\n"),
-+ {ok,R} = win32reg:open(""),
-+ Key="\\local_machine\\SOFTWARE\\Microsoft\\IE Setup\\Setup",
-+ win32reg:change_key(R,Key),
-+ {ok,Val} = win32reg:value(R,"Path"),
-+ IExplore=filename:join(win32reg:expand(Val),"iexplore.exe"),
-+ os:cmd("\"" ++ IExplore ++ "\" " ++ Url);
-+ _ when OSType == win32 ->
-+ io:format("Starting ~w...\n",[Browser]),
-+ os:cmd("\"" ++ atom_to_list(Browser) ++ "\" " ++ Url);
-+ B when B==firefox; B==mozilla ->
-+ io:format("Sending URL to ~w...",[Browser]),
-+ BStr = atom_to_list(Browser),
-+ SendCmd = BStr ++ " -raise -remote \'openUrl(" ++
-+ Url ++ ")\'",
-+ Port = open_port({spawn,SendCmd},[exit_status]),
-+ receive
-+ {Port,{exit_status,0}} ->
-+ io:format("done\n"),
-+ ok;
-+ {Port,{exit_status,_Error}} ->
-+ io:format(" not running, starting ~w...\n",
-+ [Browser]),
-+ os:cmd(BStr ++ " " ++ Url),
-+ ok
-+ after ?SEND_URL_TIMEOUT ->
-+ io:format(" failed, starting ~w...\n",[Browser]),
-+ erlang:port_close(Port),
-+ os:cmd(BStr ++ " " ++ Url)
-+ end;
-+ _ ->
-+ io:format("Starting ~w...\n",[Browser]),
-+ os:cmd(atom_to_list(Browser) ++ " " ++ Url)
-+ end,
-+ ok;
-+ false ->
-+ stop(),
-+ io:format("\n{error,{unknown_app,~p}}\n",[App]),
-+ halt()
-+ end.
-+
-+usage() ->
-+ io:format("Starting webtool...\n"),
-+ start(),
-+ Apps = lists:map(fun({A,_}) -> A end,get_applications()),
-+ io:format(
-+ "\nUsage: start_webtool application [ browser ]\n"
-+ "\nAvailable applications are: ~p\n"
-+ "Default browser is \'iexplore\' (Internet Explorer) on Windows "
-+ "or else \'firefox\'\n",
-+ [Apps]),
-+ stop().
-+
-+
-+get_applications() ->
-+ gen_server:call(ct_web_tool,get_applications).
-+
-+get_port() ->
-+ gen_server:call(ct_web_tool,get_port).
-+
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%% %%
-+%% Api functions to the genserver. %%
-+%% %%
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%----------------------------------------------------------------------
-+%
-+%----------------------------------------------------------------------
-+
-+start()->
-+ start(standard_path,standard_data).
-+
-+start(Path,standard_data)->
-+ case get_standard_data() of
-+ {error,Reason} ->
-+ {error,Reason};
-+ Data ->
-+ start(Path,Data)
-+ end;
-+
-+start(standard_path,Data)->
-+ Path=get_path(),
-+ start(Path,Data);
-+
-+start(Path,Port) when is_integer(Port)->
-+ Data = get_standard_data(Port),
-+ start(Path,Data);
-+
-+start(Path,Data0)->
-+ Data = Data0 ++ rest_of_standard_data(),
-+ gen_server:start({local,ct_web_tool},ct_webtool,{Path,Data},[]).
-+
-+stop()->
-+ gen_server:call(ct_web_tool,stoppit).
-+
-+%----------------------------------------------------------------------
-+%Web Api functions called by the web
-+%----------------------------------------------------------------------
-+started_tools(Env,Input)->
-+ gen_server:call(ct_web_tool,{started_tools,Env,Input}).
-+
-+toolbar(Env,Input)->
-+ gen_server:call(ct_web_tool,{toolbar,Env,Input}).
-+
-+start_tools(Env,Input)->
-+ gen_server:call(ct_web_tool,{start_tools,Env,Input}).
-+
-+stop_tools(Env,Input)->
-+ gen_server:call(ct_web_tool,{stop_tools,Env,Input}).
-+%----------------------------------------------------------------------
-+%Support API for other tools
-+%----------------------------------------------------------------------
-+
-+is_localhost()->
-+ gen_server:call(ct_web_tool,is_localhost).
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%% %%
-+%%The gen_server callback functions that builds the webbpages %%
-+%% %%
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+handle_call(get_applications,_,State)->
-+ MS = ets:fun2ms(fun({Tool,{web_data,{_,Start}}}) -> {Tool,Start} end),
-+ Tools = ets:select(State#state.app_data,MS),
-+ {reply,Tools,State};
-+
-+handle_call(get_port,_,State)->
-+ {value,{port,Port}}=lists:keysearch(port,1,State#state.web_data),
-+ {reply,Port,State};
-+
-+handle_call({started_tools,_Env,_Input},_,State)->
-+ {reply,started_tools_page(State),State};
-+
-+handle_call({toolbar,_Env,_Input},_,State)->
-+ {reply,toolbar(),State};
-+
-+handle_call({start_tools,Env,Input},_,State)->
-+ {NewState,Page}=start_tools_page(Env,Input,State),
-+ {reply,Page,NewState};
-+
-+handle_call({stop_tools,Env,Input},_,State)->
-+ {NewState,Page}=stop_tools_page(Env,Input,State),
-+ {reply,Page,NewState};
-+
-+handle_call(stoppit,_From,Data)->
-+ {stop,normal,ok,Data};
-+
-+handle_call(is_localhost,_From,Data)->
-+ Result=case proplists:get_value(bind_address, Data#state.web_data) of
-+ ?DEFAULT_ADDR ->
-+ true;
-+ _IpNumber ->
-+ false
-+ end,
-+ {reply,Result,Data}.
-+
-+
-+handle_info(_Message,State)->
-+ {noreply,State}.
-+
-+handle_cast(_Request,State)->
-+ {noreply,State}.
-+
-+code_change(_,State,_)->
-+ {ok,State}.
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%
-+% The other functions needed by the gen_server behaviour
-+%
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%----------------------------------------------------------------------
-+% Start the gen_server
-+%----------------------------------------------------------------------
-+init({Path,Config})->
-+ case filelib:is_dir(Path) of
-+ true ->
-+ {ok, Table} = get_tool_files_data(),
-+ insert_app(?WEBTOOL_ALIAS, Table),
-+ case ct_webtool_sup:start_link() of
-+ {ok, Pid} ->
-+ case start_webserver(Table, Path, Config) of
-+ {ok, _} ->
-+ print_url(Config),
-+ {ok,#state{priv_dir=Path,
-+ app_data=Table,
-+ supvis=Pid,
-+ web_data=Config}};
-+ {error, Error} ->
-+ {stop, {error, Error}}
-+ end;
-+ Error ->
-+ {stop,Error}
-+ end;
-+ false ->
-+ {stop, {error, error_dir}}
-+ end.
-+
-+terminate(_Reason,Data)->
-+ %%shut down the webbserver
-+ shutdown_server(Data),
-+ %%Shutdown the different tools that are started with application:start
-+ shutdown_apps(Data),
-+ %%Shutdown the supervisor and its children will die
-+ shutdown_supervisor(Data),
-+ ok.
-+
-+print_url(ConfigData)->
-+ Server=proplists:get_value(server_name,ConfigData,"undefined"),
-+ Port=proplists:get_value(port,ConfigData,"undefined"),
-+ {A,B,C,D}=proplists:get_value(bind_address,ConfigData,"undefined"),
-+ io:format("WebTool is available at http://~s:~w/~n",[Server,Port]),
-+ io:format("Or http://~w.~w.~w.~w:~w/~n",[A,B,C,D,Port]).
-+
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%
-+% begin build the pages
-+%
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+
-+%----------------------------------------------------------------------
-+%The page that shows the started tools
-+%----------------------------------------------------------------------
-+started_tools_page(State)->
-+ [?HEADER,?HTML_HEADER,started_tools(State),?HTML_END].
-+
-+toolbar()->
-+ [?HEADER,?HTML_HEADER,toolbar_page(),?HTML_END].
-+
-+
-+start_tools_page(_Env,Input,State)->
-+ %%io:format("~n======= ~n ~p ~n============~n",[Input]),
-+ case get_tools(Input) of
-+ {tools,Tools}->
-+ %%io:format("~n======= ~n ~p ~n============~n",[Tools]),
-+ {ok,NewState}=handle_apps(Tools,State,start),
-+ {NewState,[?HEADER,?HTML_HEADER_RELOAD,reload_started_apps(),
-+ show_unstarted_apps(NewState),?HTML_END]};
-+ _ ->
-+ {State,[?HEADER,?HTML_HEADER,show_unstarted_apps(State),?HTML_END]}
-+ end.
-+
-+stop_tools_page(_Env,Input,State)->
-+ case get_tools(Input) of
-+ {tools,Tools}->
-+ {ok,NewState}=handle_apps(Tools,State,stop),
-+ {NewState,[?HEADER,?HTML_HEADER_RELOAD,reload_started_apps(),
-+ show_started_apps(NewState),?HTML_END]};
-+ _ ->
-+ {State,[?HEADER,?HTML_HEADER,show_started_apps(State),?HTML_END]}
-+ end.
-+
-+
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%%
-+%% Functions that start and config the webserver
-+%% 1. Collect the config data
-+%% 2. Start webserver
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+
-+%----------------------------------------------------------------------
-+% Start the webserver
-+%----------------------------------------------------------------------
-+start_webserver(Data,Path,Config)->
-+ case get_conf_data(Data,Path,Config) of
-+ {ok,Conf_data}->
-+ %%io:format("Conf_data: ~p~n",[Conf_data]),
-+ start_server(Conf_data);
-+ {error,Error} ->
-+ {error,{error_server_conf_file,Error}}
-+ end.
-+
-+start_server(Conf_data)->
-+ case inets:start(httpd, Conf_data, stand_alone) of
-+ {ok,Pid}->
-+ {ok,Pid};
-+ Error->
-+ {error,{server_error,Error}}
-+ end.
-+
-+%----------------------------------------------------------------------
-+% Create config data for the webserver
-+%----------------------------------------------------------------------
-+get_conf_data(Data,Path,Config)->
-+ Aliases=get_aliases(Data),
-+ ServerRoot = filename:join([Path,"root"]),
-+ MimeTypesFile = filename:join([ServerRoot,"conf","mime.types"]),
-+ case httpd_conf:load_mime_types(MimeTypesFile) of
-+ {ok,MimeTypes} ->
-+ Config1 = Config ++ Aliases,
-+ Config2 = [{server_root,ServerRoot},
-+ {document_root,filename:join([Path,"root/doc"])},
-+ {mime_types,MimeTypes} |
-+ Config1],
-+ {ok,Config2};
-+ Error ->
-+ Error
-+ end.
-+
-+%----------------------------------------------------------------------
-+% Control the path for *.tools files
-+%----------------------------------------------------------------------
-+get_tool_files_data()->
-+ Tools=get_tools1(code:get_path()),
-+ %%io:format("Data : ~p ~n",[Tools]),
-+ get_file_content(Tools).
-+
-+%----------------------------------------------------------------------
-+%Control that the data in the file really is erlang terms
-+%----------------------------------------------------------------------
-+get_file_content(Tools)->
-+ Get_data=fun({tool,ToolData}) ->
-+ %%io:format("Data : ~p ~n",[ToolData]),
-+ case proplists:get_value(config_func,ToolData) of
-+ {M,F,A}->
-+ case catch apply(M,F,A) of
-+ {'EXIT',_} ->
-+ bad_data;
-+ Data when is_tuple(Data) ->
-+ Data;
-+ _->
-+ bad_data
-+ end;
-+ _ ->
-+ bad_data
-+ end
-+ end,
-+ insert_file_content([X ||X<-lists:map(Get_data,Tools),X/=bad_data]).
-+
-+%----------------------------------------------------------------------
-+%Insert the data from the file in to the ets:table
-+%----------------------------------------------------------------------
-+insert_file_content(Content)->
-+ Table=ets:new(app_data,[bag]),
-+ lists:foreach(fun(X)->
-+ insert_app(X,Table)
-+ end,Content),
-+ {ok,Table}.
-+
-+%----------------------------------------------------------------------
-+%Control that we got a a tuple of a atom and a list if so add the
-+%elements in the list to the ets:table
-+%----------------------------------------------------------------------
-+insert_app({Name,Key_val_list},Table) when is_list(Key_val_list),is_atom(Name)->
-+ %%io:format("ToolData: ~p: ~p~n",[Name,Key_val_list]),
-+ lists:foreach(
-+ fun({alias,{erl_alias,Alias,Mods}}) ->
-+ Key_val = {erl_script_alias,{Alias,Mods}},
-+ %%io:format("Insert: ~p~n",[Key_val]),
-+ ets:insert(Table,{Name,Key_val});
-+ (Key_val_pair)->
-+ %%io:format("Insert: ~p~n",[Key_val_pair]),
-+ ets:insert(Table,{Name,Key_val_pair})
-+ end,
-+ Key_val_list);
-+
-+insert_app(_,_)->
-+ ok.
-+
-+%----------------------------------------------------------------------
-+% Select all the alias in the database
-+%----------------------------------------------------------------------
-+get_aliases(Data)->
-+ MS = ets:fun2ms(fun({_,{erl_script_alias,Alias}}) ->
-+ {erl_script_alias,Alias};
-+ ({_,{alias,Alias}}) ->
-+ {alias,Alias}
-+ end),
-+ ets:select(Data,MS).
-+
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%% %%
-+%% Helper functions %%
-+%% %%
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+get_standard_data(Port)->
-+ [
-+ {port,Port},
-+ {bind_address,?DEFAULT_ADDR},
-+ {server_name,"localhost"}
-+ ].
-+
-+get_standard_data()->
-+ case get_free_port(?DEFAULT_PORT,?MAX_NUMBER_OF_WEBTOOLS) of
-+ {error,Reason} -> {error,Reason};
-+ Port ->
-+ [
-+ {port,Port},
-+ {bind_address,?DEFAULT_ADDR},
-+ {server_name,"localhost"}
-+ ]
-+ end.
-+
-+get_free_port(_Port,0) ->
-+ {error,no_free_port_found};
-+get_free_port(Port,N) ->
-+ case gen_tcp:connect("localhost",Port,[]) of
-+ {error, _Reason} ->
-+ Port;
-+ {ok,Sock} ->
-+ gen_tcp:close(Sock),
-+ get_free_port(Port+1,N-1)
-+ end.
-+
-+rest_of_standard_data() ->
-+ [
-+ %% Do not allow the server to be crashed by malformed http-request
-+ {max_header_siz,1024},
-+ {max_header_action,reply414},
-+ %% Go on a straight ip-socket
-+ {com_type,ip_comm},
-+ %% Do not change the order of these module names!!
-+ {modules,[mod_alias,
-+ mod_auth,
-+ mod_esi,
-+ mod_actions,
-+ mod_cgi,
-+ mod_include,
-+ mod_dir,
-+ mod_get,
-+ mod_head,
-+ mod_log,
-+ mod_disk_log]},
-+ {directory_index,["index.html"]},
-+ {default_type,"text/plain"}
-+ ].
-+
-+
-+get_path()->
-+ code:priv_dir(webtool).
-+
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+% These functions is used to shutdown the webserver
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+
-+%----------------------------------------------------------------------
-+% Shut down the webbserver
-+%----------------------------------------------------------------------
-+shutdown_server(State)->
-+ {Addr,Port} = get_addr_and_port(State#state.web_data),
-+ inets:stop(httpd,{Addr,Port}).
-+
-+get_addr_and_port(Config) ->
-+ Addr = proplists:get_value(bind_address,Config,?DEFAULT_ADDR),
-+ Port = proplists:get_value(port,Config,?DEFAULT_PORT),
-+ {Addr,Port}.
-+
-+%----------------------------------------------------------------------
-+% Select all apps in the table and close them
-+%----------------------------------------------------------------------
-+shutdown_apps(State)->
-+ Data=State#state.app_data,
-+ MS = ets:fun2ms(fun({_,{start,HowToStart}}) -> HowToStart end),
-+ lists:foreach(fun(Start_app)->
-+ stop_app(Start_app)
-+ end,
-+ ets:select(Data,MS)).
-+
-+%----------------------------------------------------------------------
-+%Shuts down the supervisor that supervises tools that is not
-+%Designed as applications
-+%----------------------------------------------------------------------
-+shutdown_supervisor(State)->
-+ %io:format("~n==================~n"),
-+ ct_webtool_sup:stop(State#state.supvis).
-+ %io:format("~n==================~n").
-+
-+%----------------------------------------------------------------------
-+%close the individual apps.
-+%----------------------------------------------------------------------
-+stop_app({child,_Real_name})->
-+ ok;
-+
-+stop_app({app,Real_name})->
-+ application:stop(Real_name);
-+
-+stop_app({func,_Start,Stop})->
-+ case Stop of
-+ {M,F,A} ->
-+ catch apply(M,F,A);
-+ _NoStop ->
-+ ok
-+ end.
-+
-+
-+
-+
-+
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%%
-+%% These functions creates the webpage where the user can select if
-+%% to start apps or to stop apps
-+%%
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+
-+toolbar_page()->
-+ "<TABLE>
-+ <TR>
-+ <TD>
-+ <B>Select Action</B>
-+ </TD>
-+ </TR>
-+ <TR>
-+ <TD>
-+ <A HREF=\"./start_tools\" TARGET=right> Start Tools</A>
-+ </TD>
-+ </TR>
-+ <TR>
-+ <TD>
-+ <A HREF=\"./stop_tools\" TARGET=right> Stop Tools</A>
-+ </TD>
-+ </TR>
-+ </TABLE>".
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%%
-+%% These functions creates the webbpage that shows the started apps
-+%%
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+
-+%----------------------------------------------------------------------
-+% started_tools(State)->String (html table)
-+% State is a record of type state
-+%----------------------------------------------------------------------
-+started_tools(State)->
-+ Names=get_started_apps(State#state.app_data,State#state.started),
-+ "<TABLE BORDER=1 WIDTH=100%>
-+ "++ make_rows(Names,[],0) ++"
-+ </TABLE>".
-+%----------------------------------------------------------------------
-+%get_started_apps(Data,Started)-> [{web_name,link}]
-+%selects the started apps from the ets table of apps.
-+%----------------------------------------------------------------------
-+
-+get_started_apps(Data,Started)->
-+ SelectData=fun({Name,Link}) ->
-+ {Name,Link}
-+ end,
-+ MS = lists:map(fun(A) -> {{A,{web_data,'$1'}},[],['$1']} end,Started),
-+
-+ [{"WebTool","/tool_management.html"} |
-+ [SelectData(X) || X <- ets:select(Data,MS)]].
-+
-+%----------------------------------------------------------------------
-+% make_rows(List,Result,Fields)-> String (The rows of a htmltable
-+% List a list of tupler discibed above
-+% Result an accumulator for the result
-+% Field, counter that counts the number of cols in each row.
-+%----------------------------------------------------------------------
-+make_rows([],Result,Fields)->
-+ Result ++ fill_out(Fields);
-+make_rows([Data|Paths],Result,Field)when Field==0->
-+ make_rows(Paths,Result ++ "<TR>" ++ make_field(Data),Field+1);
-+
-+make_rows([Path|Paths],Result,Field)when Field==4->
-+ make_rows(Paths,Result ++ make_field(Path) ++ "</TR>",0);
-+
-+make_rows([Path|Paths],Result,Field)->
-+ make_rows(Paths,Result ++ make_field(Path),Field+1).
-+
-+%----------------------------------------------------------------------
-+% make_fields(Path)-> String that is a field i a html table
-+% Path is a name url tuple {Name,url}
-+%----------------------------------------------------------------------
-+make_field(Path)->
-+ "<TD WIDTH=20%>" ++ get_name(Path) ++ "</TD>".
-+
-+
-+%----------------------------------------------------------------------
-+%get_name({Nae,Url})->String that represents a <A> tag in html.
-+%----------------------------------------------------------------------
-+get_name({Name,Url})->
-+ "<A HREF=\"" ++ Url ++ "\" TARGET=app_frame>" ++ Name ++ "</A>".
-+
-+
-+%----------------------------------------------------------------------
-+% fill_out(Nr)-> String, that represent Nr fields in a html-table.
-+%----------------------------------------------------------------------
-+fill_out(Nr)when Nr==0->
-+ [];
-+fill_out(Nr)when Nr==4->
-+ "<TD WIDTH=\"20%\" >&nbsp</TD></TR>";
-+
-+fill_out(Nr)->
-+ "<TD WIDTH=\"20%\">&nbsp</TD>" ++ fill_out(Nr+1).
-+
-+
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%%
-+%%These functions starts applicatons and builds the page showing tools
-+%%to start
-+%%
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%----------------------------------------------------------------------
-+%Controls whether the user selected a tool to start
-+%----------------------------------------------------------------------
-+get_tools(Input)->
-+ case httpd:parse_query(Input) of
-+ []->
-+ no_tools;
-+ Tools->
-+ FormatData=fun({_Name,Data}) -> list_to_atom(Data) end,
-+ SelectData=
-+ fun({Name,_Data}) -> string:equal(Name,"app") end,
-+ {tools,[FormatData(X)||X<-Tools,SelectData(X)]}
-+ end.
-+
-+%----------------------------------------------------------------------
-+% Selects the data to start the applications the user has ordered
-+% starting of
-+%----------------------------------------------------------------------
-+handle_apps([],State,_Cmd)->
-+ {ok,State};
-+
-+handle_apps([Tool|Tools],State,Cmd)->
-+ case ets:match_object(State#state.app_data,{Tool,{start,'_'}}) of
-+ []->
-+ Started = case Cmd of
-+ start ->
-+ [Tool|State#state.started];
-+ stop ->
-+ lists:delete(Tool,State#state.started)
-+ end,
-+ {ok,#state{priv_dir=State#state.priv_dir,
-+ app_data=State#state.app_data,
-+ supvis=State#state.supvis,
-+ web_data=State#state.web_data,
-+ started=Started}};
-+ ToStart ->
-+ case handle_apps2(ToStart,State,Cmd) of
-+ {ok,NewState}->
-+ handle_apps(Tools,NewState,Cmd);
-+ _->
-+ handle_apps(Tools,State,Cmd)
-+ end
-+ end.
-+
-+%----------------------------------------------------------------------
-+%execute every start or stop data about a tool.
-+%----------------------------------------------------------------------
-+handle_apps2([{Name,Start_data}],State,Cmd)->
-+ case handle_app({Name,Start_data},State#state.app_data,State#state.supvis,Cmd) of
-+ ok->
-+ Started = case Cmd of
-+ start ->
-+ [Name|State#state.started];
-+ stop ->
-+
-+ lists:delete(Name,State#state.started)
-+ end,
-+ {ok,#state{priv_dir=State#state.priv_dir,
-+ app_data=State#state.app_data,
-+ supvis=State#state.supvis,
-+ web_data=State#state.web_data,
-+ started=Started}};
-+ _->
-+ error
-+ end;
-+
-+handle_apps2([{Name,Start_data}|Rest],State,Cmd)->
-+ case handle_app({Name,Start_data},State#state.app_data,State#state.supvis,Cmd)of
-+ ok->
-+ handle_apps2(Rest,State,Cmd);
-+ _->
-+ error
-+ end.
-+
-+
-+%----------------------------------------------------------------------
-+% Handle start and stop of applications
-+%----------------------------------------------------------------------
-+
-+handle_app({Name,{start,{func,Start,Stop}}},Data,_Pid,Cmd)->
-+ Action = case Cmd of
-+ start ->
-+ Start;
-+ _ ->
-+ Stop
-+ end,
-+ case Action of
-+ {M,F,A} ->
-+ case catch apply(M,F,A) of
-+ {'EXIT',_} = Exit->
-+ %%! Here the tool disappears from the webtool interface!!
-+ io:format("\n=======ERROR (webtool, line ~w) =======\n"
-+ "Could not start application \'~p\'\n\n"
-+ "~w:~w(~s) ->\n"
-+ "~p\n\n",
-+ [?LINE,Name,M,F,format_args(A),Exit]),
-+ ets:delete(Data,Name);
-+ _OK->
-+ ok
-+ end;
-+ _NoStart ->
-+ ok
-+ end;
-+
-+
-+handle_app({Name,{start,{child,ChildSpec}}},Data,Pid,Cmd)->
-+ case Cmd of
-+ start ->
-+ case catch supervisor:start_child(Pid,ChildSpec) of
-+ {ok,_}->
-+ ok;
-+ {ok,_,_}->
-+ ok;
-+ {error,Reason}->
-+ %%! Here the tool disappears from the webtool interface!!
-+ io:format("\n=======ERROR (webtool, line ~w) =======\n"
-+ "Could not start application \'~p\'\n\n"
-+ "supervisor:start_child(~p,~p) ->\n"
-+ "~p\n\n",
-+ [?LINE,Name,Pid,ChildSpec,{error,Reason}]),
-+ ets:delete(Data,Name);
-+ Error ->
-+ %%! Here the tool disappears from the webtool interface!!
-+ io:format("\n=======ERROR (webtool, line ~w) =======\n"
-+ "Could not start application \'~p\'\n\n"
-+ "supervisor:start_child(~p,~p) ->\n"
-+ "~p\n\n",
-+ [?LINE,Name,Pid,ChildSpec,Error]),
-+ ets:delete(Data,Name)
-+ end;
-+ stop ->
-+ case catch supervisor:terminate_child(websup,element(1,ChildSpec)) of
-+ ok ->
-+ supervisor:delete_child(websup,element(1,ChildSpec));
-+ _ ->
-+ error
-+ end
-+ end;
-+
-+
-+
-+handle_app({Name,{start,{app,Real_name}}},Data,_Pid,Cmd)->
-+ case Cmd of
-+ start ->
-+ case application:start(Real_name,temporary) of
-+ ok->
-+ io:write(Name),
-+ ok;
-+ {error,{already_started,_}}->
-+ %% Remove it from the database so we dont start
-+ %% anything already started
-+ ets:match_delete(Data,{Name,{start,{app,Real_name}}}),
-+ ok;
-+ {error,_Reason}=Error->
-+ %%! Here the tool disappears from the webtool interface!!
-+ io:format("\n=======ERROR (webtool, line ~w) =======\n"
-+ "Could not start application \'~p\'\n\n"
-+ "application:start(~p,~p) ->\n"
-+ "~p\n\n",
-+ [?LINE,Name,Real_name,temporary,Error]),
-+ ets:delete(Data,Name)
-+ end;
-+
-+ stop ->
-+ application:stop(Real_name)
-+ end;
-+
-+%----------------------------------------------------------------------
-+% If the data is incorrect delete the app
-+%----------------------------------------------------------------------
-+handle_app({Name,Incorrect},Data,_Pid,Cmd)->
-+ %%! Here the tool disappears from the webtool interface!!
-+ io:format("\n=======ERROR (webtool, line ~w) =======\n"
-+ "Could not ~w application \'~p\'\n\n"
-+ "Incorrect data: ~p\n\n",
-+ [?LINE,Cmd,Name,Incorrect]),
-+ ets:delete(Data,Name).
-+
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%% %%
-+%% this functions creates the page that shows the unstarted tools %%
-+%% %%
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+
-+reload_started_apps()->
-+ "<script>
-+ function reloadCompiledList()
-+ {
-+ parent.parent.top1.document.location.href=\"/webtool/webtool/started_tools\";
-+ }
-+ </script>".
-+
-+show_unstarted_apps(State)->
-+ "<TABLE HEIGHT=100% WIDTH=100% BORDER=0>
-+ <TR HEIGHT=80%><TD ALIGN=\"center\" VALIGN=\"middle\">
-+ <FORM NAME=\"stop_apps\" ACTION=\"/webtool/webtool/start_tools\" >
-+ <TABLE BORDER=1 WIDTH=60%>
-+ <TR BGCOLOR=\"#8899AA\">
-+ <TD ALIGN=CENTER COLSPAN=2><FONT SIZE=4>Available Tools<FONT></TD>
-+ </TR>
-+ <TR>
-+ <TD WIDTH=50%>
-+ <TABLE BORDER=0>
-+ "++ list_available_apps(State)++"
-+ <TR><TD COLSPAN=2>&nbsp;</TD></TR>
-+ <TR>
-+ <TD COLSPAN=2 ALIGN=\"center\">
-+ <INPUT TYPE=submit VALUE=\"Start\">
-+ </TD>
-+ </TR>
-+ </TABLE>
-+ </TD>
-+ <TD>
-+ To Start a Tool:
-+ <UL>
-+ <LI>Select the
-+ checkbox for each tool to
-+ start.</LI>
-+ <LI>Click on the
-+ button marked <EM>Start</EM>.</LI></UL>
-+ </TD>
-+ </TR>
-+ </TABLE>
-+ </FORM>
-+ </TD></TR>
-+ <TR><TD>&nbsp;</TD></TR>
-+ </TABLE>".
-+
-+
-+
-+list_available_apps(State)->
-+ MS = ets:fun2ms(fun({Tool,{web_data,{Name,_}}}) -> {Tool,Name} end),
-+ Unstarted_apps=
-+ lists:filter(
-+ fun({Tool,_})->
-+ false==lists:member(Tool,State#state.started)
-+ end,
-+ ets:select(State#state.app_data,MS)),
-+ case Unstarted_apps of
-+ []->
-+ "<TR><TD>All tools are started</TD></TR>";
-+ _->
-+ list_apps(Unstarted_apps)
-+ end.
-+
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%% %%
-+%% these functions creates the page that shows the started apps %%
-+%% the user can select to shutdown %%
-+%% %%
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+show_started_apps(State)->
-+ "<TABLE HEIGHT=100% WIDTH=100% BORDER=0>
-+ <TR HEIGHT=80%><TD ALIGN=\"center\" VALIGN=\"middle\">
-+ <FORM NAME=\"stop_apps\" ACTION=\"/webtool/webtool/stop_tools\" >
-+ <TABLE BORDER=1 WIDTH=60%>
-+ <TR BGCOLOR=\"#8899AA\">
-+ <TD ALIGN=CENTER COLSPAN=2><FONT SIZE=4>Started Tools<FONT></TD>
-+ </TR>
-+ <TR>
-+ <TD WIDTH=50%>
-+ <TABLE BORDER=0>
-+ "++ list_started_apps(State)++"
-+ <TR><TD COLSPAN=2>&nbsp;</TD></TR>
-+ <TR>
-+ <TD COLSPAN=2 ALIGN=\"center\">
-+ <INPUT TYPE=submit VALUE=\"Stop\">
-+ </TD>
-+ </TR>
-+ </TABLE>
-+ </TD>
-+ <TD>
-+ Stop a Tool:
-+ <UL>
-+ <LI>Select the
-+ checkbox for each tool to
-+ stop.</LI>
-+ <LI>Click on the
-+ button marked <EM>Stop</EM>.</LI></UL>
-+ </TD>
-+ </TR>
-+ </TABLE>
-+ </FORM>
-+ </TD></TR>
-+ <TR><TD>&nbsp;</TD></TR>
-+ </TABLE>".
-+
-+list_started_apps(State)->
-+ MS = lists:map(fun(A) -> {{A,{web_data,{'$1','_'}}},[],[{{A,'$1'}}]} end,
-+ State#state.started),
-+ Started_apps= ets:select(State#state.app_data,MS),
-+ case Started_apps of
-+ []->
-+ "<TR><TD>No tool is started yet.</TD></TR>";
-+ _->
-+ list_apps(Started_apps)
-+ end.
-+
-+
-+list_apps(Apps) ->
-+ lists:map(fun({Tool,Name})->
-+ "<TR><TD>
-+ <INPUT TYPE=\"checkbox\" NAME=\"app\" VALUE=\""
-+ ++ atom_to_list(Tool) ++ "\">
-+ " ++ Name ++ "
-+ </TD></TR>"
-+ end,
-+ Apps).
-+
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%% %%
-+%% Collecting the data from the *.tool files %%
-+%% %%
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%----------------------------------------
-+% get_tools(Dirs) => [{M,F,A},{M,F,A}...{M,F,A}]
-+% Dirs - [string()] Directory names
-+% Calls get_tools2/2 recursively for a number of directories
-+% to retireve the configuration data for the web based tools.
-+%----------------------------------------
-+get_tools1(Dirs)->
-+ get_tools1(Dirs,[]).
-+
-+get_tools1([Dir|Rest],Data) when is_list(Dir) ->
-+ Tools=case filename:basename(Dir) of
-+ %% Dir is an 'ebin' directory, check in '../priv' as well
-+ "ebin" ->
-+ [get_tools2(filename:join(filename:dirname(Dir),"priv")) |
-+ get_tools2(Dir)];
-+ _ ->
-+ get_tools2(Dir)
-+ end,
-+ get_tools1(Rest,[Tools|Data]);
-+
-+get_tools1([],Data) ->
-+ lists:flatten(Data).
-+
-+%----------------------------------------
-+% get_tools2(Directory) => DataList
-+% DataList : [WebTuple]|[]
-+% WebTuple: {tool,[{web,M,F,A}]}
-+%
-+%----------------------------------------
-+get_tools2(Dir)->
-+ get_tools2(tool_files(Dir),[]).
-+
-+get_tools2([ToolFile|Rest],Data) ->
-+ case get_tools3(ToolFile) of
-+ {tool,WebData} ->
-+ get_tools2(Rest,[{tool,WebData}|Data]);
-+ {error,_Reason} ->
-+ get_tools2(Rest,Data);
-+ nodata ->
-+ get_tools2(Rest,Data)
-+ end;
-+
-+get_tools2([],Data) ->
-+ Data.
-+
-+%----------------------------------------
-+% get_tools3(ToolFile) => {ok,Tool}|{error,Reason}|nodata
-+% Tool: {tool,[KeyValTuple]}
-+% ToolFile - string() A .tool file
-+% Now we have the file get the data and sort it out
-+%----------------------------------------
-+get_tools3(ToolFile) ->
-+ case file:consult(ToolFile) of
-+ {error,open} ->
-+ {error,nofile};
-+ {error,read} ->
-+ {error,format};
-+ {ok,[{version,"1.2"},ToolInfo]} when is_list(ToolInfo)->
-+ webdata(ToolInfo);
-+ {ok,[{version,_Vsn},_Info]} ->
-+ {error,old_version};
-+ {ok,_Other} ->
-+ {error,format}
-+ end.
-+
-+
-+%----------------------------------------------------------------------
-+% webdata(TupleList)-> ToolTuple| nodata
-+% ToolTuple: {tool,[{config_func,{M,F,A}}]}
-+%
-+% There are a little unneccesary work in this format but it is extendable
-+%----------------------------------------------------------------------
-+webdata(TupleList)->
-+ case proplists:get_value(config_func,TupleList,nodata) of
-+ {M,F,A} ->
-+ {tool,[{config_func,{M,F,A}}]};
-+ _ ->
-+ nodata
-+ end.
-+
-+
-+%=============================================================================
-+% Functions for getting *.tool configuration files
-+%=============================================================================
-+
-+%----------------------------------------
-+% tool_files(Dir) => ToolFiles
-+% Dir - string() Directory name
-+% ToolFiles - [string()]
-+% Return the list of all files in Dir ending with .tool (appended to Dir)
-+%----------------------------------------
-+tool_files(Dir) ->
-+ case file:list_dir(Dir) of
-+ {ok,Files} ->
-+ filter_tool_files(Dir,Files);
-+ {error,_Reason} ->
-+ []
-+ end.
-+
-+%----------------------------------------
-+% filter_tool_files(Dir,Files) => ToolFiles
-+% Dir - string() Directory name
-+% Files, ToolFiles - [string()] File names
-+% Filters out the files in Files ending with .tool and append them to Dir
-+%----------------------------------------
-+filter_tool_files(_Dir,[]) ->
-+ [];
-+filter_tool_files(Dir,[File|Rest]) ->
-+ case filename:extension(File) of
-+ ".tool" ->
-+ [filename:join(Dir,File)|filter_tool_files(Dir,Rest)];
-+ _ ->
-+ filter_tool_files(Dir,Rest)
-+ end.
-+
-+
-+%%%-----------------------------------------------------------------
-+%%% format functions
-+ffunc({M,F,A}) when is_list(A) ->
-+ io_lib:format("~w:~w(~s)\n",[M,F,format_args(A)]);
-+ffunc({M,F,A}) when is_integer(A) ->
-+ io_lib:format("~w:~w/~w\n",[M,F,A]).
-+
-+format_args([]) ->
-+ "";
-+format_args(Args) ->
-+ Str = lists:append(["~p"|lists:duplicate(length(Args)-1,",~p")]),
-+ io_lib:format(Str,Args).
-diff --git lib/common_test/src/ct_webtool_sup.erl lib/common_test/src/ct_webtool_sup.erl
-new file mode 100644
-index 0000000..1d612a2
---- /dev/null
-+++ lib/common_test/src/ct_webtool_sup.erl
-@@ -0,0 +1,74 @@
-+%%
-+%% %CopyrightBegin%
-+%%
-+%% Copyright Ericsson AB 2001-2009. 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(ct_webtool_sup).
-+
-+-behaviour(supervisor).
-+
-+%% External exports
-+-export([start_link/0,stop/1]).
-+
-+%% supervisor callbacks
-+-export([init/1]).
-+
-+%%%----------------------------------------------------------------------
-+%%% API
-+%%%----------------------------------------------------------------------
-+start_link() ->
-+ supervisor:start_link({local,ct_websup},ct_webtool_sup, []).
-+
-+stop(Pid)->
-+ exit(Pid,normal).
-+%%%----------------------------------------------------------------------
-+%%% Callback functions from supervisor
-+%%%----------------------------------------------------------------------
-+
-+%%----------------------------------------------------------------------
-+%% Func: init/1
-+%% Returns: {ok, {SupFlags, [ChildSpec]}} |
-+%% ignore |
-+%% {error, Reason}
-+%%----------------------------------------------------------------------
-+init(_StartArgs) ->
-+ %%Child1 =
-+ %%Child2 ={webcover_backend,{webcover_backend,start_link,[]},permanent,2000,worker,[webcover_backend]},
-+ %%{ok,{{simple_one_for_one,5,10},[Child1]}}.
-+ {ok,{{one_for_one,100,10},[]}}.
-+
-+%%%----------------------------------------------------------------------
-+%%% Internal functions
-+%%%----------------------------------------------------------------------
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-diff --git lib/common_test/src/vts.erl lib/common_test/src/vts.erl
-index b340c6f..ab13e7d 100644
---- lib/common_test/src/vts.erl
-+++ lib/common_test/src/vts.erl
-@@ -63,21 +63,21 @@
- %%%-----------------------------------------------------------------
- %%% User API
- start() ->
-- webtool:start(),
-- webtool:start_tools([],"app=vts").
-+ ct_webtool:start(),
-+ ct_webtool:start_tools([],"app=vts").
-
- init_data(ConfigFiles,EvHandlers,LogDir,LogOpts,Tests) ->
- call({init_data,ConfigFiles,EvHandlers,LogDir,LogOpts,Tests}).
-
- stop() ->
-- webtool:stop_tools([],"app=vts"),
-- webtool:stop().
-+ ct_webtool:stop_tools([],"app=vts"),
-+ ct_webtool:stop().
-
- report(What,Data) ->
- call({report,What,Data}).
-
- %%%-----------------------------------------------------------------
--%%% Return config data used by webtool
-+%%% Return config data used by ct_webtool
- config_data() ->
- {ok,LogDir} =
- case lists:keysearch(logdir,1,init:get_arguments()) of
-diff --git lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
-index a145d85..d01211b 100644
---- lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
-+++ lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
-@@ -164,7 +164,7 @@ hello_from_server_first(Config) ->
- {ok,Client} = ct_netconfc:only_open(?DEFAULT_SSH_OPTS(DataDir)),
- ct:sleep(500),
- ?NS:expect(hello),
-- ?ok = ct_netconfc:hello(Client),
-+ ?ok = ct_netconfc:hello(Client, [{capability, ["urn:com:ericsson:ebase:1.1.0"]}], infinity),
- ?NS:expect_do_reply('close-session',close,ok),
- ?ok = ct_netconfc:close_session(Client),
- ok.
-@@ -490,13 +490,16 @@ action(Config) ->
- Data = [{myactionreturn,[{xmlns,"myns"}],["value"]}],
- %% test either to receive {data,Data} or {ok,Data},
- %% both need to be handled
-- {Reply,RetVal} = case element(3, now()) rem 2 of
-- 0 -> {{data,Data},{ok,Data}};
-- 1 -> {{ok,Data},ok}
-- end,
-- ct:log("Client will receive {~w,Data}", [element(1,Reply)]),
-- ?NS:expect_reply(action,Reply),
-- RetVal = ct_netconfc:action(Client,{myaction,[{xmlns,"myns"}],[]}),
-+ ct:log("Client will receive {~w,~p}", [data,Data]),
-+ ct:log("Expecting ~p", [{ok, Data}]),
-+ ?NS:expect_reply(action,{data, Data}),
-+ {ok, Data} = ct_netconfc:action(Client,{myaction,[{xmlns,"myns"}],[]}),
-+
-+ ct:log("Client will receive {~w,~p}", [ok,Data]),
-+ ct:log("Expecting ~p", [ok]),
-+ ?NS:expect_reply(action,{ok, Data}),
-+ ok = ct_netconfc:action(Client,{myaction,[{xmlns,"myns"}],[]}),
-+
- ?NS:expect_do_reply('close-session',close,ok),
- ?ok = ct_netconfc:close_session(Client),
- ok.
-diff --git lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl
-index 1d3f591..9dc9095 100644
---- lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl
-+++ lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl
-@@ -40,6 +40,7 @@ all() ->
- expect,
- expect_repeat,
- expect_sequence,
-+ expect_wait_until_prompt,
- expect_error_prompt,
- expect_error_timeout1,
- expect_error_timeout2,
-@@ -81,6 +82,8 @@ end_per_group(_GroupName, Config) ->
- expect(_) ->
- {ok, Handle} = ct_telnet:open(telnet_server_conn1),
- ok = ct_telnet:send(Handle, "echo ayt"),
-+ {ok,["ayt"]} = ct_telnet:expect(Handle, "ayt"),
-+ ok = ct_telnet:send(Handle, "echo ayt"),
- {ok,["ayt"]} = ct_telnet:expect(Handle, ["ayt"]),
- ok = ct_telnet:close(Handle),
- ok.
-@@ -103,6 +106,21 @@ expect_sequence(_) ->
- ok = ct_telnet:close(Handle),
- ok.
-
-+%% Check that expect can wait for delayed prompt
-+expect_wait_until_prompt(_) ->
-+ {ok, Handle} = ct_telnet:open(telnet_server_conn1),
-+ Timeouts = [{idle_timeout,5000},{total_timeout,7000}],
-+
-+ ok = ct_telnet:send(Handle, "echo_delayed_prompt 3000 xxx"),
-+ {ok,["xxx"]} =
-+ ct_telnet:expect(Handle, "xxx",
-+ [wait_for_prompt|Timeouts]),
-+ ok = ct_telnet:send(Handle, "echo_delayed_prompt 3000 yyy zzz"),
-+ {ok,[["yyy"],["zzz"]]} =
-+ ct_telnet:expect(Handle, ["yyy","zzz"],
-+ [{wait_for_prompt,"> "}|Timeouts]),
-+ ok.
-+
- %% Check that expect returns when a prompt is found, even if pattern
- %% is not matched.
- expect_error_prompt(_) ->
-diff --git lib/common_test/test/telnet_server.erl lib/common_test/test/telnet_server.erl
-index 11959c3..2db5a9b 100644
---- lib/common_test/test/telnet_server.erl
-+++ lib/common_test/test/telnet_server.erl
-@@ -242,6 +242,12 @@ do_handle_data("echo_loop " ++ Data,State) ->
- ReturnData = string:join(Lines,"\n"),
- send_loop(list_to_integer(TStr),ReturnData,State),
- {ok,State};
-+do_handle_data("echo_delayed_prompt "++Data,State) ->
-+ [MsStr|EchoData] = string:tokens(Data, " "),
-+ send(string:join(EchoData,"\n"),State),
-+ ct:sleep(list_to_integer(MsStr)),
-+ send("\r\n> ",State),
-+ {ok,State};
- do_handle_data("disconnect_after " ++WaitStr,State) ->
- Wait = list_to_integer(string:strip(WaitStr,right,$\n)),
- dbg("Server will close connection in ~w ms...", [Wait]),
-diff --git lib/common_test/vsn.mk lib/common_test/vsn.mk
-index d654a8a..e2d9217 100644
---- lib/common_test/vsn.mk
-+++ lib/common_test/vsn.mk
-@@ -1 +1 @@
--COMMON_TEST_VSN = 1.10
-+COMMON_TEST_VSN = 1.10.1
-diff --git lib/diameter/doc/src/diameter.xml lib/diameter/doc/src/diameter.xml
-index 6e41b01..ea175a5 100644
---- lib/diameter/doc/src/diameter.xml
-+++ lib/diameter/doc/src/diameter.xml
-@@ -1820,7 +1820,8 @@ The information presented here is as in the <c>connect</c> case except
- that the client connections are grouped under an <c>accept</c> tuple.</p>
-
- <p>
--Whether or not the &transport_opt; <c>pool_size</c> affects the format
-+Whether or not the &transport_opt; <c>pool_size</c> has been
-+configured affects the format
- of the listing in the case of a connecting transport, since a value
- greater than 1 implies multiple transport processes for the same
- <c>&transport_ref;</c>, as in the listening case.
-diff --git lib/diameter/doc/src/notes.xml lib/diameter/doc/src/notes.xml
-index 479fab2..6931788 100644
---- lib/diameter/doc/src/notes.xml
-+++ lib/diameter/doc/src/notes.xml
-@@ -42,6 +42,47 @@ first.</p>
-
- <!-- ===================================================================== -->
-
-+<section><title>diameter 1.9.1</title>
-+
-+ <section><title>Known Bugs and Problems</title>
-+ <list>
-+ <item>
-+ <p>
-+ Don't leave extra bit in decoded AVP data.</p>
-+ <p>
-+ OTP-12074 in OTP 17.3 missed one case: a length error on
-+ a trailing AVP unknown to the dictionary in question.</p>
-+ <p>
-+ Own Id: OTP-12642</p>
-+ </item>
-+ <item>
-+ <p>
-+ Don't confuse Result-Code and Experimental-Result</p>
-+ <p>
-+ The errors field of a decoded diameter_packet record was
-+ populated with a Result-Code AVP when an
-+ Experimental-Result containing a 3xxx Result-Code was
-+ received in an answer not setting the E-bit. The correct
-+ AVP is now extracted from the incoming message.</p>
-+ <p>
-+ Own Id: OTP-12654 Aux Id: seq12851 </p>
-+ </item>
-+ <item>
-+ <p>
-+ Don't count on unknown Application Id.</p>
-+ <p>
-+ OTP-11721 in OTP 17.1 missed the case of an Application
-+ Id not agreeing with that of the dictionary in question,
-+ causing counters to be accumulated on keys containing the
-+ unknown id.</p>
-+ <p>
-+ Own Id: OTP-12701</p>
-+ </item>
-+ </list>
-+ </section>
-+
-+</section>
-+
- <section><title>diameter 1.9</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
-diff --git lib/diameter/include/diameter_gen.hrl lib/diameter/include/diameter_gen.hrl
-index 0eef218..e8ffe7f 100644
---- lib/diameter/include/diameter_gen.hrl
-+++ lib/diameter/include/diameter_gen.hrl
-@@ -445,7 +445,7 @@ reset(_, _) ->
- %% undecoded. Note that the type field is 'undefined' in this case.
-
- decode_AVP(Name, Avp, {Avps, Acc}) ->
-- {[Avp | Avps], pack_AVP(Name, Avp, Acc)}.
-+ {[trim(Avp) | Avps], pack_AVP(Name, Avp, Acc)}.
-
- %% rc/1
-
-diff --git lib/diameter/src/base/diameter_codec.erl lib/diameter/src/base/diameter_codec.erl
-index 15a4c5e..bf2fe8e 100644
---- lib/diameter/src/base/diameter_codec.erl
-+++ lib/diameter/src/base/diameter_codec.erl
-@@ -640,8 +640,12 @@ split_data(Bin, Len) ->
- %% payload if this is a request. Do this (in cases that we
- %% know the type) by inducing a decode failure and letting
- %% the dictionary's decode (in diameter_gen) deal with it.
-- %% Here we don't know type. If the type isn't known, then
-- %% the decode just strips the extra bit.
-+ %%
-+ %% Note that the extra bit can only occur in the trailing
-+ %% AVP of a message or Grouped AVP, since a faulty AVP
-+ %% Length is otherwise indistinguishable from a correct
-+ %% one here, since we don't know the types of the AVPs
-+ %% being extracted.
- {<<0:1, Bin/binary>>, <<>>}
- end.
-
-@@ -690,8 +694,8 @@ pack_avp(#diameter_avp{code = undefined, data = B})
- Len = size(<<H:5/binary, _:24, T/binary>> = <<B/binary, 0:Pad>>),
- <<H/binary, Len:24, T/binary>>;
-
--%% ... from a dictionary compiled against old code in diameter_gen ...
- %% ... when ignoring errors in Failed-AVP ...
-+%% ... during a relay encode ...
- pack_avp(#diameter_avp{data = <<0:1, B/binary>>} = A) ->
- pack_avp(A#diameter_avp{data = B});
-
-diff --git lib/diameter/src/base/diameter_traffic.erl lib/diameter/src/base/diameter_traffic.erl
-index 538ebee..ffd2c0a 100644
---- lib/diameter/src/base/diameter_traffic.erl
-+++ lib/diameter/src/base/diameter_traffic.erl
-@@ -980,8 +980,8 @@ answer_message(OH, OR, RC, Dict0, #diameter_packet{avps = Avps,
- session_id(Code, Vid, Dict0, Avps)
- when is_list(Avps) ->
- try
-- {value, #diameter_avp{data = D}} = find_avp(Code, Vid, Avps),
-- [{'Session-Id', [Dict0:avp(decode, D, 'Session-Id')]}]
-+ #diameter_avp{data = Bin} = find_avp(Code, Vid, Avps),
-+ [{'Session-Id', [Dict0:avp(decode, Bin, 'Session-Id')]}]
- catch
- error: _ ->
- []
-@@ -998,26 +998,17 @@ failed_avp(_, [] = No) ->
-
- %% find_avp/3
-
--find_avp(Code, Vid, Avps)
-- when is_integer(Code), (undefined == Vid orelse is_integer(Vid)) ->
-- find(fun(A) -> is_avp(Code, Vid, A) end, Avps).
-+%% Grouped ...
-+find_avp(Code, VId, [[#diameter_avp{code = Code, vendor_id = VId} | _] = As
-+ | _]) ->
-+ As;
-
--%% The final argument here could be a list of AVP's, depending on the case,
--%% but we're only searching at the top level.
--is_avp(Code, Vid, #diameter_avp{code = Code, vendor_id = Vid}) ->
-- true;
--is_avp(_, _, _) ->
-- false.
-+%% ... or not.
-+find_avp(Code, VId, [#diameter_avp{code = Code, vendor_id = VId} = A | _]) ->
-+ A;
-
--find(_, []) ->
-- false;
--find(Pred, [H|T]) ->
-- case Pred(H) of
-- true ->
-- {value, H};
-- false ->
-- find(Pred, T)
-- end.
-+find_avp(Code, VId, [_ | Avps]) ->
-+ find_avp(Code, VId, Avps).
-
- %% 7. Error Handling
- %%
-@@ -1086,7 +1077,6 @@ incr_result(_, #diameter_packet{msg = undefined = No}, _, _) ->
- incr_result(Dir, Pkt, TPid, {Dict, AppDict, Dict0}) ->
- #diameter_packet{header = #diameter_header{is_error = E}
- = Hdr,
-- msg = Msg,
- errors = Es}
- = Pkt,
-
-@@ -1096,13 +1086,13 @@ incr_result(Dir, Pkt, TPid, {Dict, AppDict, Dict0}) ->
- recv /= Dir orelse [] == Es orelse incr_error(Dir, Id, TPid, AppDict),
-
- %% Exit on a missing result code.
-- T = rc_counter(Dict, Msg),
-+ T = rc_counter(Dict, Dir, Pkt),
- T == false andalso ?LOGX(no_result_code, {Dict, Dir, Hdr}),
-- {Ctr, RC} = T,
-+ {Ctr, RC, Avp} = T,
-
- %% Or on an inappropriate value.
- is_result(RC, E, Dict0)
-- orelse ?LOGX(invalid_error_bit, {Dict, Dir, Hdr, RC}),
-+ orelse ?LOGX(invalid_error_bit, {Dict, Dir, Hdr, Avp}),
-
- incr(TPid, {Id, Dir, Ctr}),
- Ctr.
-@@ -1116,19 +1106,15 @@ msg_id(#diameter_packet{header = H}, Dict) ->
- %% there are 2^32 (application ids) * 2^24 (command codes) = 2^56
- %% pairs for an attacker to choose from.
- msg_id(Hdr, Dict) ->
-- {_ApplId, Code, R} = Id = diameter_codec:msg_id(Hdr),
-- case Dict:msg_name(Code, 0 == R) of
-- '' ->
-- unknown(Dict:id(), R);
-- _ ->
-- Id
-+ {Aid, Code, R} = Id = diameter_codec:msg_id(Hdr),
-+ if Aid == ?APP_ID_RELAY ->
-+ {relay, R};
-+ true ->
-+ choose(Aid /= Dict:id() orelse '' == Dict:msg_name(Code, 0 == R),
-+ unknown,
-+ Id)
- end.
-
--unknown(?APP_ID_RELAY, R) ->
-- {relay, R};
--unknown(_, _) ->
-- unknown.
--
- %% No E-bit: can't be 3xxx.
- is_result(RC, false, _Dict0) ->
- RC < 3000 orelse 4000 =< RC;
-@@ -1148,7 +1134,7 @@ is_result(RC, true, _) ->
- incr(TPid, Counter) ->
- diameter_stats:incr(Counter, TPid, 1).
-
--%% rc_counter/2
-+%% rc_counter/3
-
- %% RFC 3588, 7.6:
- %%
-@@ -1156,39 +1142,45 @@ incr(TPid, Counter) ->
- %% applications MUST include either one Result-Code AVP or one
- %% Experimental-Result AVP.
-
-+rc_counter(Dict, recv, #diameter_packet{header = H, avps = As}) ->
-+ rc_counter(Dict, [H|As]);
-+
-+rc_counter(Dict, _, #diameter_packet{msg = Msg}) ->
-+ rc_counter(Dict, Msg).
-+
- rc_counter(Dict, Msg) ->
-- rcc(Dict, Msg, int(get_avp_value(Dict, 'Result-Code', Msg))).
-+ rcc(get_result(Dict, Msg)).
-
--rcc(Dict, Msg, undefined) ->
-- rcc(get_avp_value(Dict, 'Experimental-Result', Msg));
--
--rcc(_, _, N)
-+rcc(#diameter_avp{name = 'Result-Code' = Name, value = N} = A)
- when is_integer(N) ->
-- {{'Result-Code', N}, N}.
-+ {{Name, N}, N, A};
-
--%% Outgoing answers may be in any of the forms messages can be sent
--%% in. Incoming messages will be records. We're assuming here that the
--%% arity of the result code AVP's is 0 or 1.
-+rcc(#diameter_avp{name = 'Result-Code' = Name, value = [N|_]} = A)
-+ when is_integer(N) ->
-+ {{Name, N}, N, A};
-
--rcc([{_,_,N} = T | _])
-+rcc(#diameter_avp{name = 'Experimental-Result', value = {_,_,N} = T} = A)
- when is_integer(N) ->
-- {T,N};
--rcc({_,_,N} = T)
-+ {T, N, A};
-+
-+rcc(#diameter_avp{name = 'Experimental-Result', value = [{_,_,N} = T|_]} = A)
- when is_integer(N) ->
-- {T,N};
-+ {T, N, A};
-+
- rcc(_) ->
- false.
-
--%% Extract the first good looking integer. There's no guarantee
--%% that what we're looking for has arity 1.
--int([N|_])
-- when is_integer(N) ->
-- N;
--int(N)
-- when is_integer(N) ->
-- N;
--int(_) ->
-- undefined.
-+%% get_result/2
-+
-+get_result(Dict, Msg) ->
-+ try
-+ [throw(A) || N <- ['Result-Code', 'Experimental-Result'],
-+ #diameter_avp{} = A <- [get_avp(Dict, N, Msg)]]
-+ of
-+ [] -> false
-+ catch
-+ #diameter_avp{} = A -> A
-+ end.
-
- x(T) ->
- exit(T).
-@@ -1528,10 +1520,10 @@ handle_A(Pkt, SvcName, Dict, Dict0, App, #request{transport = TPid} = Req) ->
- %% a missing AVP. If both are optional in the dictionary
- %% then this isn't a decode error: just continue on.
- answer(Pkt, SvcName, App, Req);
-- exit: {invalid_error_bit, {_, _, _, RC}} ->
-+ exit: {invalid_error_bit, {_, _, _, Avp}} ->
- #diameter_packet{errors = Es}
- = Pkt,
-- E = {5004, #diameter_avp{name = 'Result-Code', value = RC}},
-+ E = {5004, Avp},
- answer(Pkt#diameter_packet{errors = [E|Es]}, SvcName, App, Req)
- end.
-
-@@ -1868,7 +1860,7 @@ str([]) ->
- str(T) ->
- T.
-
--%% get_avp_value/3
-+%% get_avp/3
- %%
- %% Find an AVP in a message of one of three forms:
- %%
-@@ -1885,47 +1877,71 @@ str(T) ->
- %% look for are in the common dictionary. This is required since the
- %% relay dictionary doesn't inherit the common dictionary (which maybe
- %% it should).
--get_avp_value(?RELAY, Name, Msg) ->
-- get_avp_value(?BASE, Name, Msg);
-+get_avp(?RELAY, Name, Msg) ->
-+ get_avp(?BASE, Name, Msg);
-
--%% Message sent as a header/avps list, probably a relay case but not
--%% necessarily.
--get_avp_value(Dict, Name, [#diameter_header{} | Avps]) ->
-+%% Message as a header/avps list.
-+get_avp(Dict, Name, [#diameter_header{} | Avps]) ->
- try
- {Code, _, VId} = Dict:avp_header(Name),
-- [A|_] = lists:dropwhile(fun(#diameter_avp{code = C, vendor_id = V}) ->
-- C /= Code orelse V /= VId
-- end,
-- Avps),
-- avp_decode(Dict, Name, A)
-+ find_avp(Code, VId, Avps)
-+ of
-+ A ->
-+ avp_decode(Dict, Name, ungroup(A))
- catch
- error: _ ->
- undefined
- end;
-
- %% Outgoing message as a name/values list.
--get_avp_value(_, Name, [_MsgName | Avps]) ->
-+get_avp(_, Name, [_MsgName | Avps]) ->
- case lists:keyfind(Name, 1, Avps) of
- {_, V} ->
-- V;
-+ #diameter_avp{name = Name, value = V};
- _ ->
- undefined
- end;
-
- %% Message is typically a record but not necessarily.
--get_avp_value(Dict, Name, Rec) ->
-+get_avp(Dict, Name, Rec) ->
- try
-- Dict:'#get-'(Name, Rec)
-+ #diameter_avp{name = Name, value = Dict:'#get-'(Name, Rec)}
- catch
- error:_ ->
- undefined
- end.
-
-+%% get_avp_value/3
-+
-+get_avp_value(Dict, Name, Msg) ->
-+ case get_avp(Dict, Name, Msg) of
-+ #diameter_avp{value = V} ->
-+ V;
-+ undefined = No ->
-+ No
-+ end.
-+
-+%% ungroup/1
-+
-+ungroup([Avp|_]) ->
-+ Avp;
-+ungroup(Avp) ->
-+ Avp.
-+
-+%% avp_decode/3
-+
- avp_decode(Dict, Name, #diameter_avp{value = undefined,
-- data = Bin}) ->
-- Dict:avp(decode, Bin, Name);
--avp_decode(_, _, #diameter_avp{value = V}) ->
-- V.
-+ data = Bin}
-+ = Avp) ->
-+ try Dict:avp(decode, Bin, Name) of
-+ V ->
-+ Avp#diameter_avp{value = V}
-+ catch
-+ error:_ ->
-+ Avp
-+ end;
-+avp_decode(_, _, #diameter_avp{} = Avp) ->
-+ Avp.
-
- cb(#diameter_app{module = [_|_] = M}, F, A) ->
- eval(M, F, A);
-diff --git lib/diameter/src/diameter.appup.src lib/diameter/src/diameter.appup.src
-index a54eb24..0ef0fd3 100644
---- lib/diameter/src/diameter.appup.src
-+++ lib/diameter/src/diameter.appup.src
-@@ -35,32 +35,10 @@
- {"1.4.3", [{restart_application, diameter}]}, %% R16B02
- {"1.4.4", [{restart_application, diameter}]},
- {"1.5", [{restart_application, diameter}]}, %% R16B03
-- {"1.6", [{load_module, diameter_lib}, %% 17.0
-- {load_module, diameter_traffic},
-- {load_module, diameter_watchdog},
-- {load_module, diameter_peer_fsm},
-- {load_module, diameter_service},
-- {load_module, diameter_gen_base_rfc6733},
-- {load_module, diameter_gen_acct_rfc6733},
-- {load_module, diameter_gen_base_rfc3588},
-- {load_module, diameter_gen_base_accounting},
-- {load_module, diameter_gen_relay},
-- {load_module, diameter_codec},
-- {load_module, diameter_sctp}]},
-- {"1.7", [{load_module, diameter_service}, %% 17.1
-- {load_module, diameter_codec},
-- {load_module, diameter_gen_base_rfc6733},
-- {load_module, diameter_gen_acct_rfc6733},
-- {load_module, diameter_gen_base_rfc3588},
-- {load_module, diameter_gen_base_accounting},
-- {load_module, diameter_gen_relay},
-- {load_module, diameter_traffic},
-- {load_module, diameter_peer_fsm}]},
-- {"1.7.1", [{load_module, diameter_traffic}, %% 17.3
-- {load_module, diameter_watchdog},
-- {load_module, diameter_peer_fsm},
-- {load_module, diameter_service}]},
-- {"1.8", [{load_module, diameter_lib}, %% 17.4
-+ {"1.6", [{restart_application, diameter}]}, %% 17.0
-+ {"1.7", [{restart_application, diameter}]}, %% 17.[12]
-+ {<<"^1\\.(7\\.1|8)$">>, %% 17.[34]
-+ [{load_module, diameter_lib},
- {load_module, diameter_peer},
- {load_module, diameter_reg},
- {load_module, diameter_session},
-@@ -84,7 +62,14 @@
- {load_module, diameter_gen_relay},
- {update, diameter_transport_sup, supervisor},
- {update, diameter_service_sup, supervisor},
-- {update, diameter_sup, supervisor}]}
-+ {update, diameter_sup, supervisor}]},
-+ {"1.9", [{load_module, diameter_codec}, %% 17.5
-+ {load_module, diameter_traffic},
-+ {load_module, diameter_gen_base_rfc6733},
-+ {load_module, diameter_gen_acct_rfc6733},
-+ {load_module, diameter_gen_base_rfc3588},
-+ {load_module, diameter_gen_base_accounting},
-+ {load_module, diameter_gen_relay}]}
- ],
- [
- {"0.9", [{restart_application, diameter}]},
-@@ -102,55 +87,40 @@
- {"1.4.3", [{restart_application, diameter}]},
- {"1.4.4", [{restart_application, diameter}]},
- {"1.5", [{restart_application, diameter}]},
-- {"1.6", [{load_module, diameter_sctp},
-- {load_module, diameter_codec},
-+ {"1.6", [{restart_application, diameter}]},
-+ {"1.7", [{restart_application, diameter}]},
-+ {<<"^1\\.(7\\.1|8)$">>,
-+ [{update, diameter_sup, supervisor},
-+ {update, diameter_service_sup, supervisor},
-+ {update, diameter_transport_sup, supervisor},
- {load_module, diameter_gen_relay},
- {load_module, diameter_gen_base_accounting},
- {load_module, diameter_gen_base_rfc3588},
- {load_module, diameter_gen_acct_rfc6733},
- {load_module, diameter_gen_base_rfc6733},
-- {load_module, diameter_service},
-- {load_module, diameter_peer_fsm},
-+ {load_module, diameter},
-+ {load_module, diameter_config},
-+ {load_module, diameter_sctp},
-+ {load_module, diameter_tcp},
- {load_module, diameter_watchdog},
-+ {load_module, diameter_peer_fsm},
-+ {load_module, diameter_service},
- {load_module, diameter_traffic},
-+ {load_module, diameter_types},
-+ {load_module, diameter_codec},
-+ {load_module, diameter_capx},
-+ {load_module, diameter_sync},
-+ {load_module, diameter_stats},
-+ {load_module, diameter_session},
-+ {load_module, diameter_reg},
-+ {load_module, diameter_peer},
- {load_module, diameter_lib}]},
-- {"1.7", [{load_module, diameter_peer_fsm},
-- {load_module, diameter_traffic},
-- {load_module, diameter_gen_relay},
-- {load_module, diameter_gen_base_accounting},
-- {load_module, diameter_gen_base_rfc3588},
-- {load_module, diameter_gen_acct_rfc6733},
-- {load_module, diameter_gen_base_rfc6733},
-- {load_module, diameter_codec},
-- {load_module, diameter_service}]},
-- {"1.7.1", [{load_module, diameter_service},
-- {load_module, diameter_peer_fsm},
-- {load_module, diameter_watchdog},
-- {load_module, diameter_traffic}]},
-- {"1.8", [{update, diameter_sup, supervisor},
-- {update, diameter_service_sup, supervisor},
-- {update, diameter_transport_sup, supervisor},
-- {load_module, diameter_gen_relay},
-+ {"1.9", [{load_module, diameter_gen_relay},
- {load_module, diameter_gen_base_accounting},
- {load_module, diameter_gen_base_rfc3588},
- {load_module, diameter_gen_acct_rfc6733},
- {load_module, diameter_gen_base_rfc6733},
-- {load_module, diameter},
-- {load_module, diameter_config},
-- {load_module, diameter_sctp},
-- {load_module, diameter_tcp},
-- {load_module, diameter_watchdog},
-- {load_module, diameter_peer_fsm},
-- {load_module, diameter_service},
- {load_module, diameter_traffic},
-- {load_module, diameter_types},
-- {load_module, diameter_codec},
-- {load_module, diameter_capx},
-- {load_module, diameter_sync},
-- {load_module, diameter_stats},
-- {load_module, diameter_session},
-- {load_module, diameter_reg},
-- {load_module, diameter_peer},
-- {load_module, diameter_lib}]}
-+ {load_module, diameter_codec}]}
- ]
- }.
-diff --git lib/diameter/test/diameter_3xxx_SUITE.erl lib/diameter/test/diameter_3xxx_SUITE.erl
-index 071b1a1..44fc3a6 100644
---- lib/diameter/test/diameter_3xxx_SUITE.erl
-+++ lib/diameter/test/diameter_3xxx_SUITE.erl
-@@ -47,6 +47,7 @@
- send_double_error/1,
- send_3xxx/1,
- send_5xxx/1,
-+ counters/1,
- stop/1]).
-
- %% diameter callbacks
-@@ -111,7 +112,7 @@ all() ->
-
- groups() ->
- Tc = tc(),
-- [{?util:name([E,D]), [], [start] ++ Tc ++ [stop]}
-+ [{?util:name([E,D]), [], [start] ++ Tc ++ [counters, stop]}
- || E <- ?ERRORS, D <- ?RFCS].
-
- init_per_suite(Config) ->
-@@ -169,6 +170,203 @@ stop(_Config) ->
- ok = diameter:stop_service(?SERVER),
- ok = diameter:stop_service(?CLIENT).
-
-+%% counters/1
-+%%
-+%% Check that counters are as expected.
-+
-+counters(Config) ->
-+ Group = proplists:get_value(group, Config),
-+ [_Errors, _Rfc] = G = ?util:name(Group),
-+ [] = ?util:run([[fun counters/3, K, S, G]
-+ || K <- [statistics, transport, connections],
-+ S <- [?CLIENT, ?SERVER]]).
-+
-+counters(Key, Svc, Group) ->
-+ counters(Key, Svc, Group, [_|_] = diameter:service_info(Svc, Key)).
-+
-+counters(statistics, Svc, [Errors, Rfc], L) ->
-+ [{P, Stats}] = L,
-+ true = is_pid(P),
-+ stats(Svc, Errors, Rfc, lists:sort(Stats));
-+
-+counters(_, _, _, _) ->
-+ todo.
-+
-+stats(?CLIENT, E, rfc3588, L)
-+ when E == answer;
-+ E == answer_3xxx ->
-+ [{{unknown,recv},2},
-+ {{{0,257,0},recv},1},
-+ {{{0,257,1},send},1},
-+ {{{0,275,0},recv},6},
-+ {{{0,275,1},send},10},
-+ {{unknown,recv,{'Result-Code',3001}},1},
-+ {{unknown,recv,{'Result-Code',3007}},1},
-+ {{{0,257,0},recv,{'Result-Code',2001}},1},
-+ {{{0,275,0},recv,{'Result-Code',2001}},1},
-+ {{{0,275,0},recv,{'Result-Code',3008}},2},
-+ {{{0,275,0},recv,{'Result-Code',3999}},1},
-+ {{{0,275,0},recv,{'Result-Code',5002}},1},
-+ {{{0,275,0},recv,{'Result-Code',5005}},1}]
-+ = L;
-+
-+stats(?SERVER, E, rfc3588, L)
-+ when E == answer;
-+ E == answer_3xxx ->
-+ [{{unknown,recv},1},
-+ {{unknown,send},2},
-+ {{{0,257,0},send},1},
-+ {{{0,257,1},recv},1},
-+ {{{0,275,0},send},6},
-+ {{{0,275,1},recv},8},
-+ {{unknown,recv,error},1},
-+ {{unknown,send,{'Result-Code',3001}},1},
-+ {{unknown,send,{'Result-Code',3007}},1},
-+ {{{0,257,0},send,{'Result-Code',2001}},1},
-+ {{{0,275,0},send,{'Result-Code',2001}},1},
-+ {{{0,275,0},send,{'Result-Code',3008}},2},
-+ {{{0,275,0},send,{'Result-Code',3999}},1},
-+ {{{0,275,0},send,{'Result-Code',5002}},1},
-+ {{{0,275,0},send,{'Result-Code',5005}},1},
-+ {{{0,275,1},recv,error},5}]
-+ = L;
-+
-+stats(?CLIENT, answer, rfc6733, L) ->
-+ [{{unknown,recv},2},
-+ {{{0,257,0},recv},1},
-+ {{{0,257,1},send},1},
-+ {{{0,275,0},recv},8},
-+ {{{0,275,1},send},10},
-+ {{unknown,recv,{'Result-Code',3001}},1},
-+ {{unknown,recv,{'Result-Code',3007}},1},
-+ {{{0,257,0},recv,{'Result-Code',2001}},1},
-+ {{{0,275,0},recv,{'Result-Code',3008}},2},
-+ {{{0,275,0},recv,{'Result-Code',3999}},1},
-+ {{{0,275,0},recv,{'Result-Code',5002}},1},
-+ {{{0,275,0},recv,{'Result-Code',5005}},3},
-+ {{{0,275,0},recv,{'Result-Code',5999}},1}]
-+ = L;
-+
-+stats(?SERVER, answer, rfc6733, L) ->
-+ [{{unknown,recv},1},
-+ {{unknown,send},2},
-+ {{{0,257,0},send},1},
-+ {{{0,257,1},recv},1},
-+ {{{0,275,0},send},8},
-+ {{{0,275,1},recv},8},
-+ {{unknown,recv,error},1},
-+ {{unknown,send,{'Result-Code',3001}},1},
-+ {{unknown,send,{'Result-Code',3007}},1},
-+ {{{0,257,0},send,{'Result-Code',2001}},1},
-+ {{{0,275,0},send,{'Result-Code',3008}},2},
-+ {{{0,275,0},send,{'Result-Code',3999}},1},
-+ {{{0,275,0},send,{'Result-Code',5002}},1},
-+ {{{0,275,0},send,{'Result-Code',5005}},3},
-+ {{{0,275,0},send,{'Result-Code',5999}},1},
-+ {{{0,275,1},recv,error},5}]
-+ = L;
-+
-+stats(?CLIENT, answer_3xxx, rfc6733, L) ->
-+ [{{unknown,recv},2},
-+ {{{0,257,0},recv},1},
-+ {{{0,257,1},send},1},
-+ {{{0,275,0},recv},8},
-+ {{{0,275,1},send},10},
-+ {{unknown,recv,{'Result-Code',3001}},1},
-+ {{unknown,recv,{'Result-Code',3007}},1},
-+ {{{0,257,0},recv,{'Result-Code',2001}},1},
-+ {{{0,275,0},recv,{'Result-Code',2001}},1},
-+ {{{0,275,0},recv,{'Result-Code',3008}},2},
-+ {{{0,275,0},recv,{'Result-Code',3999}},1},
-+ {{{0,275,0},recv,{'Result-Code',5002}},1},
-+ {{{0,275,0},recv,{'Result-Code',5005}},2},
-+ {{{0,275,0},recv,{'Result-Code',5999}},1}]
-+ = L;
-+
-+stats(?SERVER, answer_3xxx, rfc6733, L) ->
-+ [{{unknown,recv},1},
-+ {{unknown,send},2},
-+ {{{0,257,0},send},1},
-+ {{{0,257,1},recv},1},
-+ {{{0,275,0},send},8},
-+ {{{0,275,1},recv},8},
-+ {{unknown,recv,error},1},
-+ {{unknown,send,{'Result-Code',3001}},1},
-+ {{unknown,send,{'Result-Code',3007}},1},
-+ {{{0,257,0},send,{'Result-Code',2001}},1},
-+ {{{0,275,0},send,{'Result-Code',2001}},1},
-+ {{{0,275,0},send,{'Result-Code',3008}},2},
-+ {{{0,275,0},send,{'Result-Code',3999}},1},
-+ {{{0,275,0},send,{'Result-Code',5002}},1},
-+ {{{0,275,0},send,{'Result-Code',5005}},2},
-+ {{{0,275,0},send,{'Result-Code',5999}},1},
-+ {{{0,275,1},recv,error},5}]
-+ = L;
-+
-+stats(?CLIENT, callback, rfc3588, L) ->
-+ [{{unknown,recv},1},
-+ {{{0,257,0},recv},1},
-+ {{{0,257,1},send},1},
-+ {{{0,275,0},recv},6},
-+ {{{0,275,1},send},10},
-+ {{unknown,recv,{'Result-Code',3007}},1},
-+ {{{0,257,0},recv,{'Result-Code',2001}},1},
-+ {{{0,275,0},recv,{'Result-Code',2001}},2},
-+ {{{0,275,0},recv,{'Result-Code',3999}},1},
-+ {{{0,275,0},recv,{'Result-Code',5002}},1},
-+ {{{0,275,0},recv,{'Result-Code',5005}},2}]
-+ = L;
-+
-+stats(?SERVER, callback, rfc3588, L) ->
-+ [{{unknown,recv},1},
-+ {{unknown,send},1},
-+ {{{0,257,0},send},1},
-+ {{{0,257,1},recv},1},
-+ {{{0,275,0},send},6},
-+ {{{0,275,1},recv},8},
-+ {{unknown,recv,error},1},
-+ {{unknown,send,{'Result-Code',3007}},1},
-+ {{{0,257,0},send,{'Result-Code',2001}},1},
-+ {{{0,275,0},send,{'Result-Code',2001}},2},
-+ {{{0,275,0},send,{'Result-Code',3999}},1},
-+ {{{0,275,0},send,{'Result-Code',5002}},1},
-+ {{{0,275,0},send,{'Result-Code',5005}},2},
-+ {{{0,275,1},recv,error},5}]
-+ = L;
-+
-+stats(?CLIENT, callback, rfc6733, L) ->
-+ [{{unknown,recv},1},
-+ {{{0,257,0},recv},1},
-+ {{{0,257,1},send},1},
-+ {{{0,275,0},recv},8},
-+ {{{0,275,1},send},10},
-+ {{unknown,recv,{'Result-Code',3007}},1},
-+ {{{0,257,0},recv,{'Result-Code',2001}},1},
-+ {{{0,275,0},recv,{'Result-Code',2001}},2},
-+ {{{0,275,0},recv,{'Result-Code',3999}},1},
-+ {{{0,275,0},recv,{'Result-Code',5002}},1},
-+ {{{0,275,0},recv,{'Result-Code',5005}},3},
-+ {{{0,275,0},recv,{'Result-Code',5999}},1}]
-+ = L;
-+
-+stats(?SERVER, callback, rfc6733, L) ->
-+ [{{unknown,recv},1},
-+ {{unknown,send},1},
-+ {{{0,257,0},send},1},
-+ {{{0,257,1},recv},1},
-+ {{{0,275,0},send},8},
-+ {{{0,275,1},recv},8},
-+ {{unknown,recv,error},1},
-+ {{unknown,send,{'Result-Code',3007}},1},
-+ {{{0,257,0},send,{'Result-Code',2001}},1},
-+ {{{0,275,0},send,{'Result-Code',2001}},2},
-+ {{{0,275,0},send,{'Result-Code',3999}},1},
-+ {{{0,275,0},send,{'Result-Code',5002}},1},
-+ {{{0,275,0},send,{'Result-Code',5005}},3},
-+ {{{0,275,0},send,{'Result-Code',5999}},1},
-+ {{{0,275,1},recv,error},5}]
-+ = L.
-+
- %% send_unknown_application/1
- %%
- %% Send an unknown application that a callback (which shouldn't take
-diff --git lib/diameter/test/diameter_app_SUITE.erl lib/diameter/test/diameter_app_SUITE.erl
-index 6975e83..84f8a66 100644
---- lib/diameter/test/diameter_app_SUITE.erl
-+++ lib/diameter/test/diameter_app_SUITE.erl
-@@ -249,11 +249,10 @@ release() ->
- end.
-
- unversion(App) ->
-- T = lists:dropwhile(fun is_vsn_ch/1, lists:reverse(App)),
-- lists:reverse(case T of [$-|TT] -> TT; _ -> T end).
--
--is_vsn_ch(C) ->
-- $0 =< C andalso C =< $9 orelse $. == C.
-+ {Name, [$-|Vsn]} = lists:splitwith(fun(C) -> C /= $- end, App),
-+ true = is_app(Name), %% assert
-+ Vsn = vsn_str(Vsn), %%
-+ Name.
-
- app('$M_EXPR') -> %% could be anything but assume it's ok
- "erts";
-@@ -322,11 +321,11 @@ acc_rel(Dir, Rel, {Vsn, _}, Acc) ->
-
- %% Write a rel file and return its name.
- write_rel(Dir, [Erts | Apps], Vsn) ->
-- true = is_vsn(Vsn),
-- Name = "diameter_test_" ++ Vsn,
-+ VS = vsn_str(Vsn),
-+ Name = "diameter_test_" ++ VS,
- ok = write_file(filename:join([Dir, Name ++ ".rel"]),
- {release,
-- {"diameter " ++ Vsn ++ " test release", Vsn},
-+ {"diameter " ++ VS ++ " test release", VS},
- Erts,
- Apps}),
- Name.
-@@ -341,10 +340,34 @@ fetch(Key, List) ->
- write_file(Path, T) ->
- file:write_file(Path, io_lib:format("~p.", [T])).
-
--%% Is a version string of the expected form? Return the argument
--%% itself for 'false' for a useful badmatch.
-+%% Is a version string of the expected form?
- is_vsn(V) ->
-- is_list(V)
-- andalso length(V) == string:span(V, "0123456789.")
-- andalso V == string:join(string:tokens(V, [$.]), ".") %% no ".."
-- orelse {error, V}.
-+ V = vsn_str(V),
-+ true.
-+
-+%% Turn a from/to version in appup to a version string after ensuring
-+%% that it's valid version number of regexp. In the regexp case, the
-+%% regexp itself becomes the version string since there's no
-+%% requirement that a version in appup be anything but a string. The
-+%% restrictions placed on string-valued version numbers (that they be
-+%% '.'-separated integers) are our own.
-+
-+vsn_str(S)
-+ when is_list(S) ->
-+ {_, match} = {S, match(S, "^(0|[1-9][0-9]*)(\\.(0|[1-9][0-9]*))*$")},
-+ {_, nomatch} = {S, match(S, "\\.0\\.0$")},
-+ S;
-+
-+vsn_str(B)
-+ when is_binary(B) ->
-+ {ok, _} = re:compile(B),
-+ binary_to_list(B).
-+
-+match(S, RE) ->
-+ re:run(S, RE, [{capture, none}]).
-+
-+%% Is an application name of the expected form?
-+is_app(S)
-+ when is_list(S) ->
-+ {_, match} = {S, match(S, "^([a-z]([a-z_]*|[a-zA-Z]*))$")},
-+ true.
-diff --git lib/diameter/test/diameter_traffic_SUITE.erl lib/diameter/test/diameter_traffic_SUITE.erl
-index 7dd9f39..7ff6ba7 100644
---- lib/diameter/test/diameter_traffic_SUITE.erl
-+++ lib/diameter/test/diameter_traffic_SUITE.erl
-@@ -41,6 +41,7 @@
- send_eval/1,
- send_bad_answer/1,
- send_protocol_error/1,
-+ send_experimental_result/1,
- send_arbitrary/1,
- send_unknown/1,
- send_unknown_short/1,
-@@ -301,6 +302,7 @@ tc() ->
- send_eval,
- send_bad_answer,
- send_protocol_error,
-+ send_experimental_result,
- send_arbitrary,
- send_unknown,
- send_unknown_short,
-@@ -443,7 +445,7 @@ send_ok(Config) ->
- Req = ['ACR', {'Accounting-Record-Type', ?EVENT_RECORD},
- {'Accounting-Record-Number', 1}],
-
-- ['ACA', _SessionId, {'Result-Code', ?SUCCESS} | _]
-+ ['ACA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _]
- = call(Config, Req).
-
- %% Send an accounting ACR that the server answers badly to.
-@@ -459,7 +461,7 @@ send_eval(Config) ->
- Req = ['ACR', {'Accounting-Record-Type', ?EVENT_RECORD},
- {'Accounting-Record-Number', 3}],
-
-- ['ACA', _SessionId, {'Result-Code', ?SUCCESS} | _]
-+ ['ACA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _]
- = call(Config, Req).
-
- %% Send an accounting ACR that the server tries to answer with an
-@@ -480,12 +482,20 @@ send_protocol_error(Config) ->
- ?answer_message(?TOO_BUSY)
- = call(Config, Req).
-
-+%% Send a 3xxx Experimental-Result in an answer not setting the E-bit
-+%% and missing a Result-Code.
-+send_experimental_result(Config) ->
-+ Req = ['ACR', {'Accounting-Record-Type', ?EVENT_RECORD},
-+ {'Accounting-Record-Number', 5}],
-+ ['ACA', {'Session-Id', _} | _]
-+ = call(Config, Req).
-+
- %% Send an ASR with an arbitrary non-mandatory AVP and expect success
- %% and the same AVP in the reply.
- send_arbitrary(Config) ->
- Req = ['ASR', {'AVP', [#diameter_avp{name = 'Product-Name',
- value = "XXX"}]}],
-- ['ASA', _SessionId, {'Result-Code', ?SUCCESS} | Avps]
-+ ['ASA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | Avps]
- = call(Config, Req),
- {'AVP', [#diameter_avp{name = 'Product-Name',
- value = V}]}
-@@ -497,7 +507,7 @@ send_unknown(Config) ->
- Req = ['ASR', {'AVP', [#diameter_avp{code = 999,
- is_mandatory = false,
- data = <<17>>}]}],
-- ['ASA', _SessionId, {'Result-Code', ?SUCCESS} | Avps]
-+ ['ASA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | Avps]
- = call(Config, Req),
- {'AVP', [#diameter_avp{code = 999,
- is_mandatory = false,
-@@ -513,7 +523,7 @@ send_unknown_short(Config, M, RC) ->
- Req = ['ASR', {'AVP', [#diameter_avp{code = 999,
- is_mandatory = M,
- data = <<17>>}]}],
-- ['ASA', _SessionId, {'Result-Code', RC} | Avps]
-+ ['ASA', {'Session-Id', _}, {'Result-Code', RC} | Avps]
- = call(Config, Req),
- [#'diameter_base_Failed-AVP'{'AVP' = As}]
- = proplists:get_value('Failed-AVP', Avps),
-@@ -527,7 +537,7 @@ send_unknown_mandatory(Config) ->
- Req = ['ASR', {'AVP', [#diameter_avp{code = 999,
- is_mandatory = true,
- data = <<17>>}]}],
-- ['ASA', _SessionId, {'Result-Code', ?AVP_UNSUPPORTED} | Avps]
-+ ['ASA', {'Session-Id', _}, {'Result-Code', ?AVP_UNSUPPORTED} | Avps]
- = call(Config, Req),
- [#'diameter_base_Failed-AVP'{'AVP' = As}]
- = proplists:get_value('Failed-AVP', Avps),
-@@ -547,7 +557,7 @@ send_unexpected_mandatory_decode(Config) ->
- Req = ['ASR', {'AVP', [#diameter_avp{code = 27, %% Session-Timeout
- is_mandatory = true,
- data = <<12:32>>}]}],
-- ['ASA', _SessionId, {'Result-Code', ?AVP_UNSUPPORTED} | Avps]
-+ ['ASA', {'Session-Id', _}, {'Result-Code', ?AVP_UNSUPPORTED} | Avps]
- = call(Config, Req),
- [#'diameter_base_Failed-AVP'{'AVP' = As}]
- = proplists:get_value('Failed-AVP', Avps),
-@@ -583,7 +593,7 @@ send_error_bit(Config) ->
- %% Send a bad version and check that we get 5011.
- send_unsupported_version(Config) ->
- Req = ['STR', {'Termination-Cause', ?LOGOUT}],
-- ['STA', _SessionId, {'Result-Code', ?UNSUPPORTED_VERSION} | _]
-+ ['STA', {'Session-Id', _}, {'Result-Code', ?UNSUPPORTED_VERSION} | _]
- = call(Config, Req).
-
- %% Send a request containing an AVP length > data size.
-@@ -603,14 +613,14 @@ send_zero_avp_length(Config) ->
- send_invalid_avp_length(Config) ->
- Req = ['STR', {'Termination-Cause', ?LOGOUT}],
-
-- ['STA', _SessionId,
-+ ['STA', {'Session-Id', _},
- {'Result-Code', ?INVALID_AVP_LENGTH},
-- _OriginHost,
-- _OriginRealm,
-- _UserName,
-- _Class,
-- _ErrorMessage,
-- _ErrorReportingHost,
-+ {'Origin-Host', _},
-+ {'Origin-Realm', _},
-+ {'User-Name', _},
-+ {'Class', _},
-+ {'Error-Message', _},
-+ {'Error-Reporting-Host', _},
- {'Failed-AVP', [#'diameter_base_Failed-AVP'{'AVP' = [_]}]}
- | _]
- = call(Config, Req).
-@@ -628,14 +638,14 @@ send_invalid_reject(Config) ->
- send_unexpected_mandatory(Config) ->
- Req = ['STR', {'Termination-Cause', ?LOGOUT}],
-
-- ['STA', _SessionId, {'Result-Code', ?AVP_UNSUPPORTED} | _]
-+ ['STA', {'Session-Id', _}, {'Result-Code', ?AVP_UNSUPPORTED} | _]
- = call(Config, Req).
-
- %% Send something long that will be fragmented by TCP.
- send_long(Config) ->
- Req = ['STR', {'Termination-Cause', ?LOGOUT},
- {'User-Name', [lists:duplicate(1 bsl 20, $X)]}],
-- ['STA', _SessionId, {'Result-Code', ?SUCCESS} | _]
-+ ['STA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _]
- = call(Config, Req).
-
- %% Send something longer than the configure incoming_maxlen.
-@@ -677,7 +687,7 @@ send_any_2(Config) ->
- send_all_1(Config) ->
- Req = ['STR', {'Termination-Cause', ?LOGOUT}],
- Realm = lists:foldr(fun(C,A) -> [C,A] end, [], ?REALM),
-- ['STA', _SessionId, {'Result-Code', ?SUCCESS} | _]
-+ ['STA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _]
- = call(Config, Req, [{filter, {all, [{host, any},
- {realm, Realm}]}}]).
- send_all_2(Config) ->
-@@ -697,9 +707,8 @@ send_timeout(Config) ->
- %% received the Session-Id.
- send_error(Config) ->
- Req = ['RAR', {'Re-Auth-Request-Type', ?AUTHORIZE_AUTHENTICATE}],
-- ?answer_message(SId, ?TOO_BUSY)
-- = call(Config, Req),
-- true = undefined /= SId.
-+ ?answer_message([_], ?TOO_BUSY)
-+ = call(Config, Req).
-
- %% Send a request with the detached option and receive it as a message
- %% from handle_answer instead.
-@@ -708,7 +717,7 @@ send_detach(Config) ->
- Ref = make_ref(),
- ok = call(Config, Req, [{extra, [{self(), Ref}]}, detach]),
- Ans = receive {Ref, T} -> T end,
-- ['STA', _SessionId, {'Result-Code', ?SUCCESS} | _]
-+ ['STA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _]
- = Ans.
-
- %% Send a request which can't be encoded and expect {error, encode}.
-@@ -721,11 +730,11 @@ send_destination_1(Config) ->
- = group(Config),
- Req = ['STR', {'Termination-Cause', ?LOGOUT},
- {'Destination-Host', [?HOST(SN, ?REALM)]}],
-- ['STA', _SessionId, {'Result-Code', ?SUCCESS} | _]
-+ ['STA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _]
- = call(Config, Req, [{filter, {all, [host, realm]}}]).
- send_destination_2(Config) ->
- Req = ['STR', {'Termination-Cause', ?LOGOUT}],
-- ['STA', _SessionId, {'Result-Code', ?SUCCESS} | _]
-+ ['STA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _]
- = call(Config, Req, [{filter, {all, [host, realm]}}]).
-
- %% Send with filtering on and expect failure when specifying an
-@@ -789,7 +798,7 @@ send_bad_filter(Config, F) ->
- %% Specify multiple filter options and expect them be conjunctive.
- send_multiple_filters_1(Config) ->
- Fun = fun(#diameter_caps{}) -> true end,
-- ['STA', _SessionId, {'Result-Code', ?SUCCESS} | _]
-+ ['STA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _]
- = send_multiple_filters(Config, [host, {eval, Fun}]).
- send_multiple_filters_2(Config) ->
- E = {erlang, is_tuple, []},
-@@ -800,7 +809,7 @@ send_multiple_filters_3(Config) ->
- E2 = {erlang, is_tuple, []},
- E3 = {erlang, is_record, [diameter_caps]},
- E4 = [{erlang, is_record, []}, diameter_caps],
-- ['STA', _SessionId, {'Result-Code', ?SUCCESS} | _]
-+ ['STA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _]
- = send_multiple_filters(Config, [{eval, E} || E <- [E1,E2,E3,E4]]).
-
- send_multiple_filters(Config, Fs) ->
-@@ -811,7 +820,7 @@ send_multiple_filters(Config, Fs) ->
- %% only the return value from the prepare_request callback being
- %% significant.
- send_anything(Config) ->
-- ['STA', _SessionId, {'Result-Code', ?SUCCESS} | _]
-+ ['STA', {'Session-Id', _}, {'Result-Code', ?SUCCESS} | _]
- = call(Config, anything).
-
- %% ===========================================================================
-@@ -1144,6 +1153,13 @@ answer(Pkt, Req, _Peer, Name, #group{client_dict0 = Dict0}) ->
- [R | Vs] = Dict:'#get-'(answer(Ans, Es, Name)),
- [Dict:rec2msg(R) | Vs].
-
-+%% Missing Result-Codec and inapproriate Experimental-Result-Code.
-+answer(Rec, Es, send_experimental_result) ->
-+ [{5004, #diameter_avp{name = 'Experimental-Result'}},
-+ {5005, #diameter_avp{name = 'Result-Code'}}]
-+ = Es,
-+ Rec;
-+
- %% An inappropriate E-bit results in a decode error ...
- answer(Rec, Es, send_bad_answer) ->
- [{5004, #diameter_avp{name = 'Result-Code'}} | _] = Es,
-@@ -1175,7 +1191,9 @@ handle_error(Reason, _Req, [$C|_], _Peer, _, _Time) ->
- %% Note that diameter will set Result-Code and Failed-AVPs if
- %% #diameter_packet.errors is non-null.
-
--handle_request(#diameter_packet{header = H, msg = M}, _, {_Ref, Caps}) ->
-+handle_request(#diameter_packet{header = H, msg = M, avps = As},
-+ _,
-+ {_Ref, Caps}) ->
- #diameter_header{end_to_end_id = EI,
- hop_by_hop_id = HI}
- = H,
-@@ -1183,10 +1201,12 @@ handle_request(#diameter_packet{header = H, msg = M}, _, {_Ref, Caps}) ->
- V = EI bsr B, %% assert
- V = HI bsr B, %%
- #diameter_caps{origin_state_id = {_,[Id]}} = Caps,
-- answer(origin(Id), request(M, Caps)).
-+ answer(origin(Id), request(M, [H|As], Caps)).
-
- answer(T, {Tag, Action, Post}) ->
- {Tag, answer(T, Action), Post};
-+answer(_, {reply, [#diameter_header{} | _]} = T) ->
-+ T;
- answer({A,C}, {reply, Ans}) ->
- answer(C, {reply, msg(Ans, A, diameter_gen_base_rfc3588)});
- answer(pkt, {reply, Ans})
-@@ -1195,6 +1215,41 @@ answer(pkt, {reply, Ans})
- answer(_, T) ->
- T.
-
-+%% request/3
-+
-+%% send_experimental_result
-+request(#diameter_base_accounting_ACR{'Accounting-Record-Number' = 5},
-+ [Hdr | Avps],
-+ #diameter_caps{origin_host = {OH, _},
-+ origin_realm = {OR, _}}) ->
-+ [H,R|T] = [A || N <- ['Origin-Host',
-+ 'Origin-Realm',
-+ 'Session-Id',
-+ 'Accounting-Record-Type',
-+ 'Accounting-Record-Number'],
-+ #diameter_avp{} = A
-+ <- [lists:keyfind(N, #diameter_avp.name, Avps)]],
-+ Ans = [Hdr#diameter_header{is_request = false},
-+ H#diameter_avp{data = OH},
-+ R#diameter_avp{data = OR},
-+ #diameter_avp{name = 'Experimental-Result',
-+ code = 297,
-+ need_encryption = false,
-+ data = [#diameter_avp{data = {?DIAMETER_DICT_COMMON,
-+ 'Vendor-Id',
-+ 123}},
-+ #diameter_avp{data
-+ = {?DIAMETER_DICT_COMMON,
-+ 'Experimental-Result-Code',
-+ 3987}}]}
-+ | T],
-+ {reply, Ans};
-+
-+request(Msg, _Avps, Caps) ->
-+ request(Msg, Caps).
-+
-+%% request/2
-+
- %% send_nok
- request(#diameter_base_accounting_ACR{'Accounting-Record-Number' = 0},
- _) ->
-diff --git lib/diameter/vsn.mk lib/diameter/vsn.mk
-index c00bac2..db7f72c 100644
---- lib/diameter/vsn.mk
-+++ lib/diameter/vsn.mk
-@@ -16,5 +16,5 @@
- # %CopyrightEnd%
-
- APPLICATION = diameter
--DIAMETER_VSN = 1.9
-+DIAMETER_VSN = 1.9.1
- APP_VSN = $(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN)
-diff --git lib/snmp/doc/src/notes.xml lib/snmp/doc/src/notes.xml
-index fd307ef..52022f5 100644
---- lib/snmp/doc/src/notes.xml
-+++ lib/snmp/doc/src/notes.xml
-@@ -33,7 +33,40 @@
- </header>
-
-
-- <section>
-+ <section><title>SNMP 5.1.2</title>
-+
-+ <section><title>Fixed Bugs and Malfunctions</title>
-+ <list>
-+ <item>
-+ <p>
-+ A bug in the SNMP Agent has been corrected; when opening
-+ a port using the command line argument -snmpa_fd the Port
-+ should be 0 when calling gen_udp:open.</p>
-+ <p>
-+ A bug in the SNMP manager has been corrected; it should
-+ not look at the -snmp_fd command line argument, but
-+ instead at -snmpm_fd.</p>
-+ <p>
-+ Own Id: OTP-12669 Aux Id: seq12841 </p>
-+ </item>
-+ </list>
-+ </section>
-+
-+
-+ <section><title>Improvements and New Features</title>
-+ <list>
-+ <item>
-+ <p>
-+ Improved cryptocraphic capability.</p>
-+ <p>
-+ Own Id: OTP-12452</p>
-+ </item>
-+ </list>
-+ </section>
-+
-+</section>
-+
-+<section>
- <title>SNMP Development Toolkit 5.1.1</title>
- <p>Version 5.1.1 supports code replacement in runtime from/to
- version 5.1. </p>
-diff --git lib/snmp/src/agent/snmpa_net_if.erl lib/snmp/src/agent/snmpa_net_if.erl
-index 840d56d..57d63ba 100644
---- lib/snmp/src/agent/snmpa_net_if.erl
-+++ lib/snmp/src/agent/snmpa_net_if.erl
-@@ -1,7 +1,7 @@
- %%
- %% %CopyrightBegin%
- %%
--%% Copyright Ericsson AB 2004-2014. All Rights Reserved.
-+%% Copyright Ericsson AB 2004-2015. 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
-@@ -297,14 +297,14 @@ socket_open(snmpUDPDomain = Domain, [IpPort | Opts]) ->
- Fd = list_to_integer(FdStr),
- ?vdebug("socket_open(~p, [~p | ~p]) Fd: ~p",
- [Domain, IpPort, Opts, Fd]),
-- gen_udp_open(IpPort, [{fd, Fd} | Opts]);
-+ gen_udp_open(0, [{fd, Fd} | Opts]);
- error ->
- case init:get_argument(snmpa_fd) of
- {ok, [[FdStr]]} ->
- Fd = list_to_integer(FdStr),
- ?vdebug("socket_open(~p, [~p | ~p]) Fd: ~p",
- [Domain, IpPort, Opts, Fd]),
-- gen_udp_open(IpPort, [{fd, Fd} | Opts]);
-+ gen_udp_open(0, [{fd, Fd} | Opts]);
- error ->
- ?vdebug("socket_open(~p, [~p | ~p])",
- [Domain, IpPort, Opts]),
-diff --git lib/snmp/src/app/snmp.appup.src lib/snmp/src/app/snmp.appup.src
-index e7e54f5..081163b 100644
---- lib/snmp/src/app/snmp.appup.src
-+++ lib/snmp/src/app/snmp.appup.src
-@@ -1,7 +1,7 @@
- %%
- %% %CopyrightBegin%
- %%
--%% Copyright Ericsson AB 1999-2014. All Rights Reserved.
-+%% Copyright Ericsson AB 1999-2015. 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
-@@ -28,6 +28,7 @@
- %% {update, snmpa_local_db, soft, soft_purge, soft_purge, []}
- %% {add_module, snmpm_net_if_mt}
- [
-+ {"5.1.1", [{restart_application, snmp}]},
- {"5.1", [ % Only compiler changes
- ]},
- {"5.0", [{restart_application, snmp}]},
-@@ -46,6 +47,7 @@
- %% {remove, {snmpm_net_if_mt, soft_purge, soft_purge}}
-
- [
-+ {"5.1.1", [{restart_application, snmp}]},
- {"5.1", [ % Only compiler changes
- ]},
- {"5.0", [{restart_application, snmp}]},
-diff --git lib/snmp/src/manager/snmpm_net_if.erl lib/snmp/src/manager/snmpm_net_if.erl
-index b4cc165..0e1c51c 100644
---- lib/snmp/src/manager/snmpm_net_if.erl
-+++ lib/snmp/src/manager/snmpm_net_if.erl
-@@ -1,7 +1,7 @@
- %%
- %% %CopyrightBegin%
- %%
--%% Copyright Ericsson AB 2004-2014. All Rights Reserved.
-+%% Copyright Ericsson AB 2004-2015. 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
-@@ -330,7 +330,7 @@ socket_params(Domain, {IpAddr, IpPort} = Addr, BindTo, CommonSocketOpts) ->
- end,
- case Family of
- inet ->
-- case init:get_argument(snmp_fd) of
-+ case init:get_argument(snmpm_fd) of
- {ok, [[FdStr]]} ->
- Fd = list_to_integer(FdStr),
- case BindTo of
-diff --git lib/snmp/src/manager/snmpm_server.erl lib/snmp/src/manager/snmpm_server.erl
-index a75122d..8fc3359 100644
---- lib/snmp/src/manager/snmpm_server.erl
-+++ lib/snmp/src/manager/snmpm_server.erl
-@@ -1,7 +1,7 @@
- %%
- %% %CopyrightBegin%
- %%
--%% Copyright Ericsson AB 2004-2014. All Rights Reserved.
-+%% Copyright Ericsson AB 2004-2015. 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
-@@ -2116,7 +2116,8 @@ do_handle_agent(DefUserId, DefMod,
- ok;
-
- InvalidResult ->
-- CallbackArgs = [Domain, Addr, Type, SnmpInfo, DefData],
-+ CallbackArgs =
-+ [Domain_or_Ip, Addr_or_Port, Type, SnmpInfo, DefData],
- handle_invalid_result(handle_agent, CallbackArgs, InvalidResult)
-
- catch
-@@ -2212,7 +2213,8 @@ do_handle_agent(DefUserId, DefMod,
- end;
-
- T:E ->
-- CallbackArgs = [Domain, Addr, Type, SnmpInfo, DefData],
-+ CallbackArgs =
-+ [Domain_or_Ip, Addr_or_Port, Type, SnmpInfo, DefData],
- handle_invalid_result(handle_agent, CallbackArgs, T, E)
-
- end.
-diff --git lib/snmp/vsn.mk lib/snmp/vsn.mk
-index 345cc79..67adf0a 100644
---- lib/snmp/vsn.mk
-+++ lib/snmp/vsn.mk
-@@ -2,7 +2,7 @@
-
- # %CopyrightBegin%
- #
--# Copyright Ericsson AB 1997-2014. All Rights Reserved.
-+# Copyright Ericsson AB 1997-2015. 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
-@@ -18,6 +18,6 @@
- # %CopyrightEnd%
-
- APPLICATION = snmp
--SNMP_VSN = 5.1.1
-+SNMP_VSN = 5.1.2
- PRE_VSN =
- APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)"
-diff --git lib/test_server/doc/src/notes.xml lib/test_server/doc/src/notes.xml
-index f21c32a..e996d2b 100644
---- lib/test_server/doc/src/notes.xml
-+++ lib/test_server/doc/src/notes.xml
-@@ -32,6 +32,28 @@
- <file>notes.xml</file>
- </header>
-
-+<section><title>Test_Server 3.8.1</title>
-+
-+ <section><title>Fixed Bugs and Malfunctions</title>
-+ <list>
-+ <item>
-+ <p>
-+ If the last expression in a test case causes a timetrap
-+ timeout, the stack trace is ignored and not printed to
-+ the test case log file. This happens because the
-+ {Suite,TestCase,Line} info is not available in the stack
-+ trace in this scenario, due to tail call elimination.
-+ Common Test has been modified to handle this situation by
-+ inserting a {Suite,TestCase,last_expr} tuple in the
-+ correct place and printing the stack trace as expected.</p>
-+ <p>
-+ Own Id: OTP-12697 Aux Id: seq12848 </p>
-+ </item>
-+ </list>
-+ </section>
-+
-+</section>
-+
- <section><title>Test_Server 3.8</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
-diff --git lib/test_server/src/erl2html2.erl lib/test_server/src/erl2html2.erl
-index 7cfaa2c..50dbbb8 100644
---- lib/test_server/src/erl2html2.erl
-+++ lib/test_server/src/erl2html2.erl
-@@ -117,9 +117,10 @@ parse_preprocessed_file(Epp,File,InCorrectFile) ->
- parse_preprocessed_file(Epp,File,true);
- {attribute,_,file,{_OtherFile,_}} ->
- parse_preprocessed_file(Epp,File,false);
-- {function,L,F,A,[_|C]} when InCorrectFile ->
-- Clauses = [{clause,CL} || {clause,CL,_,_,_} <- C],
-- [{atom_to_list(F),A,L} | Clauses] ++
-+ {function,L,F,A,Cs} when InCorrectFile ->
-+ {CLs,LastCL} = find_clause_lines(Cs, []),
-+ %% tl(CLs) cause we know the start line already
-+ [{atom_to_list(F),A,L,LastCL} | tl(CLs)] ++
- parse_preprocessed_file(Epp,File,true);
- _ ->
- parse_preprocessed_file(Epp,File,InCorrectFile)
-@@ -146,9 +147,10 @@ parse_non_preprocessed_file(Epp, File, Location) ->
- case epp_dodger:parse_form(Epp, Location) of
- {ok,Tree,Location1} ->
- try erl_syntax:revert(Tree) of
-- {function,L,F,A,[_|C]} ->
-- Clauses = [{clause,CL} || {clause,CL,_,_,_} <- C],
-- [{atom_to_list(F),A,L} | Clauses] ++
-+ {function,L,F,A,Cs} ->
-+ {CLs,LastCL} = find_clause_lines(Cs, []),
-+ %% tl(CLs) cause we know the start line already
-+ [{atom_to_list(F),A,L,LastCL} | tl(CLs)] ++
- parse_non_preprocessed_file(Epp, File, Location1);
- _ ->
- parse_non_preprocessed_file(Epp, File, Location1)
-@@ -162,22 +164,48 @@ parse_non_preprocessed_file(Epp, File, Location) ->
- end.
-
- %%%-----------------------------------------------------------------
-+%%% Find the line number of the last expression in the function
-+find_clause_lines([{clause,CL,_Params,_Op,Exprs}], CLs) -> % last clause
-+ try tuple_to_list(lists:last(Exprs)) of
-+ [_Type,ExprLine | _] ->
-+ {lists:reverse([{clause,CL}|CLs]), ExprLine};
-+ _ ->
-+ {lists:reverse([{clause,CL}|CLs]), CL}
-+ catch
-+ _:_ ->
-+ {lists:reverse([{clause,CL}|CLs]), CL}
-+ end;
-+
-+find_clause_lines([{clause,CL,_Params,_Op,_Exprs} | Cs], CLs) ->
-+ find_clause_lines(Cs, [{clause,CL}|CLs]).
-+
-+%%%-----------------------------------------------------------------
- %%% Add a link target for each line and one for each function definition.
--build_html(SFd,DFd,Encoding,Functions) ->
-- build_html(SFd,DFd,Encoding,file:read_line(SFd),1,Functions,false).
-+build_html(SFd,DFd,Encoding,FuncsAndCs) ->
-+ build_html(SFd,DFd,Encoding,file:read_line(SFd),1,FuncsAndCs,
-+ false,undefined).
-
--build_html(SFd,DFd,Encoding,{ok,Str},L,[{F,A,L}|Functions],_IsFuncDef) ->
-+%% function start line found
-+build_html(SFd,DFd,Enc,{ok,Str},L0,[{F,A,L0,LastL}|FuncsAndCs],
-+ _IsFuncDef,_FAndLastL) ->
- FALink = test_server_ctrl:uri_encode(F++"-"++integer_to_list(A),utf8),
-- file:write(DFd,["<a name=\"",to_raw_list(FALink,Encoding),"\"/>"]),
-- build_html(SFd,DFd,Encoding,{ok,Str},L,Functions,true);
--build_html(SFd,DFd,Encoding,{ok,Str},L,[{clause,L}|Functions],_IsFuncDef) ->
-- build_html(SFd,DFd,Encoding,{ok,Str},L,Functions,true);
--build_html(SFd,DFd,Encoding,{ok,Str},L,Functions,IsFuncDef) ->
-+ file:write(DFd,["<a name=\"",to_raw_list(FALink,Enc),"\"/>"]),
-+ build_html(SFd,DFd,Enc,{ok,Str},L0,FuncsAndCs,true,{F,LastL});
-+%% line of last expression in function found
-+build_html(SFd,DFd,Enc,{ok,Str},LastL,FuncsAndCs,_IsFuncDef,{F,LastL}) ->
-+ LastLineLink = test_server_ctrl:uri_encode(F++"-last_expr",utf8),
-+ file:write(DFd,["<a name=\"",
-+ to_raw_list(LastLineLink,Enc),"\"/>"]),
-+ build_html(SFd,DFd,Enc,{ok,Str},LastL,FuncsAndCs,true,undefined);
-+build_html(SFd,DFd,Enc,{ok,Str},L,[{clause,L}|FuncsAndCs],
-+ _IsFuncDef,FAndLastL) ->
-+ build_html(SFd,DFd,Enc,{ok,Str},L,FuncsAndCs,true,FAndLastL);
-+build_html(SFd,DFd,Enc,{ok,Str},L,FuncsAndCs,IsFuncDef,FAndLastL) ->
- LStr = line_number(L),
- Str1 = line(Str,IsFuncDef),
- file:write(DFd,[LStr,Str1]),
-- build_html(SFd,DFd,Encoding,file:read_line(SFd),L+1,Functions,false);
--build_html(_SFd,_DFd,_Encoding,eof,L,_Functions,_IsFuncDef) ->
-+ build_html(SFd,DFd,Enc,file:read_line(SFd),L+1,FuncsAndCs,false,FAndLastL);
-+build_html(_SFd,_DFd,_Enc,eof,L,_FuncsAndCs,_IsFuncDef,_FAndLastL) ->
- L.
-
- line_number(L) ->
-diff --git lib/test_server/src/test_server.erl lib/test_server/src/test_server.erl
-index 8d91778..1c33525 100644
---- lib/test_server/src/test_server.erl
-+++ lib/test_server/src/test_server.erl
-@@ -1355,12 +1355,30 @@ get_loc(Pid) ->
- Stk = [rewrite_loc_item(Loc) || Loc <- Stk0],
- case get(test_server_loc) of
- [{Suite,Case}] ->
-- %% location info unknown, check if {Suite,Case,Line}
-- %% is available in stacktrace. and if so, use stacktrace
-- %% instead of current test_server_loc
-+ %% Location info unknown, check if {Suite,Case,Line}
-+ %% is available in stacktrace and if so, use stacktrace
-+ %% instead of current test_server_loc.
-+ %% If location is the last expression in a test case
-+ %% function, the info is not available due to tail call
-+ %% elimination. We need to check if the test case has been
-+ %% called by ts_tc/3 and, if so, insert the test case info
-+ %% at that position.
- case [match || {S,C,_L} <- Stk, S == Suite, C == Case] of
-- [match|_] -> put(test_server_loc, Stk);
-- _ -> ok
-+ [match|_] ->
-+ put(test_server_loc, Stk);
-+ _ ->
-+ {PreTC,PostTC} =
-+ lists:splitwith(fun({test_server,ts_tc,_}) ->
-+ false;
-+ (_) ->
-+ true
-+ end, Stk),
-+ if PostTC == [] ->
-+ ok;
-+ true ->
-+ put(test_server_loc,
-+ PreTC++[{Suite,Case,last_expr} | PostTC])
-+ end
- end;
- _ ->
- put(test_server_loc, Stk)
-@@ -1422,7 +1440,10 @@ lookup_config(Key,Config) ->
- undefined
- end.
-
--%% timer:tc/3
-+%%
-+%% IMPORTANT: get_loc/1 uses the name of this function when analysing
-+%% stack traces. If the name changes, get_loc/1 must be updated!
-+%%
- ts_tc(M, F, A) ->
- Before = erlang:now(),
- Result = try
-diff --git lib/test_server/src/test_server_sup.erl lib/test_server/src/test_server_sup.erl
-index 96e369a..15a6fdd 100644
---- lib/test_server/src/test_server_sup.erl
-+++ lib/test_server/src/test_server_sup.erl
-@@ -61,33 +61,37 @@ timetrap(Timeout0, ReportTVal, Scale, Pid) ->
- TruncTO = trunc(Timeout),
- receive
- after TruncTO ->
-- case is_process_alive(Pid) of
-- true ->
-- TimeToReport = if Timeout0 == ReportTVal -> TruncTO;
-- true -> ReportTVal end,
-- MFLs = test_server:get_loc(Pid),
-- Mon = erlang:monitor(process, Pid),
-- Trap = {timetrap_timeout,TimeToReport,MFLs},
-- exit(Pid, Trap),
-- receive
-- {'DOWN', Mon, process, Pid, _} ->
-- ok
-- after 10000 ->
-- %% Pid is probably trapping exits, hit it harder...
-- catch error_logger:warning_msg(
-- "Testcase process ~w not "
-- "responding to timetrap "
-- "timeout:~n"
-- " ~p.~n"
-- "Killing testcase...~n",
-- [Pid, Trap]),
-- exit(Pid, kill)
-- end;
-- false ->
-+ kill_the_process(Pid, Timeout0, TruncTO, ReportTVal)
-+ end.
-+
-+kill_the_process(Pid, Timeout0, TruncTO, ReportTVal) ->
-+ case is_process_alive(Pid) of
-+ true ->
-+ TimeToReport = if Timeout0 == ReportTVal -> TruncTO;
-+ true -> ReportTVal end,
-+ MFLs = test_server:get_loc(Pid),
-+ Mon = erlang:monitor(process, Pid),
-+ Trap = {timetrap_timeout,TimeToReport,MFLs},
-+ exit(Pid, Trap),
-+ receive
-+ {'DOWN', Mon, process, Pid, _} ->
- ok
-- end
-+ after 10000 ->
-+ %% Pid is probably trapping exits, hit it harder...
-+ catch error_logger:warning_msg(
-+ "Testcase process ~w not "
-+ "responding to timetrap "
-+ "timeout:~n"
-+ " ~p.~n"
-+ "Killing testcase...~n",
-+ [Pid, Trap]),
-+ exit(Pid, kill)
-+ end;
-+ false ->
-+ ok
- end.
-
-+
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %% timetrap_cancel(Handle) -> ok
- %% Handle = term()
-@@ -812,10 +816,19 @@ format_loc1({Mod,Func,Line}) ->
- case {lists:member(no_src, get(test_server_logopts)),
- lists:reverse(ModStr)} of
- {false,[$E,$T,$I,$U,$S,$_|_]} ->
-- io_lib:format("{~w,~w,<a href=\"~ts~ts#~w\">~w</a>}",
-+ Link = if is_integer(Line) ->
-+ integer_to_list(Line);
-+ Line == last_expr ->
-+ list_to_atom(atom_to_list(Func)++"-last_expr");
-+ is_atom(Line) ->
-+ atom_to_list(Line);
-+ true ->
-+ Line
-+ end,
-+ io_lib:format("{~w,~w,<a href=\"~ts~ts#~s\">~w</a>}",
- [Mod,Func,
- test_server_ctrl:uri_encode(downcase(ModStr)),
-- ?src_listing_ext,Line,Line]);
-+ ?src_listing_ext,Link,Line]);
- _ ->
- io_lib:format("{~w,~w,~w}",[Mod,Func,Line])
- end.
-diff --git lib/test_server/vsn.mk lib/test_server/vsn.mk
-index 77225b4..2a2ed2b 100644
---- lib/test_server/vsn.mk
-+++ lib/test_server/vsn.mk
-@@ -1 +1 @@
--TEST_SERVER_VSN = 3.8
-+TEST_SERVER_VSN = 3.8.1
-diff --git otp_versions.table otp_versions.table
-index 4bf6cb9..12790c8 100644
---- otp_versions.table
-+++ otp_versions.table
-@@ -1,3 +1,4 @@
-+OTP-17.5.3 : common_test-1.10.1 diameter-1.9.1 erts-6.4.1 snmp-5.1.2 test_server-3.8.1 # asn1-3.0.4 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.7 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 ssh-3.2.2 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
- OTP-17.5.2 : inets-5.10.7 ssh-3.2.2 # asn1-3.0.4 common_test-1.10 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.1 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
- OTP-17.5.1 : ssh-3.2.1 # asn1-3.0.4 common_test-1.10 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.6 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.1 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
- OTP-17.5 : asn1-3.0.4 common_test-1.10 compiler-5.0.4 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9 eldap-1.1.1 erts-6.4 hipe-3.11.3 inets-5.10.6 kernel-3.2 mnesia-4.12.5 observer-2.0.4 os_mon-2.3.1 public_key-0.23 runtime_tools-1.8.16 ssh-3.2 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8 tools-2.7.2 wx-1.3.3 # cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 edoc-0.7.16 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 ic-4.3.6 jinterface-1.5.12 megaco-3.17.3 odbc-2.10.22 orber-3.7.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 reltool-0.6.6 sasl-2.4.1 snmp-5.1.1 typer-0.9.8 webtool-0.8.10 xmerl-1.3.7 :
diff --git a/lang/erlang-runtime17/files/patch-otp-17.5.4 b/lang/erlang-runtime17/files/patch-otp-17.5.4
deleted file mode 100644
index 569ef76e5248..000000000000
--- a/lang/erlang-runtime17/files/patch-otp-17.5.4
+++ /dev/null
@@ -1,306 +0,0 @@
-diff --git OTP_VERSION OTP_VERSION
-index f32d20d..64b493c 100644
---- OTP_VERSION
-+++ OTP_VERSION
-@@ -1 +1 @@
--17.5.3
-+17.5.4
-diff --git lib/inets/doc/src/notes.xml lib/inets/doc/src/notes.xml
-index 12bbc2b..bae8e32 100644
---- lib/inets/doc/src/notes.xml
-+++ lib/inets/doc/src/notes.xml
-@@ -32,7 +32,22 @@
- <file>notes.xml</file>
- </header>
-
-- <section><title>Inets 5.10.7</title>
-+ <section><title>Inets 5.10.8</title>
-+
-+ <section><title>Fixed Bugs and Malfunctions</title>
-+ <list>
-+ <item>
-+ <p>
-+ Reject messages with a Content-Length less than 0</p>
-+ <p>
-+ Own Id: OTP-12739 Aux Id: seq12860 </p>
-+ </item>
-+ </list>
-+ </section>
-+
-+</section>
-+
-+<section><title>Inets 5.10.7</title>
-
- <section><title>Improvements and New Features</title>
- <list>
-diff --git lib/inets/src/http_server/httpd_request.erl lib/inets/src/http_server/httpd_request.erl
-index 6985065..3ff0761 100644
---- lib/inets/src/http_server/httpd_request.erl
-+++ lib/inets/src/http_server/httpd_request.erl
-@@ -417,8 +417,12 @@ check_header({"content-length", Value}, Maxsizes) ->
- case length(Value) =< MaxLen of
- true ->
- try
-- _ = list_to_integer(Value),
-- ok
-+ list_to_integer(Value)
-+ of
-+ I when I>= 0 ->
-+ ok;
-+ _ ->
-+ {error, {size_error, Max, 411, "negative content-length"}}
- catch _:_ ->
- {error, {size_error, Max, 411, "content-length not an integer"}}
- end;
-diff --git lib/inets/vsn.mk lib/inets/vsn.mk
-index e9ecb26..ecb84e4 100644
---- lib/inets/vsn.mk
-+++ lib/inets/vsn.mk
-@@ -18,6 +18,6 @@
- # %CopyrightEnd%
-
- APPLICATION = inets
--INETS_VSN = 5.10.7
-+INETS_VSN = 5.10.8
- PRE_VSN =
- APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
-diff --git lib/ssh/doc/src/notes.xml lib/ssh/doc/src/notes.xml
-index 41885c6..579a3ae 100644
---- lib/ssh/doc/src/notes.xml
-+++ lib/ssh/doc/src/notes.xml
-@@ -29,6 +29,25 @@
- <file>notes.xml</file>
- </header>
-
-+<section><title>Ssh 3.2.3</title>
-+
-+ <section><title>Fixed Bugs and Malfunctions</title>
-+ <list>
-+ <item>
-+ <p>
-+ A new option for handling the SSH_MSG_DEBUG message's
-+ printouts. A fun could be given in the options that will
-+ be called whenever the SSH_MSG_DEBUG message arrives.
-+ This enables the user to format the printout or just
-+ discard it.</p>
-+ <p>
-+ Own Id: OTP-12738 Aux Id: seq12860 </p>
-+ </item>
-+ </list>
-+ </section>
-+
-+</section>
-+
- <section><title>Ssh 3.2.2</title>
-
- <section><title>Improvements and New Features</title>
-diff --git lib/ssh/doc/src/ssh.xml lib/ssh/doc/src/ssh.xml
-index 72dafc0..501668c 100644
---- lib/ssh/doc/src/ssh.xml
-+++ lib/ssh/doc/src/ssh.xml
-@@ -201,6 +201,14 @@
- <tag><c><![CDATA[{idle_time, integer()}]]></c></tag>
- <item>
- <p>Sets a timeout on connection when no channels are active, default is infinity</p></item>
-+
-+ <tag><c><![CDATA[{ssh_msg_debug_fun, fun(ConnectionRef::ssh_connection_ref(), AlwaysDisplay::boolean(), Msg::binary(), LanguageTag::binary()) -> _}]]></c></tag>
-+ <item>
-+ <p>Provide a fun to implement your own logging of the SSH message SSH_MSG_DEBUG. The last three parameters are from the message, see RFC4253, section 11.3. The <c>ConnectionRef</c> is the reference to the connection on which the message arrived. The return value from the fun is not checked.</p>
-+ <p>The default behaviour is ignore the message.
-+ To get a printout for each message with <c>AlwaysDisplay = true</c>, use for example <c>{ssh_msg_debug_fun, fun(_,true,M,_)-> io:format("DEBUG: ~p~n", [M]) end}</c></p>
-+ </item>
-+
- </taglist>
- </desc>
- </func>
-@@ -383,8 +391,16 @@
- <item>
- <p>Provide a fun to implement your own logging when a user disconnects from the server.</p>
- </item>
-- </taglist>
-- </desc>
-+
-+ <tag><c><![CDATA[{ssh_msg_debug_fun, fun(ConnectionRef::ssh_connection_ref(), AlwaysDisplay::boolean(), Msg::binary(), LanguageTag::binary()) -> _}]]></c></tag>
-+ <item>
-+ <p>Provide a fun to implement your own logging of the SSH message SSH_MSG_DEBUG. The last three parameters are from the message, see RFC4253, section 11.3. The <c>ConnectionRef</c> is the reference to the connection on which the message arrived. The return value from the fun is not checked.</p>
-+ <p>The default behaviour is ignore the message.
-+ To get a printout for each message with <c>AlwaysDisplay = true</c>, use for example <c>{ssh_msg_debug_fun, fun(_,true,M,_)-> io:format("DEBUG: ~p~n", [M]) end}</c></p>
-+ </item>
-+
-+ </taglist>
-+ </desc>
- </func>
-
-
-diff --git lib/ssh/src/ssh.erl lib/ssh/src/ssh.erl
-index d4b02a0..71e7d77 100644
---- lib/ssh/src/ssh.erl
-+++ lib/ssh/src/ssh.erl
-@@ -312,6 +312,8 @@ handle_option([{disconnectfun, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
- handle_option([{failfun, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-+handle_option([{ssh_msg_debug_fun, _} = Opt | Rest], SocketOptions, SshOptions) ->
-+ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
- %%Backwards compatibility should not be underscore between ip and v6 in API
- handle_option([{ip_v6_disabled, Value} | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option({ipv6_disabled, Value}) | SshOptions]);
-@@ -417,6 +419,8 @@ handle_ssh_option({disconnectfun , Value} = Opt) when is_function(Value) ->
- Opt;
- handle_ssh_option({failfun, Value} = Opt) when is_function(Value) ->
- Opt;
-+handle_ssh_option({ssh_msg_debug_fun, Value} = Opt) when is_function(Value,4) ->
-+ Opt;
-
- handle_ssh_option({ipv6_disabled, Value} = Opt) when is_boolean(Value) ->
- throw({error, {{ipv6_disabled, Opt}, option_no_longer_valid_use_inet_option_instead}});
-diff --git lib/ssh/src/ssh_connection_handler.erl lib/ssh/src/ssh_connection_handler.erl
-index e1f2e05..0f6162d 100644
---- lib/ssh/src/ssh_connection_handler.erl
-+++ lib/ssh/src/ssh_connection_handler.erl
-@@ -580,12 +580,12 @@ handle_event(#ssh_msg_disconnect{description = Desc} = DisconnectMsg, _StateName
- handle_event(#ssh_msg_ignore{}, StateName, State) ->
- {next_state, StateName, next_packet(State)};
-
--handle_event(#ssh_msg_debug{always_display = true, message = DbgMsg},
-- StateName, State) ->
-- io:format("DEBUG: ~p\n", [DbgMsg]),
-- {next_state, StateName, next_packet(State)};
--
--handle_event(#ssh_msg_debug{}, StateName, State) ->
-+handle_event(#ssh_msg_debug{always_display = Display, message = DbgMsg, language=Lang},
-+ StateName, #state{opts = Opts} = State) ->
-+ F = proplists:get_value(ssh_msg_debug_fun, Opts,
-+ fun(_ConnRef, _AlwaysDisplay, _Msg, _Language) -> ok end
-+ ),
-+ catch F(self(), Display, DbgMsg, Lang),
- {next_state, StateName, next_packet(State)};
-
- handle_event(#ssh_msg_unimplemented{}, StateName, State) ->
-diff --git lib/ssh/test/ssh_basic_SUITE.erl lib/ssh/test/ssh_basic_SUITE.erl
-index f5f8991..fa7b426 100644
---- lib/ssh/test/ssh_basic_SUITE.erl
-+++ lib/ssh/test/ssh_basic_SUITE.erl
-@@ -52,6 +52,8 @@ all() ->
- ssh_connect_arg4_timeout,
- packet_size_zero,
- ssh_daemon_minimal_remote_max_packet_size_option,
-+ ssh_msg_debug_fun_option_client,
-+ ssh_msg_debug_fun_option_server,
- id_string_no_opt_client,
- id_string_own_string_client,
- id_string_random_client,
-@@ -494,6 +496,94 @@ server_userpassword_option(Config) when is_list(Config) ->
- ssh:stop_daemon(Pid).
-
- %%--------------------------------------------------------------------
-+ssh_msg_debug_fun_option_client() ->
-+ [{doc, "validate client that uses the 'ssh_msg_debug_fun' option"}].
-+ssh_msg_debug_fun_option_client(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"},
-+ {failfun, fun ssh_test_lib:failfun/2}]),
-+ Parent = self(),
-+ DbgFun = fun(ConnRef,Displ,Msg,Lang) -> Parent ! {msg_dbg,{ConnRef,Displ,Msg,Lang}} end,
-+
-+ ConnectionRef =
-+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
-+ {user, "foo"},
-+ {password, "morot"},
-+ {user_dir, UserDir},
-+ {user_interaction, false},
-+ {ssh_msg_debug_fun,DbgFun}]),
-+ %% Beware, implementation knowledge:
-+ gen_fsm:send_all_state_event(ConnectionRef,{ssh_msg_debug,false,<<"Hello">>,<<>>}),
-+ receive
-+ {msg_dbg,X={ConnectionRef,false,<<"Hello">>,<<>>}} ->
-+ ct:log("Got expected dbg msg ~p",[X]),
-+ ssh:stop_daemon(Pid);
-+ {msg_dbg,X={_,false,<<"Hello">>,<<>>}} ->
-+ ct:log("Got dbg msg but bad ConnectionRef (~p expected) ~p",[ConnectionRef,X]),
-+ ssh:stop_daemon(Pid),
-+ {fail, "Bad ConnectionRef received"};
-+ {msg_dbg,X} ->
-+ ct:log("Got bad dbg msg ~p",[X]),
-+ ssh:stop_daemon(Pid),
-+ {fail,"Bad msg received"}
-+ after 1000 ->
-+ ssh:stop_daemon(Pid),
-+ {fail,timeout}
-+ end.
-+
-+%%--------------------------------------------------------------------
-+ssh_msg_debug_fun_option_server() ->
-+ [{doc, "validate client that uses the 'ssh_msg_debug_fun' option"}].
-+ssh_msg_debug_fun_option_server(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),
-+
-+ Parent = self(),
-+ DbgFun = fun(ConnRef,Displ,Msg,Lang) -> Parent ! {msg_dbg,{ConnRef,Displ,Msg,Lang}} end,
-+ ConnFun = fun(_,_,_) -> Parent ! {connection_pid,self()} end,
-+
-+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
-+ {user_dir, UserDir},
-+ {password, "morot"},
-+ {failfun, fun ssh_test_lib:failfun/2},
-+ {connectfun, ConnFun},
-+ {ssh_msg_debug_fun, DbgFun}]),
-+ _ConnectionRef =
-+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
-+ {user, "foo"},
-+ {password, "morot"},
-+ {user_dir, UserDir},
-+ {user_interaction, false}]),
-+ receive
-+ {connection_pid,Server} ->
-+ %% Beware, implementation knowledge:
-+ gen_fsm:send_all_state_event(Server,{ssh_msg_debug,false,<<"Hello">>,<<>>}),
-+ receive
-+ {msg_dbg,X={_,false,<<"Hello">>,<<>>}} ->
-+ ct:log("Got expected dbg msg ~p",[X]),
-+ ssh:stop_daemon(Pid);
-+ {msg_dbg,X} ->
-+ ct:log("Got bad dbg msg ~p",[X]),
-+ ssh:stop_daemon(Pid),
-+ {fail,"Bad msg received"}
-+ after 3000 ->
-+ ssh:stop_daemon(Pid),
-+ {fail,timeout2}
-+ end
-+ after 3000 ->
-+ ssh:stop_daemon(Pid),
-+ {fail,timeout1}
-+ end.
-+
-+%%--------------------------------------------------------------------
- known_hosts() ->
- [{doc, "check that known_hosts is updated correctly"}].
- known_hosts(Config) when is_list(Config) ->
-diff --git lib/ssh/vsn.mk lib/ssh/vsn.mk
-index b2b85a7..40bda0c 100644
---- lib/ssh/vsn.mk
-+++ lib/ssh/vsn.mk
-@@ -1,4 +1,4 @@
- #-*-makefile-*- ; force emacs to enter makefile-mode
-
--SSH_VSN = 3.2.2
-+SSH_VSN = 3.2.3
- APP_VSN = "ssh-$(SSH_VSN)"
-diff --git otp_versions.table otp_versions.table
-index 12790c8..fbed2ce 100644
---- otp_versions.table
-+++ otp_versions.table
-@@ -1,3 +1,4 @@
-+OTP-17.5.4 : inets-5.10.8 ssh-3.2.3 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9.1 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4.1 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.2 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
- OTP-17.5.3 : common_test-1.10.1 diameter-1.9.1 erts-6.4.1 snmp-5.1.2 test_server-3.8.1 # asn1-3.0.4 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.7 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 ssh-3.2.2 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
- OTP-17.5.2 : inets-5.10.7 ssh-3.2.2 # asn1-3.0.4 common_test-1.10 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.1 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
- OTP-17.5.1 : ssh-3.2.1 # asn1-3.0.4 common_test-1.10 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.6 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.1 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :