From 41ea592967c208b610c256010f8b6ff77462a996 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonatan=20K=C5=82osko?=
Date: Mon, 15 Jul 2024 18:09:31 +0700
Subject: [PATCH 001/217] Move -epmd_module and -erl_epmd_port into kernel
parameters
---
erts/doc/references/erl_cmd.md | 15 ++++-----
erts/preloaded/src/init.erl | 3 --
lib/kernel/doc/kernel_app.md | 20 ++++++++++++
lib/kernel/src/erl_epmd.erl | 56 +++++++++++++++++++-------------
lib/kernel/src/net_kernel.erl | 21 ++++++++----
lib/observer/src/observer_wx.erl | 15 ++++-----
6 files changed, 83 insertions(+), 47 deletions(-)
diff --git a/erts/doc/references/erl_cmd.md b/erts/doc/references/erl_cmd.md
index 41edffcd2f4d..2406a1ce5181 100644
--- a/erts/doc/references/erl_cmd.md
+++ b/erts/doc/references/erl_cmd.md
@@ -252,14 +252,13 @@ described in the corresponding application documentation.
In this example, an Erlang runtime system is started with environment variable
`DISPLAY` set to `gin:0`.
-- **`-epmd_module Module` (init flag)** - Configures the module responsible to
- communicate to [epmd](epmd_cmd.md). Defaults to `erl_epmd`.
-
-- **`-erl_epmd_port Port` (init flag)** - Configures the port used by `erl_epmd`
- to listen for connection and connect to other nodes. If this flag is set,
- the Erlang VM will boot in distributed mode even if EPMD is not available.
- If not set, a port is chosen automatically (equivalent to port `0`).
- See `m:erl_epmd` for more details.
+- **`-epmd_module Module`{: #epmd_module }** - This flag is deprecated and has
+ been replaced by the `kernel` application parameter
+ [`epmd_module`](`e:kernel:kernel_app.md#epmd_module`).
+
+- **`-erl_epmd_port Port`{: #erl_epmd_port }** - This flag is deprecated and
+ has been replaced by the `kernel` application parameter
+ [`erl_epmd_listen_port`](`e:kernel:kernel_app.md#erl_epmd_listen_port`).
- **`-eval Expr` (init flag)** - Makes `init` evaluate the expression `Expr`;
see `m:init`.
diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl
index 7e5e8bb15214..143208a6cb54 100644
--- a/erts/preloaded/src/init.erl
+++ b/erts/preloaded/src/init.erl
@@ -90,9 +90,6 @@ The `init` module interprets the following command-line flags:
It defaults to `strict` from OTP 27 and this option is scheduled for removal
in OTP 28.
-- **`-epmd_module Module`** - Specifies the module to use for registration and
- lookup of node names. Defaults to `erl_epmd`.
-
- **`-eval Expr`** - Scans, parses, and evaluates an arbitrary expression `Expr`
during system initialization. If any of these steps fail (syntax error, parse
error, or exception during evaluation), Erlang stops with an error message. In
diff --git a/lib/kernel/doc/kernel_app.md b/lib/kernel/doc/kernel_app.md
index 432d67882369..fe3ad6682660 100644
--- a/lib/kernel/doc/kernel_app.md
+++ b/lib/kernel/doc/kernel_app.md
@@ -130,6 +130,26 @@ For more information about configuration parameters, see file
node. If a node goes down, it must thereafter be explicitly connected. See
`m:net_kernel`.
+- **`epmd_module = module()`{: #epmd_module }** - Configures the module
+ responsible for communication with [epmd](epmd_cmd.md). If this parameter
+ is undefined, it defaults to `erl_epmd`.
+
+ The now deprecated command line argument
+ [`-epmd_module `](`e:erts:erl_cmd.md#epmd_module`) has the same
+ effect as the `epmd_module` configuration parameter. If this configuration
+ parameter is defined, it will override the command line argument.
+
+- **`erl_epmd_listen_port = integer()`** - Configures the port used by `m:erl_epmd`
+ to listen for connection and connect to other nodes. If this flag is set, the
+ Erlang VM will boot in distributed mode even if EPMD is not available. If not
+ set, a port is chosen automatically (equivalent to port `0`). See `m:erl_epmd`
+ for more details.
+
+ The now deprecated command line argument
+ [`erl_epmd_port `](`e:erts:erl_cmd.md#erl_epmd_port`) has the same
+ effect as the `erl_epmd_listen_port` configuration parameter. If this
+ configuration parameter is defined, it will override the command line argument.
+
- **`permissions = [Perm]`{: #permissions }** - Specifies the default permission
for applications when they are started. In this parameter:
diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl
index aedbec8871d4..f6ecb5a05e80 100644
--- a/lib/kernel/src/erl_epmd.erl
+++ b/lib/kernel/src/erl_epmd.erl
@@ -164,14 +164,9 @@ to when accepting new distribution requests.
Host :: atom() | string() | inet:ip_address(),
Port :: non_neg_integer().
listen_port_please(_Name, _Host) ->
- try
- %% Should come up with a new name for this as ERL_EPMD_PORT describes what
- %% port epmd runs on which could easily be confused with this.
- {ok, [[StringPort]]} = init:get_argument(erl_epmd_port),
- Port = list_to_integer(StringPort),
- {ok, Port}
- catch error:_ ->
- {ok, 0}
+ case erl_epmd_listen_port() of
+ {ok, Port} -> {ok, Port};
+ undefined -> {ok, 0}
end.
-doc false.
@@ -291,26 +286,26 @@ init(_) ->
handle_call({register, Name, PortNo, Family}, _From, State) ->
case State#state.socket of
- P when P < 0 ->
- case do_register_node(Name, PortNo, Family) of
- {alive, Socket, Creation} ->
- S = State#state{socket = Socket,
- port_no = PortNo,
- name = Name,
- family = Family},
- {reply, {ok, Creation}, S};
+ P when P < 0 ->
+ case do_register_node(Name, PortNo, Family) of
+ {alive, Socket, Creation} ->
+ S = State#state{socket = Socket,
+ port_no = PortNo,
+ name = Name,
+ family = Family},
+ {reply, {ok, Creation}, S};
Error ->
- case init:get_argument(erl_epmd_port) of
+ case erl_epmd_listen_port() of
{ok, _} ->
{reply, {ok, -1}, State#state{ socket = -1,
port_no = PortNo,
name = Name} };
- error ->
+ undefined ->
{reply, Error, State}
end
- end;
- _ ->
- {reply, {error, already_registered}, State}
+ end;
+ _ ->
+ {reply, {error, already_registered}, State}
end;
handle_call(client_info_req, _From, State) ->
@@ -378,7 +373,24 @@ get_epmd_port() ->
error ->
?erlang_daemon_port
end.
-
+
+erl_epmd_listen_port() ->
+ case application:get_env(kernel, erl_epmd_listen_port) of
+ {ok, Port} when is_integer(Port), Port >= 0 ->
+ {ok, Port};
+ {ok, Invalid} ->
+ error({invalid_parameter_value, erl_epmd_listen_port, Invalid});
+ undefined ->
+ try
+ {ok, [[StringPort]]} = init:get_argument(erl_epmd_port),
+ Port = list_to_integer(StringPort),
+ ok = application:set_env(kernel, erl_epmd_listen_port, Port, [{timeout, infinity}]),
+ {ok, Port}
+ catch error:_ ->
+ undefined
+ end
+ end.
+
%%
%% Epmd socket
%%
diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl
index f99e847c10cd..630e4c9e6ed4 100644
--- a/lib/kernel/src/net_kernel.erl
+++ b/lib/kernel/src/net_kernel.erl
@@ -2423,11 +2423,21 @@ protocol_childspecs([H|T]) ->
-doc false.
epmd_module() ->
- case init:get_argument(epmd_module) of
- {ok,[[Module | _] | _]} ->
- list_to_atom(Module);
- _ ->
- erl_epmd
+ case application:get_env(kernel, epmd_module) of
+ {ok, Module} when is_atom(Module) ->
+ Module;
+ {ok, Invalid} ->
+ error({invalid_parameter_value, epmd_module, Invalid});
+ undefined ->
+ Module =
+ case init:get_argument(epmd_module) of
+ {ok,[[Mod | _] | _]} ->
+ list_to_atom(Mod);
+ _ ->
+ erl_epmd
+ end,
+ ok = application:set_env(kernel, epmd_module, Module, [{timeout, infinity}]),
+ Module
end.
%%
@@ -3011,4 +3021,3 @@ opts_node(Op, Node, Opts, From, #state{req_map = ReqMap0} = S0) ->
_ ->
async_reply({reply, {error, noconnection}, S0}, From)
end.
-
diff --git a/lib/observer/src/observer_wx.erl b/lib/observer/src/observer_wx.erl
index 07833fb50ea5..14276672fce0 100644
--- a/lib/observer/src/observer_wx.erl
+++ b/lib/observer/src/observer_wx.erl
@@ -776,12 +776,13 @@ get_nodes() ->
%% see erl_epmd:(listen_)port_please/2
erl_dist_port() ->
- try
- erl_epmd = net_kernel:epmd_module(),
- {ok, [[StringPort]]} = init:get_argument(erl_epmd_port),
- list_to_integer(StringPort)
- catch
- _:_ ->
+ case net_kernel:epmd_module() of
+ erl_epmd ->
+ case erl_epmd:listen_port_please(nonode, nohost) of
+ {ok, 0} -> undefined;
+ {ok, Port} -> Port
+ end;
+ _ ->
undefined
end.
@@ -903,5 +904,3 @@ filter_nodedown_messages(Node) ->
%% io:format("[owx] " ++ F ++ "~n", A);
%% d(_, _, _) ->
%% ok.
-
-
From d12c223dde8783b601e166cad102ca86956e7aee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonatan=20K=C5=82osko?=
Date: Thu, 8 Aug 2024 23:04:51 +0900
Subject: [PATCH 002/217] erl_epmd_listen_port -> erl_epmd_node_listen_port
---
erts/doc/references/erl_cmd.md | 2 +-
lib/kernel/doc/kernel_app.md | 4 ++--
lib/kernel/src/erl_epmd.erl | 12 ++++++------
3 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/erts/doc/references/erl_cmd.md b/erts/doc/references/erl_cmd.md
index 2406a1ce5181..f2ac3e037280 100644
--- a/erts/doc/references/erl_cmd.md
+++ b/erts/doc/references/erl_cmd.md
@@ -258,7 +258,7 @@ described in the corresponding application documentation.
- **`-erl_epmd_port Port`{: #erl_epmd_port }** - This flag is deprecated and
has been replaced by the `kernel` application parameter
- [`erl_epmd_listen_port`](`e:kernel:kernel_app.md#erl_epmd_listen_port`).
+ [`erl_epmd_node_listen_port`](`e:kernel:kernel_app.md#erl_epmd_node_listen_port`).
- **`-eval Expr` (init flag)** - Makes `init` evaluate the expression `Expr`;
see `m:init`.
diff --git a/lib/kernel/doc/kernel_app.md b/lib/kernel/doc/kernel_app.md
index fe3ad6682660..e31d4aa705bd 100644
--- a/lib/kernel/doc/kernel_app.md
+++ b/lib/kernel/doc/kernel_app.md
@@ -139,7 +139,7 @@ For more information about configuration parameters, see file
effect as the `epmd_module` configuration parameter. If this configuration
parameter is defined, it will override the command line argument.
-- **`erl_epmd_listen_port = integer()`** - Configures the port used by `m:erl_epmd`
+- **`erl_epmd_node_listen_port = integer()`** - Configures the port used by `m:erl_epmd`
to listen for connection and connect to other nodes. If this flag is set, the
Erlang VM will boot in distributed mode even if EPMD is not available. If not
set, a port is chosen automatically (equivalent to port `0`). See `m:erl_epmd`
@@ -147,7 +147,7 @@ For more information about configuration parameters, see file
The now deprecated command line argument
[`erl_epmd_port `](`e:erts:erl_cmd.md#erl_epmd_port`) has the same
- effect as the `erl_epmd_listen_port` configuration parameter. If this
+ effect as the `erl_epmd_node_listen_port` configuration parameter. If this
configuration parameter is defined, it will override the command line argument.
- **`permissions = [Perm]`{: #permissions }** - Specifies the default permission
diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl
index f6ecb5a05e80..b2c611ba581f 100644
--- a/lib/kernel/src/erl_epmd.erl
+++ b/lib/kernel/src/erl_epmd.erl
@@ -164,7 +164,7 @@ to when accepting new distribution requests.
Host :: atom() | string() | inet:ip_address(),
Port :: non_neg_integer().
listen_port_please(_Name, _Host) ->
- case erl_epmd_listen_port() of
+ case erl_epmd_node_listen_port() of
{ok, Port} -> {ok, Port};
undefined -> {ok, 0}
end.
@@ -295,7 +295,7 @@ handle_call({register, Name, PortNo, Family}, _From, State) ->
family = Family},
{reply, {ok, Creation}, S};
Error ->
- case erl_epmd_listen_port() of
+ case erl_epmd_node_listen_port() of
{ok, _} ->
{reply, {ok, -1}, State#state{ socket = -1,
port_no = PortNo,
@@ -374,17 +374,17 @@ get_epmd_port() ->
?erlang_daemon_port
end.
-erl_epmd_listen_port() ->
- case application:get_env(kernel, erl_epmd_listen_port) of
+erl_epmd_node_listen_port() ->
+ case application:get_env(kernel, erl_epmd_node_listen_port) of
{ok, Port} when is_integer(Port), Port >= 0 ->
{ok, Port};
{ok, Invalid} ->
- error({invalid_parameter_value, erl_epmd_listen_port, Invalid});
+ error({invalid_parameter_value, erl_epmd_node_listen_port, Invalid});
undefined ->
try
{ok, [[StringPort]]} = init:get_argument(erl_epmd_port),
Port = list_to_integer(StringPort),
- ok = application:set_env(kernel, erl_epmd_listen_port, Port, [{timeout, infinity}]),
+ ok = application:set_env(kernel, erl_epmd_node_listen_port, Port, [{timeout, infinity}]),
{ok, Port}
catch error:_ ->
undefined
From d0004ebd44091eb7517b4fef334ae1f2f9668767 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonatan=20K=C5=82osko?=
Date: Thu, 8 Aug 2024 23:28:39 +0900
Subject: [PATCH 003/217] Add deprecation to init docs
---
erts/preloaded/src/init.erl | 3 +++
1 file changed, 3 insertions(+)
diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl
index 143208a6cb54..3f03c689262a 100644
--- a/erts/preloaded/src/init.erl
+++ b/erts/preloaded/src/init.erl
@@ -90,6 +90,9 @@ The `init` module interprets the following command-line flags:
It defaults to `strict` from OTP 27 and this option is scheduled for removal
in OTP 28.
+- **`-epmd_module Module`** - This flag is deprecated and has been replaced by
+ the `kernel` application parameter [`epmd_module`](`e:kernel:kernel_app.md#epmd_module`).
+
- **`-eval Expr`** - Scans, parses, and evaluates an arbitrary expression `Expr`
during system initialization. If any of these steps fail (syntax error, parse
error, or exception during evaluation), Erlang stops with an error message. In
From 2684d90003559b74fe6f9ea889d99a4a2c9ef91f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonatan=20K=C5=82osko?=
Date: Mon, 12 Aug 2024 17:12:33 +0900
Subject: [PATCH 004/217] Update deprecations list
---
system/doc/general_info/deprecations_27.md | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/system/doc/general_info/deprecations_27.md b/system/doc/general_info/deprecations_27.md
index 80bd06cd56a2..a1ad5a93db54 100644
--- a/system/doc/general_info/deprecations_27.md
+++ b/system/doc/general_info/deprecations_27.md
@@ -14,3 +14,13 @@ The following features for archives are deprecated:
Using a single archive file for holding BEAM files and other data
files in an Escript is **not** deprecated. However, to access files in
the archive the `escript:extract/2` function has to be used.
+
+### erl flags
+
+The following erl flags are deprecated:
+
+* `-epmd_module Module` - deprecated in favour of the `kernel` application
+ parameter `epmd_module`.
+
+* `-erl_epmd_port Port` - deprecated in favour of the `kernel` application
+ parameter `erl_epmd_node_listen_port`.
From 1479c86823175831e379afe95b075fe9d146833b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonatan=20K=C5=82osko?=
Date: Mon, 26 Aug 2024 14:26:38 +0200
Subject: [PATCH 005/217] Update lib/kernel/doc/kernel_app.md
Co-authored-by: Lukas Larsson
---
lib/kernel/doc/kernel_app.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/kernel/doc/kernel_app.md b/lib/kernel/doc/kernel_app.md
index e31d4aa705bd..a4b2f6ccb545 100644
--- a/lib/kernel/doc/kernel_app.md
+++ b/lib/kernel/doc/kernel_app.md
@@ -131,7 +131,7 @@ For more information about configuration parameters, see file
`m:net_kernel`.
- **`epmd_module = module()`{: #epmd_module }** - Configures the module
- responsible for communication with [epmd](epmd_cmd.md). If this parameter
+ responsible for communication with [epmd](`e:erts:erl_cmd.md`). If this parameter
is undefined, it defaults to `erl_epmd`.
The now deprecated command line argument
From 754fb55fcee032d1bead0f43fa71cb36b636fb26 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonatan=20K=C5=82osko?=
Date: Mon, 26 Aug 2024 14:37:12 +0200
Subject: [PATCH 006/217] Update lib/kernel/doc/kernel_app.md
---
lib/kernel/doc/kernel_app.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/kernel/doc/kernel_app.md b/lib/kernel/doc/kernel_app.md
index a4b2f6ccb545..f432639498c3 100644
--- a/lib/kernel/doc/kernel_app.md
+++ b/lib/kernel/doc/kernel_app.md
@@ -131,7 +131,7 @@ For more information about configuration parameters, see file
`m:net_kernel`.
- **`epmd_module = module()`{: #epmd_module }** - Configures the module
- responsible for communication with [epmd](`e:erts:erl_cmd.md`). If this parameter
+ responsible for communication with [epmd](`e:erts:epmd_cmd.md`). If this parameter
is undefined, it defaults to `erl_epmd`.
The now deprecated command line argument
From fbe65e9ccfa2d19b2106b707b3139f548442fcee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonatan=20K=C5=82osko?=
Date: Thu, 29 Aug 2024 22:35:40 +0900
Subject: [PATCH 007/217] Crash when both erl flags and kernel parameter are
set
---
lib/kernel/src/erl_epmd.erl | 34 ++++++++++++++++++++-------------
lib/kernel/src/net_kernel.erl | 36 ++++++++++++++++++++---------------
2 files changed, 42 insertions(+), 28 deletions(-)
diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl
index b2c611ba581f..b204860e3051 100644
--- a/lib/kernel/src/erl_epmd.erl
+++ b/lib/kernel/src/erl_epmd.erl
@@ -375,20 +375,28 @@ get_epmd_port() ->
end.
erl_epmd_node_listen_port() ->
- case application:get_env(kernel, erl_epmd_node_listen_port) of
- {ok, Port} when is_integer(Port), Port >= 0 ->
- {ok, Port};
- {ok, Invalid} ->
- error({invalid_parameter_value, erl_epmd_node_listen_port, Invalid});
- undefined ->
- try
- {ok, [[StringPort]]} = init:get_argument(erl_epmd_port),
- Port = list_to_integer(StringPort),
- ok = application:set_env(kernel, erl_epmd_node_listen_port, Port, [{timeout, infinity}]),
- {ok, Port}
- catch error:_ ->
+ PortParameterResult =
+ case application:get_env(kernel, erl_epmd_node_listen_port) of
+ {ok, Port} when is_integer(Port), Port >= 0 ->
+ {ok, Port};
+ {ok, Invalid} ->
+ error({invalid_parameter_value, erl_epmd_node_listen_port, Invalid});
+ undefined ->
undefined
- end
+ end,
+ PortArgumentResult =
+ try
+ {ok, [[StringPort]]} = init:get_argument(erl_epmd_port),
+ IntPort = list_to_integer(StringPort),
+ {ok, IntPort}
+ catch error:_ ->
+ undefined
+ end,
+ case {PortParameterResult, PortArgumentResult} of
+ {undefined, undefined} -> undefined;
+ {_, undefined} -> PortParameterResult;
+ {undefined, _} -> PortArgumentResult;
+ _ -> error({invalid_configuration, "either -erl_epmd_port or kernel erl_epmd_node_listen_port should be specified, not both"})
end.
%%
diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl
index 630e4c9e6ed4..954e23ee850c 100644
--- a/lib/kernel/src/net_kernel.erl
+++ b/lib/kernel/src/net_kernel.erl
@@ -2423,21 +2423,27 @@ protocol_childspecs([H|T]) ->
-doc false.
epmd_module() ->
- case application:get_env(kernel, epmd_module) of
- {ok, Module} when is_atom(Module) ->
- Module;
- {ok, Invalid} ->
- error({invalid_parameter_value, epmd_module, Invalid});
- undefined ->
- Module =
- case init:get_argument(epmd_module) of
- {ok,[[Mod | _] | _]} ->
- list_to_atom(Mod);
- _ ->
- erl_epmd
- end,
- ok = application:set_env(kernel, epmd_module, Module, [{timeout, infinity}]),
- Module
+ ModuleParameterResult =
+ case application:get_env(kernel, epmd_module) of
+ {ok, Module} when is_atom(Module) ->
+ {ok, Module};
+ {ok, Invalid} ->
+ error({invalid_parameter_value, epmd_module, Invalid});
+ undefined ->
+ undefined
+ end,
+ ModuleArgumentResult =
+ case init:get_argument(epmd_module) of
+ {ok,[[Mod | _] | _]} ->
+ {ok, list_to_atom(Mod)};
+ _ ->
+ undefined
+ end,
+ case {ModuleParameterResult, ModuleArgumentResult} of
+ {undefined, undefined} -> erl_epmd;
+ {{ok, ModuleParameter}, undefined} -> ModuleParameter;
+ {undefined, {ok, ModuleArgument}} -> ModuleArgument;
+ _ -> error({invalid_configuration, "either -epmd_module or kernel epmd_module should be specified, not both"})
end.
%%
From 1714f2fac38efd869e91fe1ee9c0e54969430fcd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonatan=20K=C5=82osko?=
Date: Fri, 30 Aug 2024 00:01:59 +0900
Subject: [PATCH 008/217] Add missing anchor
---
lib/kernel/doc/kernel_app.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/kernel/doc/kernel_app.md b/lib/kernel/doc/kernel_app.md
index f432639498c3..4984a350ab70 100644
--- a/lib/kernel/doc/kernel_app.md
+++ b/lib/kernel/doc/kernel_app.md
@@ -139,7 +139,7 @@ For more information about configuration parameters, see file
effect as the `epmd_module` configuration parameter. If this configuration
parameter is defined, it will override the command line argument.
-- **`erl_epmd_node_listen_port = integer()`** - Configures the port used by `m:erl_epmd`
+- **`erl_epmd_node_listen_port = integer()`{: #erl_epmd_node_listen_port }** - Configures the port used by `m:erl_epmd`
to listen for connection and connect to other nodes. If this flag is set, the
Erlang VM will boot in distributed mode even if EPMD is not available. If not
set, a port is chosen automatically (equivalent to port `0`). See `m:erl_epmd`
From 4b0ef3f79643dc038d1cbf34740a9aabccb97a4e Mon Sep 17 00:00:00 2001
From: Maas-Maarten Zeeman
Date: Tue, 3 Sep 2024 15:10:47 +0200
Subject: [PATCH 009/217] os_mon: Fix use available mem for
system_memory_high_watermark alarm
---
lib/os_mon/c_src/memsup.c | 13 +++++++++----
lib/os_mon/test/memsup_SUITE.erl | 3 +++
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/lib/os_mon/c_src/memsup.c b/lib/os_mon/c_src/memsup.c
index 96f662da1940..ad4a193d99ba 100644
--- a/lib/os_mon/c_src/memsup.c
+++ b/lib/os_mon/c_src/memsup.c
@@ -446,9 +446,10 @@ get_extended_mem_apple(memory_ext *me) {
}
me->free = vm_stat.free_count * mach_page_size;
+ me->available = (vm_stat.inactive_count + vm_stat.free_count) * mach_page_size;
me->total = total_memory_size;
me->pagesize = 1;
- me->flag = F_MEM_TOTAL | F_MEM_FREE;
+ me->flag = F_MEM_TOTAL | F_MEM_FREE | F_MEM_AVAIL;
}
#endif
@@ -508,7 +509,11 @@ get_basic_mem(unsigned long *tot, unsigned long *used, unsigned long *pagesize){
}
*tot = me.total;
*pagesize = me.pagesize;
- *used = me.total - me.free;
+ if (me.flag & F_MEM_AVAIL) {
+ *used = me.total - me.available;
+ } else {
+ *used = me.total - me.free;
+ }
#elif defined(BSD4_4)
struct vmtotal vt;
long pgsz;
@@ -535,9 +540,9 @@ get_basic_mem(unsigned long *tot, unsigned long *used, unsigned long *pagesize){
#elif defined(__APPLE__)
{
memory_ext me;
- me.free = 0;
+ me.available = 0;
get_extended_mem_apple(&me);
- *used = me.total - me.free;
+ *used = me.total - me.available;
*tot = total_memory_size;
*pagesize = 1;
}
diff --git a/lib/os_mon/test/memsup_SUITE.erl b/lib/os_mon/test/memsup_SUITE.erl
index 1f66ea0afac4..262d3a669625 100644
--- a/lib/os_mon/test/memsup_SUITE.erl
+++ b/lib/os_mon/test/memsup_SUITE.erl
@@ -758,6 +758,9 @@ improved_system_memory_data(Config) when is_list(Config) ->
_ ->
{comment, "No available_memory present in result"}
end;
+ {unix,darwin} ->
+ true = AvailableMemoryPresent,
+ {comment, "available_memory present in result"};
_ ->
ok
end.
From 4d8871f93a296f1dbebb7bf46c22c6f353d250f2 Mon Sep 17 00:00:00 2001
From: Micael Karlberg
Date: Mon, 2 Sep 2024 15:32:09 +0200
Subject: [PATCH 010/217] [inet-drv] Add debug printouts for getifaddrs
---
erts/emulator/drivers/common/inet_drv.c | 53 +++++++++++++++++++++++--
1 file changed, 50 insertions(+), 3 deletions(-)
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index dbdc29310e36..15cf9cd20cf3 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -145,10 +145,25 @@
#define D2S(__D__) (((__D__) == INET_DELIVER_PORT) ? "port" : \
(((__D__) == INET_DELIVER_TERM) ? "term" : \
"undefined"))
-#define DOM2S(__D__) (((__D__) == INET_AF_INET) ? "inet" : \
- (((__D__) == INET_AF_INET6) ? "inet6" : \
- (((__D__) == INET_AF_LOCAL) ? "local" : \
+#define DOM2S(__D__) (((__D__) == INET_AF_INET) ? "inet" : \
+ (((__D__) == INET_AF_INET6) ? "inet6" : \
+ (((__D__) == INET_AF_LOCAL) ? "local" : \
"undefined")))
+#if defined(AF_LINK)
+#define FAM2S(__F__) (((__F__) == AF_INET) ? "inet" : \
+ (((__F__) == AF_INET6) ? "inet6" : \
+ (((__F__) == AF_LINK) ? "link" : \
+ "undefined")))
+#elif defined(AF_PACKET)
+#define FAM2S(__F__) (((__F__) == AF_INET) ? "inet" : \
+ (((__F__) == AF_INET6) ? "inet6" : \
+ (((__F__) == AF_PACKET) ? "packet" : \
+ "undefined")))
+#else
+#define FAM2S(__F__) (((__F__) == AF_INET) ? "inet" : \
+ (((__F__) == AF_INET6) ? "inet6" : \
+ "undefined"))
+#endif
#if defined(__WIN32__) && defined(ARCH_64)
#define SOCKET_FSTR "%lld"
@@ -6586,6 +6601,12 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p,
} \
} while (0)
+ DDBG(desc_p,
+ ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] "
+ "%s -> get if addrs"
+ "\r\n",
+ __LINE__, desc_p->s, driver_caller(desc_p->port), __FUNCTION__) );
+
if ((save_errno = call_getifaddrs(desc_p, &ifa_p)) != 0)
return ctl_error(save_errno, rbuf_pp, rsize);
@@ -6593,6 +6614,15 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p,
*buf_p++ = INET_REP_OK;
for (; ifa_p; ifa_p = ifa_p->ifa_next) {
int len = utf8_len(ifa_p->ifa_name, -1);
+
+ DDBG(desc_p,
+ ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] "
+ "%s -> process if-addr %s"
+ "\r\n flags: 0x%X"
+ "\r\n",
+ __LINE__, desc_p->s, driver_caller(desc_p->port), __FUNCTION__,
+ ifa_p->ifa_name, ifa_p->ifa_flags) );
+
BUF_ENSURE(len+1 + 1+4 + 1);
utf8_encode(ifa_p->ifa_name, -1, buf_p);
buf_p += len;
@@ -6600,6 +6630,15 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p,
*buf_p++ = INET_IFOPT_FLAGS;
put_int32(IFGET_FLAGS(ifa_p->ifa_flags), buf_p); buf_p += 4;
if (ifa_p->ifa_addr) {
+
+ DDBG(desc_p,
+ ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] "
+ "%s -> family: %d (%s)"
+ "\r\n",
+ __LINE__, desc_p->s, driver_caller(desc_p->port), __FUNCTION__,
+ ifa_p->ifa_addr->sa_family,
+ FAM2S(ifa_p->ifa_addr->sa_family)) );
+
if (ifa_p->ifa_addr->sa_family == AF_INET
#if defined(AF_INET6)
|| ifa_p->ifa_addr->sa_family == AF_INET6
@@ -6647,6 +6686,14 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p,
/* buf_p is now unreliable */
freeifaddrs(ifa_free_p);
*rbuf_pp = buf_alloc_p;
+
+ DDBG(desc_p,
+ ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] "
+ "%s -> done when buffer size: %d"
+ "\r\n",
+ __LINE__, desc_p->s, driver_caller(desc_p->port), __FUNCTION__,
+ buf_size) );
+
return buf_size;
# undef BUF_ENSURE
}
From 08fea31d83a1650756b28d180b22e22b1dee3c99 Mon Sep 17 00:00:00 2001
From: Lukas Larsson
Date: Fri, 30 Aug 2024 15:48:00 +0200
Subject: [PATCH 011/217] erts: Require both stdin and stdout to be ttys to
restore
If stdout is not a tty, then it might be a program that does its own
alterations of the tty which means that we should not touch it and
leave restoration to that program.
Closes #8487
---
erts/emulator/sys/unix/erl_child_setup.c | 6 +++---
erts/emulator/sys/unix/sys.c | 2 +-
erts/emulator/sys/unix/sys_drivers.c | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/erts/emulator/sys/unix/erl_child_setup.c b/erts/emulator/sys/unix/erl_child_setup.c
index 72a7f77b2e6c..317bf8cfe977 100644
--- a/erts/emulator/sys/unix/erl_child_setup.c
+++ b/erts/emulator/sys/unix/erl_child_setup.c
@@ -528,7 +528,7 @@ main(int argc, char *argv[])
SET_CLOEXEC(uds_fd);
- if (isatty(0)) {
+ if (isatty(0) && isatty(1)) {
ssize_t res = read_all(uds_fd, (char*)&initial_tty_mode, sizeof(struct termios));
if (res <= 0) {
ABORT("Failed to read initial_tty_mode: %d (%d)", res, errno);
@@ -560,7 +560,7 @@ main(int argc, char *argv[])
pipes, 3, MSG_DONTWAIT)) < 0) {
if (errno == EINTR)
continue;
- if (isatty(0)) {
+ if (isatty(0) && isatty(1)) {
tcsetattr(0,TCSANOW,&initial_tty_mode);
}
DEBUG_PRINT("erl_child_setup failed to read from uds: %d, %d", res, errno);
@@ -569,7 +569,7 @@ main(int argc, char *argv[])
if (res == 0) {
DEBUG_PRINT("uds was closed!");
- if (isatty(0)) {
+ if (isatty(0) && isatty(1)) {
tcsetattr(0,TCSANOW,&initial_tty_mode);
}
_exit(0);
diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c
index ba5ba255d495..a512f1d9977a 100644
--- a/erts/emulator/sys/unix/sys.c
+++ b/erts/emulator/sys/unix/sys.c
@@ -182,7 +182,7 @@ void sys_tty_reset(int exit_code)
if (using_oldshell && !replace_intr) {
SET_BLOCKING(0);
}
- else if (isatty(0)) {
+ else if (isatty(0) && isatty(1)) {
tcsetattr(0,TCSANOW,&erl_sys_initial_tty_mode);
}
}
diff --git a/erts/emulator/sys/unix/sys_drivers.c b/erts/emulator/sys/unix/sys_drivers.c
index 75a545782fb8..952adc0dfdc8 100644
--- a/erts/emulator/sys/unix/sys_drivers.c
+++ b/erts/emulator/sys/unix/sys_drivers.c
@@ -1666,7 +1666,7 @@ static ErlDrvData forker_start(ErlDrvPort port_num, char* name,
/* If stdin is a tty then we need to restore its settings when we exit.
So we send the tty mode to erl_child_setup so that it can cleanup
in case the emulator is terminated with SIGKILL. */
- if (isatty(0)) {
+ if (isatty(0) && isatty(1)) {
ssize_t res, pos = 0;
size_t size = sizeof(struct termios);
byte *buff = (byte *)&erl_sys_initial_tty_mode;
From 85edb09c595336388737b3beed24f82cb39aaa57 Mon Sep 17 00:00:00 2001
From: Sverker Eriksson
Date: Tue, 10 Sep 2024 17:54:11 +0200
Subject: [PATCH 012/217] crypto: Workaround fips bug causing RAND_bytes to
fail
Symtom:
RAND_bytes fails on Ubuntu pro with fips enabled.
Problem:
init_curve_types() switched FIPS mode off and on again (and generates
random keys) which seem to cause RAND_bytes to fail accessing its
fips provider.
Solution:
Remove init_curve_types() call at init as this check will be done
by get_curve_cnt() anyway first time crypto:supports(curves) is called.
---
lib/crypto/c_src/algorithms.c | 42 +++++------------------------------
1 file changed, 5 insertions(+), 37 deletions(-)
diff --git a/lib/crypto/c_src/algorithms.c b/lib/crypto/c_src/algorithms.c
index c7e1fdea0436..578f79e4f1f1 100644
--- a/lib/crypto/c_src/algorithms.c
+++ b/lib/crypto/c_src/algorithms.c
@@ -39,8 +39,7 @@ void init_pubkey_types(ErlNifEnv* env);
static ERL_NIF_TERM algo_curve[2][89]; /* increase when extending the list */
static ErlNifMutex* mtx_init_curve_types;
-void init_curve_types(ErlNifEnv* env);
-int get_curve_cnt(ErlNifEnv* env, int fips);
+static int get_curve_cnt(ErlNifEnv* env, int fips);
static unsigned int algo_rsa_opts_cnt, algo_rsa_opts_fips_cnt;
static ERL_NIF_TERM algo_rsa_opts[11]; /* increase when extending the list */
@@ -56,7 +55,6 @@ void init_algorithms_types(ErlNifEnv* env)
init_hash_types(env);
#endif
init_pubkey_types(env);
- init_curve_types(env);
init_rsa_opts_types(env);
/* ciphers and macs are initiated statically */
}
@@ -230,9 +228,9 @@ ERL_NIF_TERM curve_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
return enif_make_list_from_array(env, algo_curve[fips_mode], algo_curve_cnt);
}
-int init_curves(ErlNifEnv* env, int fips);
+static int init_curves(ErlNifEnv* env, int fips);
#if defined(HAVE_EC)
-int valid_curve(int nid);
+static int valid_curve(int nid);
#endif
int get_curve_cnt(ErlNifEnv* env, int fips) {
@@ -266,38 +264,6 @@ int get_curve_cnt(ErlNifEnv* env, int fips) {
return cnt;
}
-void init_curve_types(ErlNifEnv* env) {
- /* Initialize the curve counters and curve's lists
- by calling get_curve_cnt
- */
-#ifdef FIPS_SUPPORT
- if (FIPS_MODE()) {
- // FIPS enabled
- get_curve_cnt(env, 1);
- FIPS_mode_set(0); // disable
- get_curve_cnt(env, 0);
- FIPS_mode_set(1); // re-enable
- } else {
- // FIPS disabled but available
- get_curve_cnt(env, 0);
- FIPS_mode_set(1); // enable
- get_curve_cnt(env, 1);
- FIPS_mode_set(0); // re-disable
- }
-#else
- // FIPS mode is not available
- get_curve_cnt(env, 0);
-#endif
-
-# ifdef DEBUG
- {
- int curve_cnt = get_curve_cnt(env, 0);
- ASSERT(curve_cnt <= sizeof(algo_curve[0])/sizeof(ERL_NIF_TERM));
- }
-# endif
-}
-
-
int init_curves(ErlNifEnv* env, int fips) {
#if defined(HAVE_EC)
int cnt = 0;
@@ -647,6 +613,8 @@ int init_curves(ErlNifEnv* env, int fips) {
#endif
}
+ ASSERT(cnt <= sizeof(algo_curve[0])/sizeof(ERL_NIF_TERM));
+
return cnt;
#else /* if not HAVE_EC */
return 0;
From edbf3ebd0c26f3e781e6014faf3fc3b36fe06286 Mon Sep 17 00:00:00 2001
From: Jakub Witczak
Date: Wed, 11 Sep 2024 16:55:27 +0200
Subject: [PATCH 013/217] stdlib: customize unlink_flush for noproc scenario
- handle termination race in supervisor
- race happens when supervisor shutdown procedure
- collides with child terminating from other reason
-
- in ssh tests this happens when client closes connection
- which propagates to server over network
- and results with termination of connection processes on server side
- in parallel, server being is shutdown during test cleanup
---
lib/stdlib/src/supervisor.erl | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index 23aac8b9e1d7..9b8c64edbf8c 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -1521,16 +1521,25 @@ shutdown(#child{pid=Pid, shutdown=Time} = Child) ->
end
end.
-unlink_flush(Pid, DefaultReason) ->
- %% We call unlink in order to guarantee that the 'EXIT' has arrived
- %% from the dead process. See the unlink docs for details.
+unlink_flush(Pid, noproc) ->
+ {links, Ls} = process_info(self(),links),
+ Timeout = case lists:member(Pid, Ls) of
+ true -> infinity;
+ false -> 0
+ end,
+ receive
+ {'EXIT', Pid, ExitReason} ->
+ ExitReason
+ after Timeout ->
+ naughty_child
+ end;
+unlink_flush(Pid, ExitReason) ->
unlink(Pid),
receive
- {'EXIT', Pid, Reason} ->
- Reason
- after 0 ->
- DefaultReason
- end.
+ {'EXIT', Pid, _} -> ok
+ after 0 -> ok
+ end,
+ ExitReason.
%%-----------------------------------------------------------------
%% Func: terminate_dynamic_children/1
From 09605ff543481f1df004993b9b1afd3808bff85b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20H=C3=B6gberg?=
Date: Mon, 16 Sep 2024 14:24:55 +0200
Subject: [PATCH 014/217] jit: Check pending stubs in i_bs_create_bin
---
erts/emulator/beam/jit/arm/instr_bs.cpp | 4 +
erts/emulator/test/bs_construct_SUITE.erl | 271 +++++++++++++++++++++-
2 files changed, 272 insertions(+), 3 deletions(-)
diff --git a/erts/emulator/beam/jit/arm/instr_bs.cpp b/erts/emulator/beam/jit/arm/instr_bs.cpp
index 0bdaad1744ce..a1814fc94c14 100644
--- a/erts/emulator/beam/jit/arm/instr_bs.cpp
+++ b/erts/emulator/beam/jit/arm/instr_bs.cpp
@@ -2598,6 +2598,8 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgLabel &Fail,
break;
}
}
+
+ check_pending_stubs();
}
/* Allocate the binary. */
@@ -3243,6 +3245,8 @@ void BeamModuleAssembler::emit_i_bs_create_bin(const ArgLabel &Fail,
} else if (std::gcd(seg.unit, 8) != 8) {
is_byte_aligned = false;
}
+
+ check_pending_stubs();
}
comment("done");
diff --git a/erts/emulator/test/bs_construct_SUITE.erl b/erts/emulator/test/bs_construct_SUITE.erl
index 9a8da0bafc43..9c110b9dd007 100644
--- a/erts/emulator/test/bs_construct_SUITE.erl
+++ b/erts/emulator/test/bs_construct_SUITE.erl
@@ -31,8 +31,8 @@
bs_append_offheap/1,
reductions/1, fp16/1, zero_init/1, error_info/1, little/1,
heap_binary_unit/1,
- otp_24_code_gh_8238/1
- ]).
+ otp_24_code_gh_8238/1,
+ many_segments/1]).
-include_lib("common_test/include/ct.hrl").
@@ -48,7 +48,8 @@ all() ->
bad_append, bs_append_overflow, bs_append_offheap,
reductions, fp16, zero_init,
error_info, little, heap_binary_unit,
- otp_24_code_gh_8238].
+ otp_24_code_gh_8238,
+ many_segments].
init_per_suite(Config) ->
Config.
@@ -1730,6 +1731,270 @@ otp_24_code_gh_8238(Config) ->
{skip,"Enough to run once"}
end.
+%% GH-8815: Binary construction with "too many" segments failed to JIT on ARM.
+many_segments(_Config) ->
+ Val = id(<<"fhqwhgads">>),
+ id(<<"COL_A,COL_B\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n", Val/binary, ",B0\n",
+ Val/binary, ",B0\n">>),
+ ok.
+
%%%
%%% Common utilities.
%%%
From 900242e6538b064d95bcc9b7147605eb3ab72e96 Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Wed, 18 Sep 2024 08:52:11 +0200
Subject: [PATCH 015/217] Update copyright year
---
lib/diameter/src/base/diameter_internal.hrl | 2 +-
lib/diameter/src/base/diameter_lib.erl | 2 +-
lib/diameter/test/Makefile | 2 +-
lib/diameter/test/diameter_config_SUITE.erl | 2 +-
lib/diameter/test/diameter_event_SUITE.erl | 2 +-
lib/public_key/src/public_key.erl | 2 +-
lib/public_key/test/public_key_SUITE.erl | 2 +-
lib/ssh/src/ssh_acceptor.erl | 2 +-
lib/ssh/src/ssh_connection_handler.erl | 2 +-
lib/xmerl/src/xmerl.erl | 2 +-
lib/xmerl/src/xmerl_html.erl | 2 +-
lib/xmerl/src/xmerl_lib.erl | 2 +-
lib/xmerl/src/xmerl_otpsgml.erl | 2 +-
lib/xmerl/src/xmerl_sgml.erl | 2 +-
lib/xmerl/src/xmerl_text.erl | 2 +-
lib/xmerl/src/xmerl_xml.erl | 2 +-
lib/xmerl/test/xmerl_SUITE.erl | 2 +-
17 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/lib/diameter/src/base/diameter_internal.hrl b/lib/diameter/src/base/diameter_internal.hrl
index 0ac626696a31..3f4c958c7b03 100644
--- a/lib/diameter/src/base/diameter_internal.hrl
+++ b/lib/diameter/src/base/diameter_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2024. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/diameter/src/base/diameter_lib.erl b/lib/diameter/src/base/diameter_lib.erl
index 6dfdcc334afc..623877310803 100644
--- a/lib/diameter/src/base/diameter_lib.erl
+++ b/lib/diameter/src/base/diameter_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2024. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile
index e124ae7a6a5f..7e78730bf8ed 100644
--- a/lib/diameter/test/Makefile
+++ b/lib/diameter/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2022. All Rights Reserved.
+# Copyright Ericsson AB 2010-2024. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/diameter/test/diameter_config_SUITE.erl b/lib/diameter/test/diameter_config_SUITE.erl
index 86c98d038194..ff2c64fc65b9 100644
--- a/lib/diameter/test/diameter_config_SUITE.erl
+++ b/lib/diameter/test/diameter_config_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2022. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2024. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/diameter/test/diameter_event_SUITE.erl b/lib/diameter/test/diameter_event_SUITE.erl
index 2a391311da7e..c28da58d2f93 100644
--- a/lib/diameter/test/diameter_event_SUITE.erl
+++ b/lib/diameter/test/diameter_event_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2022. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2024. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 94f1bad405fe..8f2a33a0b2c0 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2023. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2024. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index d1f2cc1da368..ee3c6177c8b3 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2023. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2024. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index 33aecfff12b0..ff0f0dfe5abc 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2021. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2024. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 0e7e8884e2a2..91a5e2b20e79 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2023. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2024. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/xmerl/src/xmerl.erl b/lib/xmerl/src/xmerl.erl
index 216859b28b3f..9f258e3dbabf 100644
--- a/lib/xmerl/src/xmerl.erl
+++ b/lib/xmerl/src/xmerl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2024. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/xmerl/src/xmerl_html.erl b/lib/xmerl/src/xmerl_html.erl
index 807c6afb2807..e89081bfbe56 100644
--- a/lib/xmerl/src/xmerl_html.erl
+++ b/lib/xmerl/src/xmerl_html.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2024. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/xmerl/src/xmerl_lib.erl b/lib/xmerl/src/xmerl_lib.erl
index c8ebc292a9e0..5c0527596012 100644
--- a/lib/xmerl/src/xmerl_lib.erl
+++ b/lib/xmerl/src/xmerl_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2024. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/xmerl/src/xmerl_otpsgml.erl b/lib/xmerl/src/xmerl_otpsgml.erl
index 763671381180..1672e61f2a13 100644
--- a/lib/xmerl/src/xmerl_otpsgml.erl
+++ b/lib/xmerl/src/xmerl_otpsgml.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2024. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/xmerl/src/xmerl_sgml.erl b/lib/xmerl/src/xmerl_sgml.erl
index 0dcd23784727..6c98cce5a725 100644
--- a/lib/xmerl/src/xmerl_sgml.erl
+++ b/lib/xmerl/src/xmerl_sgml.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2024. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/xmerl/src/xmerl_text.erl b/lib/xmerl/src/xmerl_text.erl
index 74eedcaf7186..eb90b1a35880 100644
--- a/lib/xmerl/src/xmerl_text.erl
+++ b/lib/xmerl/src/xmerl_text.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2024. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/xmerl/src/xmerl_xml.erl b/lib/xmerl/src/xmerl_xml.erl
index 78c73c17cb42..fe6b6abe0ea2 100644
--- a/lib/xmerl/src/xmerl_xml.erl
+++ b/lib/xmerl/src/xmerl_xml.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2024. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/xmerl/test/xmerl_SUITE.erl b/lib/xmerl/test/xmerl_SUITE.erl
index 25e803697734..9b37a58e205c 100644
--- a/lib/xmerl/test/xmerl_SUITE.erl
+++ b/lib/xmerl/test/xmerl_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2023. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2024. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
From 62a32f91d2aa406561ea462cbd4fdae5d9c73984 Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Wed, 18 Sep 2024 08:52:12 +0200
Subject: [PATCH 016/217] Prepare release
---
lib/diameter/doc/src/notes.xml | 15 +++++++++++++++
lib/diameter/vsn.mk | 2 +-
lib/public_key/doc/src/notes.xml | 17 +++++++++++++++++
lib/public_key/vsn.mk | 2 +-
lib/ssh/doc/src/notes.xml | 25 +++++++++++++++++++++++++
lib/ssh/vsn.mk | 2 +-
lib/xmerl/doc/src/notes.xml | 18 ++++++++++++++++++
lib/xmerl/vsn.mk | 2 +-
make/otp_version_tickets | 11 +++++------
9 files changed, 84 insertions(+), 10 deletions(-)
diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml
index 8bf041cec510..a09961643025 100644
--- a/lib/diameter/doc/src/notes.xml
+++ b/lib/diameter/doc/src/notes.xml
@@ -43,6 +43,21 @@ first.
+diameter 2.2.7.2
+
+ Fixed Bugs and Malfunctions
+
+ -
+
+ `diameter:stop_service/1` has been made more synchronous.
+
+ Own Id: OTP-19206 Aux Id: ERIERL-1102
+
+
+
+
+
+
diameter 2.2.7.1
Fixed Bugs and Malfunctions
diff --git a/lib/diameter/vsn.mk b/lib/diameter/vsn.mk
index f157297ae60a..8266b6d92b04 100644
--- a/lib/diameter/vsn.mk
+++ b/lib/diameter/vsn.mk
@@ -17,5 +17,5 @@
# %CopyrightEnd%
APPLICATION = diameter
-DIAMETER_VSN = 2.2.7.1
+DIAMETER_VSN = 2.2.7.2
APP_VSN = $(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN)
diff --git a/lib/public_key/doc/src/notes.xml b/lib/public_key/doc/src/notes.xml
index d1e956b55b62..a70d94171751 100644
--- a/lib/public_key/doc/src/notes.xml
+++ b/lib/public_key/doc/src/notes.xml
@@ -35,6 +35,23 @@
notes.xml
+Public_Key 1.13.3.3
+
+ Fixed Bugs and Malfunctions
+
+ -
+
+ For completeness handle rsa_pss implicit default value,
+ although this will probably not be commonly used as it
+ provides very weak security.
+
+ Own Id: OTP-19179
+
+
+
+
+
+
Public_Key 1.13.3.2
Fixed Bugs and Malfunctions
diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk
index 1abec179b541..93c72b544a73 100644
--- a/lib/public_key/vsn.mk
+++ b/lib/public_key/vsn.mk
@@ -1 +1 @@
-PUBLIC_KEY_VSN = 1.13.3.2
+PUBLIC_KEY_VSN = 1.13.3.3
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index 12506657d7f8..8029f947abf8 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,31 @@
notes.xml
+Ssh 4.15.3.6
+
+ Fixed Bugs and Malfunctions
+
+ -
+
+ The SSh daemon started with a TCP port number argument
+ will now re-try obtaining a listen socket before
+ returning an error to the user.
+
+ Own Id: OTP-19170 Aux Id: GH-7746
+
+ -
+
+ Robustness has been improved by monitoring the connection
+ handler process before casting the socket control
+ notification.
+
+ Own Id: OTP-19173 Aux Id: PR-8310
+
+
+
+
+
+
Ssh 4.15.3.5
Fixed Bugs and Malfunctions
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index dce44fdffe45..d53ea8f85494 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,4 +1,4 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.15.3.5
+SSH_VSN = 4.15.3.6
APP_VSN = "ssh-$(SSH_VSN)"
diff --git a/lib/xmerl/doc/src/notes.xml b/lib/xmerl/doc/src/notes.xml
index a3942bbe59bc..695fcf376115 100644
--- a/lib/xmerl/doc/src/notes.xml
+++ b/lib/xmerl/doc/src/notes.xml
@@ -32,6 +32,24 @@
This document describes the changes made to the Xmerl application.
+Xmerl 1.3.31.2
+
+ Fixed Bugs and Malfunctions
+
+ -
+
+ Corrected export functions from internal structure to XML
+ so xmlText items of type cdata are handled correctly.
+ They were just exported as normal text instead of output
+ in a CDATA section.
+
+ Own Id: OTP-19217 Aux Id: ERIERL-1104
+
+
+
+
+
+
Xmerl 1.3.31.1
Fixed Bugs and Malfunctions
diff --git a/lib/xmerl/vsn.mk b/lib/xmerl/vsn.mk
index 3f780125a9a9..ecf3c56ef5c9 100644
--- a/lib/xmerl/vsn.mk
+++ b/lib/xmerl/vsn.mk
@@ -1 +1 @@
-XMERL_VSN = 1.3.31.1
+XMERL_VSN = 1.3.31.2
diff --git a/make/otp_version_tickets b/make/otp_version_tickets
index 213f0897e0d2..f63e92bed561 100644
--- a/make/otp_version_tickets
+++ b/make/otp_version_tickets
@@ -1,6 +1,5 @@
-OTP-19057
-OTP-19109
-OTP-19123
-OTP-19140
-OTP-19147
-OTP-19154
+OTP-19170
+OTP-19173
+OTP-19179
+OTP-19206
+OTP-19217
From 412febbe2eb15958f92dd6f908b14cfcd2ff2c16 Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Wed, 18 Sep 2024 08:52:14 +0200
Subject: [PATCH 017/217] Updated OTP version
---
OTP_VERSION | 2 +-
otp_versions.table | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/OTP_VERSION b/OTP_VERSION
index 8c3229e1394a..3f029b83e239 100644
--- a/OTP_VERSION
+++ b/OTP_VERSION
@@ -1 +1 @@
-25.3.2.13
+25.3.2.14
diff --git a/otp_versions.table b/otp_versions.table
index a67e19f8b542..c5cb810b194b 100644
--- a/otp_versions.table
+++ b/otp_versions.table
@@ -1,3 +1,4 @@
+OTP-25.3.2.14 : diameter-2.2.7.2 public_key-1.13.3.3 ssh-4.15.3.6 xmerl-1.3.31.2 # asn1-5.0.21.1 common_test-1.24.0.3 compiler-8.2.6.4 crypto-5.1.4.3 debugger-5.3.1.3 dialyzer-5.0.5 edoc-1.2 eldap-1.2.11 erl_docgen-1.4 erl_interface-5.3.2.1 erts-13.2.2.10 et-1.6.5 eunit-2.8.2 ftp-1.1.4 inets-8.3.1.3 jinterface-1.13.2 kernel-8.5.4.3 megaco-4.4.3 mnesia-4.21.4.3 observer-2.14.0.1 odbc-2.14 os_mon-2.8.2.1 parsetools-2.4.1 reltool-0.9.1.1 runtime_tools-1.19 sasl-4.2 snmp-5.13.5 ssl-10.9.1.5 stdlib-4.3.1.4 syntax_tools-3.0.1 tftp-1.0.4 tools-3.5.3 wx-2.2.2.1 :
OTP-25.3.2.13 : erts-13.2.2.10 ssh-4.15.3.5 ssl-10.9.1.5 # asn1-5.0.21.1 common_test-1.24.0.3 compiler-8.2.6.4 crypto-5.1.4.3 debugger-5.3.1.3 dialyzer-5.0.5 diameter-2.2.7.1 edoc-1.2 eldap-1.2.11 erl_docgen-1.4 erl_interface-5.3.2.1 et-1.6.5 eunit-2.8.2 ftp-1.1.4 inets-8.3.1.3 jinterface-1.13.2 kernel-8.5.4.3 megaco-4.4.3 mnesia-4.21.4.3 observer-2.14.0.1 odbc-2.14 os_mon-2.8.2.1 parsetools-2.4.1 public_key-1.13.3.2 reltool-0.9.1.1 runtime_tools-1.19 sasl-4.2 snmp-5.13.5 stdlib-4.3.1.4 syntax_tools-3.0.1 tftp-1.0.4 tools-3.5.3 wx-2.2.2.1 xmerl-1.3.31.1 :
OTP-25.3.2.12 : erts-13.2.2.9 mnesia-4.21.4.3 ssl-10.9.1.4 # asn1-5.0.21.1 common_test-1.24.0.3 compiler-8.2.6.4 crypto-5.1.4.3 debugger-5.3.1.3 dialyzer-5.0.5 diameter-2.2.7.1 edoc-1.2 eldap-1.2.11 erl_docgen-1.4 erl_interface-5.3.2.1 et-1.6.5 eunit-2.8.2 ftp-1.1.4 inets-8.3.1.3 jinterface-1.13.2 kernel-8.5.4.3 megaco-4.4.3 observer-2.14.0.1 odbc-2.14 os_mon-2.8.2.1 parsetools-2.4.1 public_key-1.13.3.2 reltool-0.9.1.1 runtime_tools-1.19 sasl-4.2 snmp-5.13.5 ssh-4.15.3.4 stdlib-4.3.1.4 syntax_tools-3.0.1 tftp-1.0.4 tools-3.5.3 wx-2.2.2.1 xmerl-1.3.31.1 :
OTP-25.3.2.11 : common_test-1.24.0.3 crypto-5.1.4.3 debugger-5.3.1.3 diameter-2.2.7.1 erts-13.2.2.8 inets-8.3.1.3 kernel-8.5.4.3 observer-2.14.0.1 os_mon-2.8.2.1 reltool-0.9.1.1 ssh-4.15.3.4 stdlib-4.3.1.4 # asn1-5.0.21.1 compiler-8.2.6.4 dialyzer-5.0.5 edoc-1.2 eldap-1.2.11 erl_docgen-1.4 erl_interface-5.3.2.1 et-1.6.5 eunit-2.8.2 ftp-1.1.4 jinterface-1.13.2 megaco-4.4.3 mnesia-4.21.4.2 odbc-2.14 parsetools-2.4.1 public_key-1.13.3.2 runtime_tools-1.19 sasl-4.2 snmp-5.13.5 ssl-10.9.1.3 syntax_tools-3.0.1 tftp-1.0.4 tools-3.5.3 wx-2.2.2.1 xmerl-1.3.31.1 :
From bd8b7e6b5874dde8c77013f7b5f6a986c7195f57 Mon Sep 17 00:00:00 2001
From: Henrik Nord
Date: Wed, 18 Sep 2024 09:58:23 +0200
Subject: [PATCH 018/217] Prepare for development
---
make/otp_version_tickets | 83 +---------------------------------------
1 file changed, 1 insertion(+), 82 deletions(-)
diff --git a/make/otp_version_tickets b/make/otp_version_tickets
index c93f51f8ff53..b8220e1a8720 100644
--- a/make/otp_version_tickets
+++ b/make/otp_version_tickets
@@ -1,82 +1 @@
-OTP-16607
-OTP-17848
-OTP-19032
-OTP-19097
-OTP-19098
-OTP-19101
-OTP-19102
-OTP-19103
-OTP-19104
-OTP-19105
-OTP-19110
-OTP-19112
-OTP-19113
-OTP-19114
-OTP-19119
-OTP-19120
-OTP-19122
-OTP-19126
-OTP-19128
-OTP-19129
-OTP-19130
-OTP-19132
-OTP-19133
-OTP-19134
-OTP-19136
-OTP-19138
-OTP-19139
-OTP-19143
-OTP-19145
-OTP-19146
-OTP-19148
-OTP-19153
-OTP-19154
-OTP-19157
-OTP-19163
-OTP-19164
-OTP-19165
-OTP-19166
-OTP-19167
-OTP-19168
-OTP-19169
-OTP-19170
-OTP-19171
-OTP-19172
-OTP-19173
-OTP-19175
-OTP-19176
-OTP-19178
-OTP-19179
-OTP-19181
-OTP-19182
-OTP-19183
-OTP-19185
-OTP-19186
-OTP-19187
-OTP-19188
-OTP-19189
-OTP-19190
-OTP-19191
-OTP-19192
-OTP-19193
-OTP-19197
-OTP-19199
-OTP-19200
-OTP-19201
-OTP-19202
-OTP-19203
-OTP-19205
-OTP-19206
-OTP-19208
-OTP-19209
-OTP-19210
-OTP-19211
-OTP-19212
-OTP-19214
-OTP-19215
-OTP-19216
-OTP-19217
-OTP-19218
-OTP-19219
-OTP-19220
-OTP-19222
+DEVELOPMENT
From b9462cbeb6bef91676022db379258ca339d7421f Mon Sep 17 00:00:00 2001
From: Jakub Witczak
Date: Thu, 19 Sep 2024 11:48:23 +0200
Subject: [PATCH 019/217] ssh: remove unused Address from function arguments
---
lib/ssh/src/ssh_connection_handler.erl | 8 ++++----
lib/ssh/src/ssh_subsystem_sup.erl | 10 +++++-----
lib/ssh/src/ssh_system_sup.erl | 2 +-
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 2648c5256bcc..fbd56dab399f 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -42,7 +42,7 @@
%%====================================================================
%%% Start and stop
--export([start_link/4, start_link/5,
+-export([start_link/3, start_link/4,
takeover/4,
stop/1
]).
@@ -98,10 +98,10 @@
%% Start / stop
%%====================================================================
-start_link(Role, Address, Socket, Options) ->
- start_link(Role, Address, undefined, Socket, Options).
+start_link(Role, Socket, Options) ->
+ start_link(Role, undefined, Socket, Options).
-start_link(Role, _Address=#address{}, Id, Socket, Options) ->
+start_link(Role, Id, Socket, Options) ->
case gen_statem:start_link(?MODULE,
[Role, Socket, Options],
[{spawn_opt, [{message_queue_data,off_heap}]}]) of
diff --git a/lib/ssh/src/ssh_subsystem_sup.erl b/lib/ssh/src/ssh_subsystem_sup.erl
index ef56c999d2ca..2eb61c6236bd 100644
--- a/lib/ssh/src/ssh_subsystem_sup.erl
+++ b/lib/ssh/src/ssh_subsystem_sup.erl
@@ -28,7 +28,7 @@
-include("ssh.hrl").
--export([start_link/5,
+-export([start_link/4,
start_channel/8,
tcpip_fwd_supervisor/1
]).
@@ -39,8 +39,8 @@
%%%=========================================================================
%%% API
%%%=========================================================================
-start_link(Role, Address=#address{}, Id, Socket, Options) ->
- case supervisor:start_link(?MODULE, [Role, Address, Id, Socket, Options]) of
+start_link(Role, Id, Socket, Options) ->
+ case supervisor:start_link(?MODULE, [Role, Id, Socket, Options]) of
{error, {shutdown, {failed_to_start_child, _, Error}}} ->
{error,Error};
Other ->
@@ -58,7 +58,7 @@ tcpip_fwd_supervisor(SubSysSup) ->
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
-init([Role, Address, Id, Socket, Options]) ->
+init([Role, Id, Socket, Options]) ->
SubSysSup = self(),
SupFlags = #{strategy => one_for_all,
auto_shutdown => any_significant,
@@ -71,7 +71,7 @@ init([Role, Address, Id, Socket, Options]) ->
significant => true,
start => {ssh_connection_handler,
start_link,
- [Role, Address, Id, Socket,
+ [Role, Id, Socket,
?PUT_INTERNAL_OPT([
{subsystem_sup, SubSysSup}
], Options)
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index 3835babf1499..cdd00cc65790 100644
--- a/lib/ssh/src/ssh_system_sup.erl
+++ b/lib/ssh/src/ssh_system_sup.erl
@@ -104,7 +104,7 @@ start_subsystem(Role, Address=#address{}, Socket, Options0) ->
case supervisor:start_child(SysPid,
#{id => Id,
start => {ssh_subsystem_sup, start_link,
- [Role,Address,Id,Socket,Options]
+ [Role,Id,Socket,Options]
},
restart => temporary,
significant => true,
From 3bc70dd6f2800e3396a0021fb161ae06f04f19c4 Mon Sep 17 00:00:00 2001
From: Jakub Witczak
Date: Thu, 19 Sep 2024 11:48:23 +0200
Subject: [PATCH 020/217] ssh: do_start_subsystem added, skip system_sup for
client
---
lib/ssh/src/ssh.erl | 11 ++-
lib/ssh/src/ssh_info.erl | 40 ++++++++---
lib/ssh/src/ssh_system_sup.erl | 124 +++++++++++++++++----------------
lib/ssh/test/ssh_sup_SUITE.erl | 19 +++--
4 files changed, 108 insertions(+), 86 deletions(-)
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index f856d3d88787..714d4390f1e8 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -392,8 +392,7 @@ daemon(Host0, Port0, UserOptions0) when 0 =< Port0, Port0 =< 65535,
%% throws error:Error if no usable hostkey is found
ssh_connection_handler:available_hkey_algorithms(server, Options1),
- ssh_system_sup:start_system(server,
- #address{address = Host,
+ ssh_system_sup:start_system(#address{address = Host,
port = Port,
profile = ?GET_OPT(profile,Options1)},
Options1)
@@ -540,8 +539,7 @@ stop_listener(Address, Port, Profile) ->
lists:foreach(fun({Sup,_Addr}) ->
stop_listener(Sup)
end,
- ssh_system_sup:addresses(server,
- #address{address=Address,
+ ssh_system_sup:addresses(#address{address=Address,
port=Port,
profile=Profile})).
@@ -552,7 +550,7 @@ stop_listener(Address, Port, Profile) ->
-spec stop_daemon(DaemonRef::daemon_ref()) -> ok.
stop_daemon(SysSup) ->
- ssh_system_sup:stop_system(server, SysSup).
+ ssh_system_sup:stop_system(SysSup).
-spec stop_daemon(inet:ip_address(), inet:port_number()) -> ok.
@@ -567,8 +565,7 @@ stop_daemon(Address, Port, Profile) ->
lists:foreach(fun({Sup,_Addr}) ->
stop_daemon(Sup)
end,
- ssh_system_sup:addresses(server,
- #address{address=Address,
+ ssh_system_sup:addresses(#address{address=Address,
port=Port,
profile=Profile})).
diff --git a/lib/ssh/src/ssh_info.erl b/lib/ssh/src/ssh_info.erl
index aa7324b58805..625d8109e1b7 100644
--- a/lib/ssh/src/ssh_info.erl
+++ b/lib/ssh/src/ssh_info.erl
@@ -131,13 +131,25 @@ format_sup(server, {{{ssh_system_sup,LocalAddress},Pid,supervisor,[ssh_system_su
walk_tree(server, Children, ?inc(Indent)),
io_lib:nl() % Separate system supervisors by an empty line
];
-format_sup(client, {{{ssh_system_sup,LocalAddress},Pid,supervisor,[ssh_system_sup]}, _Spec, Children}, Indent) ->
- [indent(Indent),
- io_lib:format("Local: ~s sys_sup=~s~n", [format_address(LocalAddress), print_pid(Pid)]),
- walk_tree(client, Children, ?inc(Indent)),
- io_lib:nl() % Separate system supervisors by an empty line
+format_sup(client,
+ {{Ref,SubSysSup,supervisor,[ssh_subsystem_sup]}, _SubSysSpec,
+ [{{connection,ConnPid,worker,[ssh_connection_handler]}, _ConnSpec}
+ | Children]
+ },
+ Indent) when is_reference(Ref) ->
+ [io_lib:format("~sLocal: ~s~n"
+ "~sRemote: ~s (Version: ~s)~n"
+ "~sConnectionRef=~s, subsys_sup=~s~n",
+ [indent(Indent), local_addr(ConnPid),
+ indent(Indent), peer_addr(ConnPid), peer_version(client,ConnPid),
+ indent(Indent), print_pid(ConnPid), print_pid(SubSysSup)
+ ]),
+ walk_tree(client,
+ [{H,{connref,ConnPid},Cs} || {H,_,Cs} <- Children],
+ ?inc(Indent)),
+ io_lib:nl() % Separate sub system supervisors by an empty line
];
-format_sup(Role,
+format_sup(server,
{{Ref,SubSysSup,supervisor,[ssh_subsystem_sup]}, _SubSysSpec,
[{{connection,ConnPid,worker,[ssh_connection_handler]}, _ConnSpec}
| Children]
@@ -145,10 +157,10 @@ format_sup(Role,
Indent) when is_reference(Ref) ->
[io_lib:format("~sRemote: ~s (Version: ~s)~n"
"~sConnectionRef=~s, subsys_sup=~s~n",
- [indent(Indent), peer_addr(ConnPid), peer_version(Role,ConnPid),
+ [indent(Indent), peer_addr(ConnPid), peer_version(server,ConnPid),
indent(Indent), print_pid(ConnPid), print_pid(SubSysSup)
]),
- walk_tree(Role,
+ walk_tree(server,
[{H,{connref,ConnPid},Cs} || {H,_,Cs} <- Children],
?inc(Indent)),
io_lib:nl() % Separate sub system supervisors by an empty line
@@ -250,7 +262,17 @@ peer_addr(Pid) ->
catch
_:_ -> "?"
end.
-
+
+local_addr(Pid) ->
+ try
+ [{socket,Socket}] =
+ ssh_connection_handler:connection_info(Pid, [socket]),
+ {ok, AddrPort} = inet:sockname(Socket),
+ ssh_lib:format_address_port(AddrPort)
+ catch
+ _:_ -> "?"
+ end.
+
format_address(#address{address=Addr, port=Port, profile=Prof}) ->
io_lib:format("~s (profile ~p)", [ssh_lib:format_address_port({Addr,Port}),Prof]);
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index cdd00cc65790..9aa645f72248 100644
--- a/lib/ssh/src/ssh_system_sup.erl
+++ b/lib/ssh/src/ssh_system_sup.erl
@@ -33,11 +33,11 @@
-export([start_link/3,
stop_listener/1,
- stop_system/2,
- start_system/3,
+ stop_system/1,
+ start_system/2,
start_subsystem/4,
get_daemon_listen_address/1,
- addresses/2,
+ addresses/1,
get_options/2,
get_acceptor_options/1,
replace_acceptor_options/2
@@ -50,29 +50,27 @@
%%% API
%%%=========================================================================
-start_system(Role, Address0, Options) ->
- case find_system_sup(Role, Address0) of
- {ok,{SysPid,Address}} when Role =:= server->
+start_system(Address0, Options) ->
+ case find_system_sup(Address0) of
+ {ok,{SysPid,Address}} ->
restart_acceptor(SysPid, Address, Options);
- {ok,{SysPid,_}}->
- {ok,SysPid};
{error,not_found} ->
- supervisor:start_child(sup(Role),
+ supervisor:start_child(sshd_sup,
#{id => {?MODULE,Address0},
- start => {?MODULE, start_link, [Role, Address0, Options]},
+ start => {?MODULE, start_link, [server, Address0, Options]},
restart => temporary,
type => supervisor
})
end.
%%%----------------------------------------------------------------
-stop_system(Role, SysSup) when is_pid(SysSup) ->
- case lists:keyfind(SysSup, 2, supervisor:which_children(sup(Role))) of
- {{?MODULE, Id}, SysSup, _, _} -> stop_system(Role, Id);
- false -> undefined % FIXME ssh:stop_daemon doc missing that ?
+stop_system(SysSup) when is_pid(SysSup) ->
+ case lists:keyfind(SysSup, 2, supervisor:which_children(sup(server))) of
+ {{?MODULE, Id}, SysSup, _, _} -> stop_system(Id);
+ false -> ok
end;
-stop_system(Role, Id) ->
- supervisor:terminate_child(sup(Role), {?MODULE, Id}).
+stop_system(Id) ->
+ supervisor:terminate_child(sup(server), {?MODULE, Id}).
%%%----------------------------------------------------------------
@@ -95,42 +93,49 @@ get_daemon_listen_address(SystemSup) ->
end.
%%%----------------------------------------------------------------
-%%% Start the subsystem child. It is a child of the system supervisor (callback = this module)
-start_subsystem(Role, Address=#address{}, Socket, Options0) ->
- Options = ?PUT_INTERNAL_OPT([{user_pid, self()}], Options0),
+%%% Start the subsystem child. It is a significant child of the system
+%%% supervisor (callback = this module) for server and non-significant
+%%% child of sshc_sup for client
+start_subsystem(Role = client, _, Socket, Options) ->
+ do_start_subsystem(Role, sup(client), false, Socket, Options);
+start_subsystem(Role = server, Address=#address{}, Socket, Options) ->
+ case get_system_sup(Address, Options) of
+ {ok, SysPid} ->
+ do_start_subsystem(Role, SysPid, true, Socket, Options);
+ Others ->
+ Others
+ end.
+
+do_start_subsystem(Role, SupPid, Significant, Socket, Options0) ->
Id = make_ref(),
- case get_system_sup(Role, Address, Options) of
- {ok,SysPid} ->
- case supervisor:start_child(SysPid,
- #{id => Id,
- start => {ssh_subsystem_sup, start_link,
- [Role,Id,Socket,Options]
- },
- restart => temporary,
- significant => true,
- type => supervisor
- })
- of
- {ok,_SubSysPid} ->
- try
- receive
- {new_connection_ref, Id, ConnPid} ->
- ssh_connection_handler:takeover(ConnPid, Role, Socket, Options)
- after 10000 ->
- error(timeout)
- end
- catch
- error:{badmatch,{error,Error}} ->
- {error,Error};
- error:timeout ->
- %% The connection was started, but the takover procedure timed out,
- %% therefore it exists a subtree, but it is not quite ready and
- %% must be removed (by the supervisor above):
- supervisor:terminate_child(SysPid, Id),
- {error, connection_start_timeout}
- end;
- Others ->
- Others
+ Options = ?PUT_INTERNAL_OPT([{user_pid, self()}], Options0),
+ case supervisor:start_child(SupPid,
+ #{id => Id,
+ start => {ssh_subsystem_sup, start_link,
+ [Role,Id,Socket,Options]
+ },
+ restart => temporary,
+ significant => Significant,
+ type => supervisor
+ })
+ of
+ {ok,_SubSysPid} ->
+ try
+ receive
+ {new_connection_ref, Id, ConnPid} ->
+ ssh_connection_handler:takeover(ConnPid, Role, Socket, Options)
+ after 10000 ->
+ error(timeout)
+ end
+ catch
+ error:{badmatch,{error,Error}} ->
+ {error,Error};
+ error:timeout ->
+ %% The connection was started, but the takover procedure timed out,
+ %% therefore it exists a subtree, but it is not quite ready and
+ %% must be removed (by the supervisor above):
+ supervisor:terminate_child(SupPid, Id),
+ {error, connection_start_timeout}
end;
Others ->
Others
@@ -141,9 +146,9 @@ start_link(Role, Address, Options) ->
supervisor:start_link(?MODULE, [Role, Address, Options]).
%%%----------------------------------------------------------------
-addresses(Role, #address{address=Address, port=Port, profile=Profile}) ->
+addresses(#address{address=Address, port=Port, profile=Profile}) ->
[{SysSup,A} || {{ssh_system_sup,A},SysSup,supervisor,_} <-
- supervisor:which_children(sup(Role)),
+ supervisor:which_children(sshd_sup),
Address == any orelse A#address.address == Address,
Port == any orelse A#address.port == Port,
Profile == any orelse A#address.profile == Profile].
@@ -226,19 +231,20 @@ acceptor_sup_child_spec(SysSup, Address, Options) ->
lookup(SupModule, SystemSup) ->
lists:keyfind([SupModule], 4, supervisor:which_children(SystemSup)).
-get_system_sup(Role, Address0, Options) ->
- case find_system_sup(Role, Address0) of
+get_system_sup(Address0, Options) ->
+ case find_system_sup(Address0) of
{ok,{SysPid,_Address}} ->
{ok,SysPid};
{error,not_found} ->
- start_system(Role, Address0, Options);
+ start_system(Address0, Options);
{error,Error} ->
{error,Error}
end.
-find_system_sup(Role, Address0) ->
- case addresses(Role, Address0) of
- [{SysSupPid,Address}] -> {ok,{SysSupPid,Address}};
+find_system_sup(Address0) ->
+ case addresses(Address0) of
+ [{SysSupPid,Address}] ->
+ {ok,{SysSupPid,Address}};
[] -> {error,not_found};
[_,_|_] -> {error,ambiguous}
end.
diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl
index 35f55fdea5d0..e8392864d87c 100644
--- a/lib/ssh/test/ssh_sup_SUITE.erl
+++ b/lib/ssh/test/ssh_sup_SUITE.erl
@@ -129,25 +129,22 @@ sshc_subtree(Config) when is_list(Config) ->
{user, ?USER},
{password, ?PASSWD},
{user_dir, UserDir}]),
- ?wait_match([?SYSTEM_SUP(SysSup,
- #address{address=LocalIP,
- port=LocalPort,
- profile=?DEFAULT_PROFILE})],
+ ?wait_match([?SUB_SYSTEM_SUP(SubSysSup)],
supervisor:which_children(sshc_sup),
- [SysSup, LocalIP, LocalPort]),
- check_sshc_system_tree(SysSup, Pid1, LocalIP, LocalPort, Config),
+ [SubSysSup]),
+ check_sshc_system_tree(SubSysSup, Pid1, Config),
Pid2 = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
{save_accepted_host, false},
{user_interaction, false},
{user, ?USER},
{password, ?PASSWD},
{user_dir, UserDir}]),
- ?wait_match([?SYSTEM_SUP(_,_),
- ?SYSTEM_SUP(_,_)
+ ?wait_match([?SUB_SYSTEM_SUP(_),
+ ?SUB_SYSTEM_SUP(_)
],
supervisor:which_children(sshc_sup)),
ssh:close(Pid1),
- ?wait_match([?SYSTEM_SUP(_,_)
+ ?wait_match([?SUB_SYSTEM_SUP(_)
],
supervisor:which_children(sshc_sup)),
ssh:close(Pid2),
@@ -415,9 +412,9 @@ check_sshd_system_tree(Daemon, Host, Port, Config) ->
ssh:close(ClientConn).
-check_sshc_system_tree(SysSup, Connection, _LocalIP, _LocalPort, _Config) ->
+check_sshc_system_tree(SubSysSup, Connection, _Config) ->
?wait_match([?SUB_SYSTEM_SUP(SubSysSup)],
- supervisor:which_children(SysSup),
+ supervisor:which_children(sshc_sup),
[SubSysSup]),
?wait_match([{_,FwdAccSup, supervisor,[ssh_tcpip_forward_acceptor_sup]},
{_,_,supervisor,[ssh_channel_sup]},
From 6617a14154471719383639d18f1074a0d8669b0d Mon Sep 17 00:00:00 2001
From: Jakub Witczak
Date: Thu, 19 Sep 2024 11:48:23 +0200
Subject: [PATCH 021/217] ssh: rename ssh_subsystem_sup to ssh_connection_sup
- rename in order to improve supervision readability
---
lib/ssh/src/Makefile | 2 +-
lib/ssh/src/ssh.app.src | 4 +-
lib/ssh/src/ssh.erl | 4 +-
lib/ssh/src/ssh_acceptor.erl | 4 +-
lib/ssh/src/ssh_connect.hrl | 2 +-
lib/ssh/src/ssh_connection.erl | 20 +++----
lib/ssh/src/ssh_connection_handler.erl | 20 +++----
...bsystem_sup.erl => ssh_connection_sup.erl} | 59 +++++++++----------
lib/ssh/src/ssh_info.erl | 10 ++--
lib/ssh/src/ssh_system_sup.erl | 18 +++---
lib/ssh/test/ssh.cover | 2 +-
lib/ssh/test/ssh_limited.cover | 2 +-
lib/ssh/test/ssh_protocol_SUITE.erl | 2 +-
lib/ssh/test/ssh_sup_SUITE.erl | 54 ++++++++---------
14 files changed, 99 insertions(+), 104 deletions(-)
rename lib/ssh/src/{ssh_subsystem_sup.erl => ssh_connection_sup.erl} (63%)
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index 2fcb1643013b..ee25174ed858 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -80,7 +80,7 @@ MODULES= \
ssh_sftpd \
ssh_sftpd_file\
ssh_shell \
- ssh_subsystem_sup \
+ ssh_connection_sup \
ssh_system_sup \
ssh_tcpip_forward_srv \
ssh_tcpip_forward_client \
diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src
index fedd05e350f4..e37116ef4908 100644
--- a/lib/ssh/src/ssh.app.src
+++ b/lib/ssh/src/ssh.app.src
@@ -36,7 +36,7 @@
ssh_sftpd,
ssh_sftpd_file,
ssh_sftpd_file_api,
- ssh_subsystem_sup,
+ ssh_connection_sup,
ssh_tcpip_forward_client,
ssh_tcpip_forward_srv,
ssh_tcpip_forward_acceptor_sup,
@@ -51,7 +51,7 @@
ssh_acceptor,
ssh_channel_sup,
ssh_connection_handler,
- ssh_subsystem_sup,
+ ssh_connection_sup,
ssh_system_sup
]},
{default_filter, rm} %% rm | filter
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 714d4390f1e8..052f5efa8842 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -248,7 +248,7 @@ continue_connect(Socket, Options0, NegTimeout) ->
port = SockPort,
profile = ?GET_OPT(profile,Options)
},
- ssh_system_sup:start_subsystem(client, Address, Socket, Options).
+ ssh_system_sup:start_connection(client, Address, Socket, Options).
%%--------------------------------------------------------------------
-spec close(ConnectionRef) -> ok | {error,term()} when
@@ -343,7 +343,7 @@ daemon(Socket, UserOptions) ->
profile = ?GET_OPT(profile,Options0)
},
Options = ?PUT_INTERNAL_OPT({connected_socket, Socket}, Options0),
- case ssh_system_sup:start_subsystem(server, Address, Socket, Options) of
+ case ssh_system_sup:start_connection(server, Address, Socket, Options) of
{ok,Pid} ->
{ok,Pid};
{error, {already_started, _}} ->
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index 7952574de78c..91d7efedcabd 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -187,7 +187,7 @@ handle_connection(Address, Port, _Peer, Options, Socket, _MaxSessions, _NumSessi
handle_connection(Address, Port, Options0, Socket) ->
Options = ?PUT_INTERNAL_OPT([{user_pid, self()}
], Options0),
- ssh_system_sup:start_subsystem(server,
+ ssh_system_sup:start_connection(server,
#address{address = Address,
port = Port,
profile = ?GET_OPT(profile,Options)
@@ -243,7 +243,7 @@ handle_error(Reason, ToAddress, ToPort, FromAddress, FromPort) ->
%%%----------------------------------------------------------------
number_of_connections(SysSupPid) ->
- lists:foldl(fun({_Ref,_Pid,supervisor,[ssh_subsystem_sup]}, N) -> N+1;
+ lists:foldl(fun({_Ref,_Pid,supervisor,[ssh_connection_sup]}, N) -> N+1;
(_, N) -> N
end, 0, supervisor:which_children(SysSupPid)).
diff --git a/lib/ssh/src/ssh_connect.hrl b/lib/ssh/src/ssh_connect.hrl
index 3bd53d59126a..4c6fdaefd4c3 100644
--- a/lib/ssh/src/ssh_connect.hrl
+++ b/lib/ssh/src/ssh_connect.hrl
@@ -269,5 +269,5 @@
suggest_window_size,
suggest_packet_size,
exec,
- sub_system_supervisor
+ connection_supervisor
}).
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index 34e97ba6ca1f..40096e1227c4 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -606,7 +606,7 @@ handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip",
suggest_window_size = WinSz,
suggest_packet_size = PktSz,
options = Options,
- sub_system_supervisor = SubSysSup
+ connection_supervisor = ConnectionSup
} = C,
client, _SSH) ->
{ReplyMsg, NextChId} =
@@ -614,7 +614,7 @@ handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip",
{ok, {ConnectToHost,ConnectToPort}} ->
case gen_tcp:connect(ConnectToHost, ConnectToPort, [{active,false}, binary]) of
{ok,Sock} ->
- {ok,Pid} = ssh_subsystem_sup:start_channel(client, SubSysSup, self(),
+ {ok,Pid} = ssh_connection_sup:start_channel(client, ConnectionSup, self(),
ssh_tcpip_forward_client, ChId,
[Sock], undefined, Options),
ssh_client_channel:cache_update(Cache,
@@ -664,7 +664,7 @@ handle_msg(#ssh_msg_channel_open{channel_type = "direct-tcpip",
suggest_window_size = WinSz,
suggest_packet_size = PktSz,
options = Options,
- sub_system_supervisor = SubSysSup
+ connection_supervisor = ConnectionSup
} = C,
server, _SSH) ->
{ReplyMsg, NextChId} =
@@ -680,7 +680,7 @@ handle_msg(#ssh_msg_channel_open{channel_type = "direct-tcpip",
case gen_tcp:connect(binary_to_list(HostToConnect), PortToConnect,
[{active,false}, binary]) of
{ok,Sock} ->
- {ok,Pid} = ssh_subsystem_sup:start_channel(server, SubSysSup, self(),
+ {ok,Pid} = ssh_connection_sup:start_channel(server, ConnectionSup, self(),
ssh_tcpip_forward_srv, ChId,
[Sock], undefined, Options),
ssh_client_channel:cache_update(Cache,
@@ -912,8 +912,8 @@ handle_msg(#ssh_msg_global_request{name = <<"tcpip-forward">>,
{[{connection_reply, request_failure_msg()}], Connection};
true ->
- SubSysSup = ?GET_INTERNAL_OPT(subsystem_sup, Opts),
- FwdSup = ssh_subsystem_sup:tcpip_fwd_supervisor(SubSysSup),
+ ConnectionSup = ?GET_INTERNAL_OPT(connection_sup, Opts),
+ FwdSup = ssh_connection_sup:tcpip_fwd_supervisor(ConnectionSup),
ConnPid = self(),
case ssh_tcpip_forward_acceptor:supervised_start(FwdSup,
{ListenAddrStr, ListenPort},
@@ -1127,22 +1127,22 @@ setup_session(#connection{channel_cache = Cache,
start_cli(#connection{options = Options,
cli_spec = CliSpec,
exec = Exec,
- sub_system_supervisor = SubSysSup}, ChannelId) ->
+ connection_supervisor = ConnectionSup}, ChannelId) ->
case CliSpec of
no_cli ->
{error, cli_disabled};
{CbModule, Args} ->
- ssh_subsystem_sup:start_channel(server, SubSysSup, self(), CbModule, ChannelId, Args, Exec, Options)
+ ssh_connection_sup:start_channel(server, ConnectionSup, self(), CbModule, ChannelId, Args, Exec, Options)
end.
start_subsystem(BinName, #connection{options = Options,
- sub_system_supervisor = SubSysSup},
+ connection_supervisor = ConnectionSup},
#channel{local_id = ChannelId}, _ReplyMsg) ->
Name = binary_to_list(BinName),
case check_subsystem(Name, Options) of
{Callback, Opts} when is_atom(Callback), Callback =/= none ->
- ssh_subsystem_sup:start_channel(server, SubSysSup, self(), Callback, ChannelId, Opts, undefined, Options);
+ ssh_connection_sup:start_channel(server, ConnectionSup, self(), Callback, ChannelId, Opts, undefined, Options);
{none, _} ->
{error, bad_subsystem};
{_, _} ->
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index fbd56dab399f..a4886ca170d0 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -110,7 +110,7 @@ start_link(Role, Id, Socket, Options) ->
%% Announce the ConnectionRef to the system supervisor so it could
%% 1) initiate the socket handover, and
%% 2) be returned to whoever called for example ssh:connect; the Pid
- %% returned from this function is "consumed" by the subsystem
+ %% returned from this function is "consumed" by the connection
%% supervisor.
?GET_INTERNAL_OPT(user_pid,Options) ! {new_connection_ref, Id, Pid},
{ok, Pid};
@@ -195,8 +195,8 @@ open_channel(ConnectionHandler,
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
start_channel(ConnectionHandler, CallbackModule, ChannelId, Args, Exec) ->
- {ok, {SubSysSup,Role,Opts}} = call(ConnectionHandler, get_misc),
- ssh_subsystem_sup:start_channel(Role, SubSysSup,
+ {ok, {ConnectionSup,Role,Opts}} = call(ConnectionHandler, get_misc),
+ ssh_connection_sup:start_channel(Role, ConnectionSup,
ConnectionHandler, CallbackModule, ChannelId,
Args, Exec, Opts).
@@ -416,7 +416,7 @@ init_connection_record(Role, Socket, Opts) ->
suggest_packet_size = PktSz,
requests = [],
options = Opts,
- sub_system_supervisor = ?GET_INTERNAL_OPT(subsystem_sup, Opts)
+ connection_supervisor = ?GET_INTERNAL_OPT(connection_sup, Opts)
},
case Role of
server ->
@@ -1017,8 +1017,8 @@ handle_event({call,From}, {eof, ChannelId}, StateName, D0)
handle_event({call,From}, get_misc, StateName,
#data{connection_state = #connection{options = Opts}} = D) when ?CONNECTED(StateName) ->
- SubSysSup = ?GET_INTERNAL_OPT(subsystem_sup, Opts),
- Reply = {ok, {SubSysSup, ?role(StateName), Opts}},
+ ConnectionSup = ?GET_INTERNAL_OPT(connection_sup, Opts),
+ Reply = {ok, {ConnectionSup, ?role(StateName), Opts}},
{keep_state, D, [{reply,From,Reply}]};
handle_event({call,From},
@@ -1281,9 +1281,9 @@ handle_event(info, check_cache, _, D) ->
handle_event(info, {fwd_connect_received, Sock, ChId, ChanCB}, StateName, #data{connection_state = Connection}) ->
#connection{options = Options,
channel_cache = Cache,
- sub_system_supervisor = SubSysSup} = Connection,
+ connection_supervisor = ConnectionSup} = Connection,
Channel = ssh_client_channel:cache_lookup(Cache, ChId),
- {ok,Pid} = ssh_subsystem_sup:start_channel(?role(StateName), SubSysSup, self(), ChanCB, ChId, [Sock], undefined, Options),
+ {ok,Pid} = ssh_connection_sup:start_channel(?role(StateName), ConnectionSup, self(), ChanCB, ChId, [Sock], undefined, Options),
ssh_client_channel:cache_update(Cache, Channel#channel{user=Pid}),
gen_tcp:controlling_process(Sock, Pid),
inet:setopts(Sock, [{active,once}]),
@@ -1292,8 +1292,8 @@ handle_event(info, {fwd_connect_received, Sock, ChId, ChanCB}, StateName, #data{
handle_event({call,From},
{handle_direct_tcpip, ListenHost, ListenPort, ConnectToHost, ConnectToPort, _Timeout},
_StateName,
- #data{connection_state = #connection{sub_system_supervisor=SubSysSup}}) ->
- case ssh_tcpip_forward_acceptor:supervised_start(ssh_subsystem_sup:tcpip_fwd_supervisor(SubSysSup),
+ #data{connection_state = #connection{connection_supervisor=ConnectionSup}}) ->
+ case ssh_tcpip_forward_acceptor:supervised_start(ssh_connection_sup:tcpip_fwd_supervisor(ConnectionSup),
{ListenHost, ListenPort},
{ConnectToHost, ConnectToPort},
"direct-tcpip", ssh_tcpip_forward_client,
diff --git a/lib/ssh/src/ssh_subsystem_sup.erl b/lib/ssh/src/ssh_connection_sup.erl
similarity index 63%
rename from lib/ssh/src/ssh_subsystem_sup.erl
rename to lib/ssh/src/ssh_connection_sup.erl
index 2eb61c6236bd..2774e4a7a44e 100644
--- a/lib/ssh/src/ssh_subsystem_sup.erl
+++ b/lib/ssh/src/ssh_connection_sup.erl
@@ -19,10 +19,10 @@
%%
%%
%%----------------------------------------------------------------------
-%% Purpose: The ssh subsystem supervisor
+%% Purpose: The ssh connection supervisor
%%----------------------------------------------------------------------
--module(ssh_subsystem_sup).
+-module(ssh_connection_sup).
-behaviour(supervisor).
@@ -51,51 +51,46 @@ start_channel(Role, SupPid, ConnRef, Callback, Id, Args, Exec, Opts) ->
ChannelSup = channel_supervisor(SupPid),
ssh_channel_sup:start_child(Role, ChannelSup, ConnRef, Callback, Id, Args, Exec, Opts).
-tcpip_fwd_supervisor(SubSysSup) ->
- find_child(tcpip_forward_acceptor_sup, SubSysSup).
+tcpip_fwd_supervisor(ConnectionSup) ->
+ find_child(tcpip_forward_acceptor_sup, ConnectionSup).
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
init([Role, Id, Socket, Options]) ->
- SubSysSup = self(),
+ ConnectionSup = self(),
SupFlags = #{strategy => one_for_all,
auto_shutdown => any_significant,
intensity => 0,
- period => 3600
- },
- ChildSpecs = [#{id => connection,
- restart => temporary,
- type => worker,
- significant => true,
- start => {ssh_connection_handler,
- start_link,
- [Role, Id, Socket,
- ?PUT_INTERNAL_OPT([
- {subsystem_sup, SubSysSup}
- ], Options)
- ]
- }
- },
- #{id => channel_sup,
- restart => temporary,
- type => supervisor,
- start => {ssh_channel_sup, start_link, [Options]}
- },
+ period => 3600},
+ ChildSpecs =
+ [#{id => connection,
+ restart => temporary,
+ type => worker,
+ significant => true,
+ start => {ssh_connection_handler,
+ start_link,
+ [Role, Id, Socket,
+ ?PUT_INTERNAL_OPT([{connection_sup, ConnectionSup}], Options)]}
+ },
+ #{id => channel_sup,
+ restart => temporary,
+ type => supervisor,
+ start => {ssh_channel_sup, start_link, [Options]}
+ },
- #{id => tcpip_forward_acceptor_sup,
- restart => temporary,
- type => supervisor,
- start => {ssh_tcpip_forward_acceptor_sup, start_link, []}
- }
- ],
+ #{id => tcpip_forward_acceptor_sup,
+ restart => temporary,
+ type => supervisor,
+ start => {ssh_tcpip_forward_acceptor_sup, start_link, []}
+ }],
{ok, {SupFlags,ChildSpecs}}.
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
-channel_supervisor(SubSysSup) -> find_child(channel_sup, SubSysSup).
+channel_supervisor(ConnectionSup) -> find_child(channel_sup, ConnectionSup).
find_child(Id, Sup) when is_pid(Sup) ->
try
diff --git a/lib/ssh/src/ssh_info.erl b/lib/ssh/src/ssh_info.erl
index 625d8109e1b7..365357b4d566 100644
--- a/lib/ssh/src/ssh_info.erl
+++ b/lib/ssh/src/ssh_info.erl
@@ -132,7 +132,7 @@ format_sup(server, {{{ssh_system_sup,LocalAddress},Pid,supervisor,[ssh_system_su
io_lib:nl() % Separate system supervisors by an empty line
];
format_sup(client,
- {{Ref,SubSysSup,supervisor,[ssh_subsystem_sup]}, _SubSysSpec,
+ {{Ref,ConnSup,supervisor,[ssh_connection_sup]}, _ConnSupSpec,
[{{connection,ConnPid,worker,[ssh_connection_handler]}, _ConnSpec}
| Children]
},
@@ -142,7 +142,7 @@ format_sup(client,
"~sConnectionRef=~s, subsys_sup=~s~n",
[indent(Indent), local_addr(ConnPid),
indent(Indent), peer_addr(ConnPid), peer_version(client,ConnPid),
- indent(Indent), print_pid(ConnPid), print_pid(SubSysSup)
+ indent(Indent), print_pid(ConnPid), print_pid(ConnSup)
]),
walk_tree(client,
[{H,{connref,ConnPid},Cs} || {H,_,Cs} <- Children],
@@ -150,15 +150,15 @@ format_sup(client,
io_lib:nl() % Separate sub system supervisors by an empty line
];
format_sup(server,
- {{Ref,SubSysSup,supervisor,[ssh_subsystem_sup]}, _SubSysSpec,
- [{{connection,ConnPid,worker,[ssh_connection_handler]}, _ConnSpec}
+ {{Ref,ConnSup,supervisor,[ssh_connection_sup]}, _ConnSupSpec,
+ [{{connection,ConnPid,worker,[ssh_connection_handler]}, _ConnSpec}
| Children]
},
Indent) when is_reference(Ref) ->
[io_lib:format("~sRemote: ~s (Version: ~s)~n"
"~sConnectionRef=~s, subsys_sup=~s~n",
[indent(Indent), peer_addr(ConnPid), peer_version(server,ConnPid),
- indent(Indent), print_pid(ConnPid), print_pid(SubSysSup)
+ indent(Indent), print_pid(ConnPid), print_pid(ConnSup)
]),
walk_tree(server,
[{H,{connref,ConnPid},Cs} || {H,_,Cs} <- Children],
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index 9aa645f72248..7d91cda9eecb 100644
--- a/lib/ssh/src/ssh_system_sup.erl
+++ b/lib/ssh/src/ssh_system_sup.erl
@@ -35,7 +35,7 @@
stop_listener/1,
stop_system/1,
start_system/2,
- start_subsystem/4,
+ start_connection/4,
get_daemon_listen_address/1,
addresses/1,
get_options/2,
@@ -93,25 +93,25 @@ get_daemon_listen_address(SystemSup) ->
end.
%%%----------------------------------------------------------------
-%%% Start the subsystem child. It is a significant child of the system
+%%% Start the connection child. It is a significant child of the system
%%% supervisor (callback = this module) for server and non-significant
%%% child of sshc_sup for client
-start_subsystem(Role = client, _, Socket, Options) ->
- do_start_subsystem(Role, sup(client), false, Socket, Options);
-start_subsystem(Role = server, Address=#address{}, Socket, Options) ->
+start_connection(Role = client, _, Socket, Options) ->
+ do_start_connection(Role, sup(client), false, Socket, Options);
+start_connection(Role = server, Address=#address{}, Socket, Options) ->
case get_system_sup(Address, Options) of
{ok, SysPid} ->
- do_start_subsystem(Role, SysPid, true, Socket, Options);
+ do_start_connection(Role, SysPid, true, Socket, Options);
Others ->
Others
end.
-do_start_subsystem(Role, SupPid, Significant, Socket, Options0) ->
+do_start_connection(Role, SupPid, Significant, Socket, Options0) ->
Id = make_ref(),
Options = ?PUT_INTERNAL_OPT([{user_pid, self()}], Options0),
case supervisor:start_child(SupPid,
#{id => Id,
- start => {ssh_subsystem_sup, start_link,
+ start => {ssh_connection_sup, start_link,
[Role,Id,Socket,Options]
},
restart => temporary,
@@ -119,7 +119,7 @@ do_start_subsystem(Role, SupPid, Significant, Socket, Options0) ->
type => supervisor
})
of
- {ok,_SubSysPid} ->
+ {ok,_ConnectionSupPid} ->
try
receive
{new_connection_ref, Id, ConnPid} ->
diff --git a/lib/ssh/test/ssh.cover b/lib/ssh/test/ssh.cover
index daf6c723b9b9..c4cac8daf5be 100644
--- a/lib/ssh/test/ssh.cover
+++ b/lib/ssh/test/ssh.cover
@@ -7,7 +7,7 @@
%% %% Supervisors
%% ssh_acceptor_sup, ssh_channel_sup,
- %% sshc_sup, sshd_sup, ssh_subsystem_sup, ssh_sup,
+ %% sshc_sup, sshd_sup, ssh_connection_sup, ssh_sup,
%% ssh_system_sup, ssh_tcpip_forward_acceptor_sup,
%% Test and/or info modules:
diff --git a/lib/ssh/test/ssh_limited.cover b/lib/ssh/test/ssh_limited.cover
index 29c0121ae1ff..64904c9ce737 100644
--- a/lib/ssh/test/ssh_limited.cover
+++ b/lib/ssh/test/ssh_limited.cover
@@ -9,7 +9,7 @@
%% Supervisors
ssh_acceptor_sup, ssh_channel_sup,
- sshc_sup, sshd_sup, ssh_subsystem_sup, ssh_sup,
+ sshc_sup, sshd_sup, ssh_connection_sup, ssh_sup,
ssh_system_sup, ssh_tcpip_forward_acceptor_sup,
%% Test and/or info modules:
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index b2a3fc417245..fd1680895ef2 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -1259,7 +1259,7 @@ find_handshake_parent([{{ssh_acceptor_sup,{address,_,Port,_}},
{Parents,Handshakers} = lists:unzip(ParentHandshakers),
find_handshake_parent(T, Port, {AccP++Parents, AccC, AccH++Handshakers});
-find_handshake_parent([{_Ref,PidS,supervisor,[ssh_subsystem_sup]}|T], Port, {AccP,AccC,AccH}) ->
+find_handshake_parent([{_Ref,PidS,supervisor,[ssh_connection_sup]}|T], Port, {AccP,AccC,AccH}) ->
Connections =
[Pid || {connection,Pid,worker,[ssh_connection_handler]} <- supervisor:which_children(PidS)],
find_handshake_parent(T, Port, {AccP, AccC++Connections, AccH});
diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl
index e8392864d87c..96be74b58750 100644
--- a/lib/ssh/test/ssh_sup_SUITE.erl
+++ b/lib/ssh/test/ssh_sup_SUITE.erl
@@ -50,7 +50,7 @@
-define(SSHD_SUP(Pid), {sshd_sup, Pid, supervisor, [supervisor]}).
-define(SYSTEM_SUP(Pid,Address),
{{ssh_system_sup, Address}, Pid, supervisor,[ssh_system_sup]}).
--define(SUB_SYSTEM_SUP(Pid), {_,Pid, supervisor,[ssh_subsystem_sup]}).
+-define(CONNECTION_SUP(Pid), {_,Pid, supervisor,[ssh_connection_sup]}).
-define(ACCEPTOR_SUP(Pid,Address),
{{ssh_acceptor_sup,Address},Pid,supervisor,[ssh_acceptor_sup]}).
-define(ACCEPTOR_WORKER(Pid,Address),
@@ -129,22 +129,22 @@ sshc_subtree(Config) when is_list(Config) ->
{user, ?USER},
{password, ?PASSWD},
{user_dir, UserDir}]),
- ?wait_match([?SUB_SYSTEM_SUP(SubSysSup)],
+ ?wait_match([?CONNECTION_SUP(ConnectionSup)],
supervisor:which_children(sshc_sup),
- [SubSysSup]),
- check_sshc_system_tree(SubSysSup, Pid1, Config),
+ [ConnectionSup]),
+ check_sshc_system_tree(ConnectionSup, Pid1, Config),
Pid2 = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
{save_accepted_host, false},
{user_interaction, false},
{user, ?USER},
{password, ?PASSWD},
{user_dir, UserDir}]),
- ?wait_match([?SUB_SYSTEM_SUP(_),
- ?SUB_SYSTEM_SUP(_)
+ ?wait_match([?CONNECTION_SUP(_),
+ ?CONNECTION_SUP(_)
],
supervisor:which_children(sshc_sup)),
ssh:close(Pid1),
- ?wait_match([?SUB_SYSTEM_SUP(_)
+ ?wait_match([?CONNECTION_SUP(_)
],
supervisor:which_children(sshc_sup)),
ssh:close(Pid2),
@@ -298,7 +298,7 @@ shell_channel_tree(Config) ->
{user_interaction, true},
{user_dir, UserDir}]),
- [SubSysSup,_ChPid|_] = Sups0 = chk_empty_con_daemon(Daemon),
+ [ConnectionSup,_ChPid|_] = Sups0 = chk_empty_con_daemon(Daemon),
{ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
ok = ssh_connection:shell(ConnectionRef,ChannelId0),
@@ -308,7 +308,7 @@ shell_channel_tree(Config) ->
{_,ChSup,supervisor,[ssh_channel_sup]},
{connection,_,worker,[ssh_connection_handler]}
],
- supervisor:which_children(SubSysSup),
+ supervisor:which_children(ConnectionSup),
[ChSup]),
?wait_match([{_,GroupPid,worker,[ssh_server_channel]}
],
@@ -325,9 +325,9 @@ shell_channel_tree(Config) ->
{ssh_cm,ConnectionRef, {data, ChannelId0, 0, <<"TimeoutShell started!",Rest/binary>>}} ->
ct:log("TimeoutShell started. Rest = ~p", [Rest]),
receive
- %%---- wait for the subsystem to terminate
+ %%---- wait for the connection to terminate
{ssh_cm,ConnectionRef,{closed,ChannelId0}} ->
- ct:log("Subsystem terminated",[]),
+ ct:log("Connection terminated",[]),
case {chk_empty_con_daemon(Daemon),
process_info(GroupPid),
process_info(ShellPid)} of
@@ -358,23 +358,23 @@ shell_channel_tree(Config) ->
end.
chk_empty_con_daemon(Daemon) ->
- ?wait_match([?SUB_SYSTEM_SUP(SubSysSup),
+ ?wait_match([?CONNECTION_SUP(ConnectionSup),
?ACCEPTOR_SUP(AccSup,_)
],
supervisor:which_children(Daemon),
- [SubSysSup,AccSup]),
+ [ConnectionSup,AccSup]),
?wait_match([{_,FwdAccSup, supervisor,[ssh_tcpip_forward_acceptor_sup]},
{_,ChSup,supervisor,[ssh_channel_sup]},
{connection,ServerConnPid,worker,[ssh_connection_handler]}
],
- supervisor:which_children(SubSysSup),
+ supervisor:which_children(ConnectionSup),
[ChSup,FwdAccSup,ServerConnPid]),
?wait_match([], supervisor:which_children(FwdAccSup)),
?wait_match([], supervisor:which_children(ChSup)),
?wait_match([?ACCEPTOR_WORKER(_,_)],
supervisor:which_children(AccSup),
[]),
- [SubSysSup, ChSup, ServerConnPid, AccSup, FwdAccSup].
+ [ConnectionSup, ChSup, ServerConnPid, AccSup, FwdAccSup].
%%-------------------------------------------------------------------------
%% Help functions
@@ -386,14 +386,14 @@ check_sshd_system_tree(Daemon, Host, Port, Config) ->
{user, ?USER},
{password, ?PASSWD},
{user_dir, UserDir}]),
- ?wait_match([?SUB_SYSTEM_SUP(SubSysSup),
+ ?wait_match([?CONNECTION_SUP(ConnectionSup),
?ACCEPTOR_SUP(AccSup,_)],
supervisor:which_children(Daemon),
- [SubSysSup,AccSup]),
+ [ConnectionSup,AccSup]),
?wait_match([{_,FwdAccSup, supervisor,[ssh_tcpip_forward_acceptor_sup]},
{_,_,supervisor,[ssh_channel_sup]},
{connection,ServerConn,worker,[ssh_connection_handler]}],
- supervisor:which_children(SubSysSup),
+ supervisor:which_children(ConnectionSup),
[FwdAccSup,ServerConn]),
?wait_match([], supervisor:which_children(FwdAccSup)),
?wait_match([?ACCEPTOR_WORKER(_,_)], supervisor:which_children(AccSup)),
@@ -401,7 +401,7 @@ check_sshd_system_tree(Daemon, Host, Port, Config) ->
?wait_match([{_,FwdAccSup, supervisor,[ssh_tcpip_forward_acceptor_sup]},
{_,ChSup,supervisor,[ssh_channel_sup]},
{connection,ServerConn,worker,[ssh_connection_handler]}],
- supervisor:which_children(SubSysSup),
+ supervisor:which_children(ConnectionSup),
[ChSup,ServerConn]),
?wait_match([{_,PidS,worker,[ssh_server_channel]}],
@@ -412,15 +412,15 @@ check_sshd_system_tree(Daemon, Host, Port, Config) ->
ssh:close(ClientConn).
-check_sshc_system_tree(SubSysSup, Connection, _Config) ->
- ?wait_match([?SUB_SYSTEM_SUP(SubSysSup)],
+check_sshc_system_tree(ConnectionSup, Connection, _Config) ->
+ ?wait_match([?CONNECTION_SUP(ConnectionSup)],
supervisor:which_children(sshc_sup),
- [SubSysSup]),
+ [ConnectionSup]),
?wait_match([{_,FwdAccSup, supervisor,[ssh_tcpip_forward_acceptor_sup]},
{_,_,supervisor,[ssh_channel_sup]},
{connection,Connection,worker,[ssh_connection_handler]}
],
- supervisor:which_children(SubSysSup),
+ supervisor:which_children(ConnectionSup),
[FwdAccSup]),
?wait_match([], supervisor:which_children(FwdAccSup)),
@@ -429,7 +429,7 @@ check_sshc_system_tree(SubSysSup, Connection, _Config) ->
{_,ChSup,supervisor, [ssh_channel_sup]},
{connection,Connection,worker,[ssh_connection_handler]}
],
- supervisor:which_children(SubSysSup),
+ supervisor:which_children(ConnectionSup),
[ChSup,FwdAccSup]),
?wait_match([{_,ChPid1,worker,[ssh_client_channel]}
@@ -442,7 +442,7 @@ check_sshc_system_tree(SubSysSup, Connection, _Config) ->
{_,ChSup,supervisor, [ssh_channel_sup]},
{connection,Connection,worker,[ssh_connection_handler]}
],
- supervisor:which_children(SubSysSup),
+ supervisor:which_children(ConnectionSup),
[ChSup,FwdAccSup]),
?wait_match([{_,ChPid2,worker,[ssh_client_channel]},
@@ -457,7 +457,7 @@ check_sshc_system_tree(SubSysSup, Connection, _Config) ->
{_,ChSup,supervisor, [ssh_channel_sup]},
{connection,Connection,worker,[ssh_connection_handler]}
],
- supervisor:which_children(SubSysSup),
+ supervisor:which_children(ConnectionSup),
[ChSup,FwdAccSup]),
?wait_match([{_,ChPid2,worker,[ssh_client_channel]}
@@ -471,7 +471,7 @@ check_sshc_system_tree(SubSysSup, Connection, _Config) ->
{_,ChSup,supervisor, [ssh_channel_sup]},
{connection,Connection,worker,[ssh_connection_handler]}
],
- supervisor:which_children(SubSysSup),
+ supervisor:which_children(ConnectionSup),
[ChSup,FwdAccSup]),
?wait_match([], supervisor:which_children(ChSup)),
From a31a7a8376b7df355e468d338b0ecc3f332cd5ee Mon Sep 17 00:00:00 2001
From: Jakub Witczak
Date: Thu, 19 Sep 2024 11:48:23 +0200
Subject: [PATCH 022/217] ssh: remove unused Address from function arguments
---
lib/ssh/src/ssh_connection_handler.erl | 8 ++++----
lib/ssh/src/ssh_subsystem_sup.erl | 10 +++++-----
lib/ssh/src/ssh_system_sup.erl | 2 +-
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 4ef45516ca23..93fd84c63d7f 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -42,7 +42,7 @@
%%====================================================================
%%% Start and stop
--export([start_link/4, start_link/5,
+-export([start_link/3, start_link/4,
takeover/4,
stop/1
]).
@@ -98,10 +98,10 @@
%% Start / stop
%%====================================================================
-start_link(Role, Address, Socket, Options) ->
- start_link(Role, Address, undefined, Socket, Options).
+start_link(Role, Socket, Options) ->
+ start_link(Role, undefined, Socket, Options).
-start_link(Role, _Address=#address{}, Id, Socket, Options) ->
+start_link(Role, Id, Socket, Options) ->
case gen_statem:start_link(?MODULE,
[Role, Socket, Options],
[{spawn_opt, [{message_queue_data,off_heap}]}]) of
diff --git a/lib/ssh/src/ssh_subsystem_sup.erl b/lib/ssh/src/ssh_subsystem_sup.erl
index ef56c999d2ca..2eb61c6236bd 100644
--- a/lib/ssh/src/ssh_subsystem_sup.erl
+++ b/lib/ssh/src/ssh_subsystem_sup.erl
@@ -28,7 +28,7 @@
-include("ssh.hrl").
--export([start_link/5,
+-export([start_link/4,
start_channel/8,
tcpip_fwd_supervisor/1
]).
@@ -39,8 +39,8 @@
%%%=========================================================================
%%% API
%%%=========================================================================
-start_link(Role, Address=#address{}, Id, Socket, Options) ->
- case supervisor:start_link(?MODULE, [Role, Address, Id, Socket, Options]) of
+start_link(Role, Id, Socket, Options) ->
+ case supervisor:start_link(?MODULE, [Role, Id, Socket, Options]) of
{error, {shutdown, {failed_to_start_child, _, Error}}} ->
{error,Error};
Other ->
@@ -58,7 +58,7 @@ tcpip_fwd_supervisor(SubSysSup) ->
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
-init([Role, Address, Id, Socket, Options]) ->
+init([Role, Id, Socket, Options]) ->
SubSysSup = self(),
SupFlags = #{strategy => one_for_all,
auto_shutdown => any_significant,
@@ -71,7 +71,7 @@ init([Role, Address, Id, Socket, Options]) ->
significant => true,
start => {ssh_connection_handler,
start_link,
- [Role, Address, Id, Socket,
+ [Role, Id, Socket,
?PUT_INTERNAL_OPT([
{subsystem_sup, SubSysSup}
], Options)
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index ed27dc52b2d9..6bde7299657c 100644
--- a/lib/ssh/src/ssh_system_sup.erl
+++ b/lib/ssh/src/ssh_system_sup.erl
@@ -103,7 +103,7 @@ start_subsystem(Role, Address=#address{}, Socket, Options0) ->
case supervisor:start_child(SysPid,
#{id => Id,
start => {ssh_subsystem_sup, start_link,
- [Role,Address,Id,Socket,Options]
+ [Role,Id,Socket,Options]
},
restart => temporary,
significant => true,
From 5710a69955ef83892d2e7c730c364994e14f185c Mon Sep 17 00:00:00 2001
From: Jakub Witczak
Date: Thu, 19 Sep 2024 11:48:23 +0200
Subject: [PATCH 023/217] ssh: do_start_subsystem added, skip system_sup for
client
---
lib/ssh/src/ssh.erl | 11 ++-
lib/ssh/src/ssh_info.erl | 40 ++++++++---
lib/ssh/src/ssh_system_sup.erl | 126 +++++++++++++++++----------------
lib/ssh/test/ssh_sup_SUITE.erl | 31 ++++----
4 files changed, 115 insertions(+), 93 deletions(-)
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index f856d3d88787..714d4390f1e8 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -392,8 +392,7 @@ daemon(Host0, Port0, UserOptions0) when 0 =< Port0, Port0 =< 65535,
%% throws error:Error if no usable hostkey is found
ssh_connection_handler:available_hkey_algorithms(server, Options1),
- ssh_system_sup:start_system(server,
- #address{address = Host,
+ ssh_system_sup:start_system(#address{address = Host,
port = Port,
profile = ?GET_OPT(profile,Options1)},
Options1)
@@ -540,8 +539,7 @@ stop_listener(Address, Port, Profile) ->
lists:foreach(fun({Sup,_Addr}) ->
stop_listener(Sup)
end,
- ssh_system_sup:addresses(server,
- #address{address=Address,
+ ssh_system_sup:addresses(#address{address=Address,
port=Port,
profile=Profile})).
@@ -552,7 +550,7 @@ stop_listener(Address, Port, Profile) ->
-spec stop_daemon(DaemonRef::daemon_ref()) -> ok.
stop_daemon(SysSup) ->
- ssh_system_sup:stop_system(server, SysSup).
+ ssh_system_sup:stop_system(SysSup).
-spec stop_daemon(inet:ip_address(), inet:port_number()) -> ok.
@@ -567,8 +565,7 @@ stop_daemon(Address, Port, Profile) ->
lists:foreach(fun({Sup,_Addr}) ->
stop_daemon(Sup)
end,
- ssh_system_sup:addresses(server,
- #address{address=Address,
+ ssh_system_sup:addresses(#address{address=Address,
port=Port,
profile=Profile})).
diff --git a/lib/ssh/src/ssh_info.erl b/lib/ssh/src/ssh_info.erl
index aa7324b58805..625d8109e1b7 100644
--- a/lib/ssh/src/ssh_info.erl
+++ b/lib/ssh/src/ssh_info.erl
@@ -131,13 +131,25 @@ format_sup(server, {{{ssh_system_sup,LocalAddress},Pid,supervisor,[ssh_system_su
walk_tree(server, Children, ?inc(Indent)),
io_lib:nl() % Separate system supervisors by an empty line
];
-format_sup(client, {{{ssh_system_sup,LocalAddress},Pid,supervisor,[ssh_system_sup]}, _Spec, Children}, Indent) ->
- [indent(Indent),
- io_lib:format("Local: ~s sys_sup=~s~n", [format_address(LocalAddress), print_pid(Pid)]),
- walk_tree(client, Children, ?inc(Indent)),
- io_lib:nl() % Separate system supervisors by an empty line
+format_sup(client,
+ {{Ref,SubSysSup,supervisor,[ssh_subsystem_sup]}, _SubSysSpec,
+ [{{connection,ConnPid,worker,[ssh_connection_handler]}, _ConnSpec}
+ | Children]
+ },
+ Indent) when is_reference(Ref) ->
+ [io_lib:format("~sLocal: ~s~n"
+ "~sRemote: ~s (Version: ~s)~n"
+ "~sConnectionRef=~s, subsys_sup=~s~n",
+ [indent(Indent), local_addr(ConnPid),
+ indent(Indent), peer_addr(ConnPid), peer_version(client,ConnPid),
+ indent(Indent), print_pid(ConnPid), print_pid(SubSysSup)
+ ]),
+ walk_tree(client,
+ [{H,{connref,ConnPid},Cs} || {H,_,Cs} <- Children],
+ ?inc(Indent)),
+ io_lib:nl() % Separate sub system supervisors by an empty line
];
-format_sup(Role,
+format_sup(server,
{{Ref,SubSysSup,supervisor,[ssh_subsystem_sup]}, _SubSysSpec,
[{{connection,ConnPid,worker,[ssh_connection_handler]}, _ConnSpec}
| Children]
@@ -145,10 +157,10 @@ format_sup(Role,
Indent) when is_reference(Ref) ->
[io_lib:format("~sRemote: ~s (Version: ~s)~n"
"~sConnectionRef=~s, subsys_sup=~s~n",
- [indent(Indent), peer_addr(ConnPid), peer_version(Role,ConnPid),
+ [indent(Indent), peer_addr(ConnPid), peer_version(server,ConnPid),
indent(Indent), print_pid(ConnPid), print_pid(SubSysSup)
]),
- walk_tree(Role,
+ walk_tree(server,
[{H,{connref,ConnPid},Cs} || {H,_,Cs} <- Children],
?inc(Indent)),
io_lib:nl() % Separate sub system supervisors by an empty line
@@ -250,7 +262,17 @@ peer_addr(Pid) ->
catch
_:_ -> "?"
end.
-
+
+local_addr(Pid) ->
+ try
+ [{socket,Socket}] =
+ ssh_connection_handler:connection_info(Pid, [socket]),
+ {ok, AddrPort} = inet:sockname(Socket),
+ ssh_lib:format_address_port(AddrPort)
+ catch
+ _:_ -> "?"
+ end.
+
format_address(#address{address=Addr, port=Port, profile=Prof}) ->
io_lib:format("~s (profile ~p)", [ssh_lib:format_address_port({Addr,Port}),Prof]);
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index 6bde7299657c..799f262eef31 100644
--- a/lib/ssh/src/ssh_system_sup.erl
+++ b/lib/ssh/src/ssh_system_sup.erl
@@ -33,12 +33,11 @@
-export([start_link/3,
stop_listener/1,
- stop_system/2,
- start_system/3,
+ stop_system/1,
+ start_system/2,
start_subsystem/4,
get_daemon_listen_address/1,
addresses/1,
- addresses/2,
get_options/2,
get_acceptor_options/1,
replace_acceptor_options/2
@@ -51,28 +50,27 @@
%%% API
%%%=========================================================================
-start_system(Role, Address0, Options) ->
- case find_system_sup(Role, Address0) of
+start_system(Address0, Options) ->
+ case find_system_sup(Address0) of
{ok,{SysPid,Address}} ->
restart_acceptor(SysPid, Address, Options);
{error,not_found} ->
- supervisor:start_child(sup(Role),
+ supervisor:start_child(sshd_sup,
#{id => {?MODULE,Address0},
- start => {?MODULE, start_link, [Role, Address0, Options]},
+ start => {?MODULE, start_link, [server, Address0, Options]},
restart => temporary,
type => supervisor
})
end.
%%%----------------------------------------------------------------
-stop_system(Role, SysSup) when is_pid(SysSup) ->
- case lists:keyfind(SysSup, 2, supervisor:which_children(sup(Role))) of
- {{?MODULE,Name}, SysSup, _, _} -> stop_system(Role, Name);
- false -> undefind
+stop_system(SysSup) when is_pid(SysSup) ->
+ case lists:keyfind(SysSup, 2, supervisor:which_children(sup(server))) of
+ {{?MODULE, Id}, SysSup, _, _} -> stop_system(Id);
+ false -> ok
end;
-stop_system(Role, Name) ->
- supervisor:terminate_child(sup(Role), {?MODULE,Name}).
-
+stop_system(Id) ->
+ supervisor:terminate_child(sup(server), {?MODULE, Id}).
%%%----------------------------------------------------------------
stop_listener(SystemSup) when is_pid(SystemSup) ->
@@ -94,43 +92,49 @@ get_daemon_listen_address(SystemSup) ->
end.
%%%----------------------------------------------------------------
-%%% Start the subsystem child. It is a child of the system supervisor (callback = this module)
-start_subsystem(Role, Address=#address{}, Socket, Options0) ->
- Options = ?PUT_INTERNAL_OPT([{user_pid, self()}], Options0),
+%%% Start the subsystem child. It is a significant child of the system
+%%% supervisor (callback = this module) for server and non-significant
+%%% child of sshc_sup for client
+start_subsystem(Role = client, _, Socket, Options) ->
+ do_start_subsystem(Role, sup(client), false, Socket, Options);
+start_subsystem(Role = server, Address=#address{}, Socket, Options) ->
+ case get_system_sup(Address, Options) of
+ {ok, SysPid} ->
+ do_start_subsystem(Role, SysPid, true, Socket, Options);
+ Others ->
+ Others
+ end.
+
+do_start_subsystem(Role, SupPid, Significant, Socket, Options0) ->
Id = make_ref(),
- case get_system_sup(Role, Address, Options) of
- {ok,SysPid} ->
- case supervisor:start_child(SysPid,
- #{id => Id,
- start => {ssh_subsystem_sup, start_link,
- [Role,Id,Socket,Options]
- },
- restart => temporary,
- significant => true,
- type => supervisor
- })
- of
- {ok,_SubSysPid} ->
- try
- receive
- {new_connection_ref, Id, ConnPid} ->
- ssh_connection_handler:takeover(ConnPid, Role, Socket, Options)
- after 10000 ->
-
- error(timeout)
- end
- catch
- error:{badmatch,{error,Error}} ->
- {error,Error};
- error:timeout ->
- %% The connection was started, but the takover procedure timed out,
- %% therefore it exists a subtree, but it is not quite ready and
- %% must be removed (by the supervisor above):
- supervisor:terminate_child(SysPid, Id),
- {error, connection_start_timeout}
- end;
- Others ->
- Others
+ Options = ?PUT_INTERNAL_OPT([{user_pid, self()}], Options0),
+ case supervisor:start_child(SupPid,
+ #{id => Id,
+ start => {ssh_subsystem_sup, start_link,
+ [Role,Id,Socket,Options]
+ },
+ restart => temporary,
+ significant => Significant,
+ type => supervisor
+ })
+ of
+ {ok,_SubSysPid} ->
+ try
+ receive
+ {new_connection_ref, Id, ConnPid} ->
+ ssh_connection_handler:takeover(ConnPid, Role, Socket, Options)
+ after 10000 ->
+ error(timeout)
+ end
+ catch
+ error:{badmatch,{error,Error}} ->
+ {error,Error};
+ error:timeout ->
+ %% The connection was started, but the takover procedure timed out,
+ %% therefore it exists a subtree, but it is not quite ready and
+ %% must be removed (by the supervisor above):
+ supervisor:terminate_child(SupPid, Id),
+ {error, connection_start_timeout}
end;
Others ->
Others
@@ -143,12 +147,9 @@ start_link(Role, Address, Options) ->
%%%----------------------------------------------------------------
-addresses(Role) ->
- addresses(Role, #address{address=any, port=any, profile=any}).
-
-addresses(Role, #address{address=Address, port=Port, profile=Profile}) ->
- [{SysSup,A} || {{ssh_system_sup,A},SysSup,supervisor,_} <-
- supervisor:which_children(sup(Role)),
+addresses(#address{address=Address, port=Port, profile=Profile}) ->
+ [{SysSup,A} || {{ssh_system_sup,A},SysSup,supervisor,_} <-
+ supervisor:which_children(sshd_sup),
Address == any orelse A#address.address == Address,
Port == any orelse A#address.port == Port,
Profile == any orelse A#address.profile == Profile].
@@ -233,19 +234,20 @@ lookup(SupModule, SystemSup) ->
lists:keyfind([SupModule], 4,
supervisor:which_children(SystemSup)).
-get_system_sup(Role, Address0, Options) ->
- case find_system_sup(Role, Address0) of
+get_system_sup(Address0, Options) ->
+ case find_system_sup(Address0) of
{ok,{SysPid,_Address}} ->
{ok,SysPid};
{error,not_found} ->
- start_system(Role, Address0, Options);
+ start_system(Address0, Options);
{error,Error} ->
{error,Error}
end.
-find_system_sup(Role, Address0) ->
- case addresses(Role, Address0) of
- [{SysSupPid,Address}] -> {ok,{SysSupPid,Address}};
+find_system_sup(Address0) ->
+ case addresses(Address0) of
+ [{SysSupPid,Address}] ->
+ {ok,{SysSupPid,Address}};
[] -> {error,not_found};
[_,_|_] -> {error,ambiguous}
end.
diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl
index 76f1cbe2c4a6..9dc9f74fc60e 100644
--- a/lib/ssh/test/ssh_sup_SUITE.erl
+++ b/lib/ssh/test/ssh_sup_SUITE.erl
@@ -131,26 +131,27 @@ sshc_subtree(Config) when is_list(Config) ->
Pid1 = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
{save_accepted_host, false},
- {user_interaction, false},
- {user, ?USER}, {password, ?PASSWD},{user_dir, UserDir}]),
-
- ?wait_match([?SYSTEM_SUP(SysSup, #address{address=LocalIP, port=LocalPort, profile=?DEFAULT_PROFILE})
- ],
+ {user_interaction, false},
+ {user, ?USER},
+ {password, ?PASSWD},
+ {user_dir, UserDir}]),
+ ?wait_match([?SUB_SYSTEM_SUP(SubSysSup)],
supervisor:which_children(sshc_sup),
- [SysSup, LocalIP, LocalPort]),
- check_sshc_system_tree(SysSup, Pid1, LocalIP, LocalPort, Config),
-
+ [SubSysSup]),
+ check_sshc_system_tree(SubSysSup, Pid1, Config),
Pid2 = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
{save_accepted_host, false},
- {user_interaction, false},
- {user, ?USER}, {password, ?PASSWD}, {user_dir, UserDir}]),
- ?wait_match([?SYSTEM_SUP(_,_),
- ?SYSTEM_SUP(_,_)
+ {user_interaction, false},
+ {user, ?USER},
+ {password, ?PASSWD},
+ {user_dir, UserDir}]),
+ ?wait_match([?SUB_SYSTEM_SUP(_),
+ ?SUB_SYSTEM_SUP(_)
],
supervisor:which_children(sshc_sup)),
ssh:close(Pid1),
- ?wait_match([?SYSTEM_SUP(_,_)
+ ?wait_match([?SUB_SYSTEM_SUP(_)
],
supervisor:which_children(sshc_sup)),
ssh:close(Pid2),
@@ -428,9 +429,9 @@ check_sshd_system_tree(Daemon, Host, Port, Config) ->
ssh:close(ClientConn).
-check_sshc_system_tree(SysSup, Connection, _LocalIP, _LocalPort, _Config) ->
+check_sshc_system_tree(SubSysSup, Connection, _Config) ->
?wait_match([?SUB_SYSTEM_SUP(SubSysSup)],
- supervisor:which_children(SysSup),
+ supervisor:which_children(sshc_sup),
[SubSysSup]),
?wait_match([{_,FwdAccSup, supervisor,[ssh_tcpip_forward_acceptor_sup]},
{_,_,supervisor,[ssh_channel_sup]},
From 6b2e8e17e1f088bec8d312d0cdc607444b4c1a8c Mon Sep 17 00:00:00 2001
From: Jakub Witczak
Date: Thu, 19 Sep 2024 11:48:23 +0200
Subject: [PATCH 024/217] ssh: rename ssh_subsystem_sup to ssh_connection_sup
- rename in order to improve supervision readability
---
lib/ssh/src/Makefile | 2 +-
lib/ssh/src/ssh.app.src | 4 +-
lib/ssh/src/ssh.erl | 4 +-
lib/ssh/src/ssh_acceptor.erl | 4 +-
lib/ssh/src/ssh_connect.hrl | 2 +-
lib/ssh/src/ssh_connection.erl | 20 ++---
lib/ssh/src/ssh_connection_handler.erl | 20 ++---
...bsystem_sup.erl => ssh_connection_sup.erl} | 59 ++++++-------
lib/ssh/src/ssh_info.erl | 10 +--
lib/ssh/src/ssh_system_sup.erl | 18 ++--
lib/ssh/test/ssh.cover | 2 +-
lib/ssh/test/ssh_limited.cover | 2 +-
lib/ssh/test/ssh_protocol_SUITE.erl | 2 +-
lib/ssh/test/ssh_sup_SUITE.erl | 84 +++++++++----------
14 files changed, 113 insertions(+), 120 deletions(-)
rename lib/ssh/src/{ssh_subsystem_sup.erl => ssh_connection_sup.erl} (63%)
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index 2fcb1643013b..ee25174ed858 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -80,7 +80,7 @@ MODULES= \
ssh_sftpd \
ssh_sftpd_file\
ssh_shell \
- ssh_subsystem_sup \
+ ssh_connection_sup \
ssh_system_sup \
ssh_tcpip_forward_srv \
ssh_tcpip_forward_client \
diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src
index 2cb8d8048882..4ce8fee692cf 100644
--- a/lib/ssh/src/ssh.app.src
+++ b/lib/ssh/src/ssh.app.src
@@ -36,7 +36,7 @@
ssh_sftpd,
ssh_sftpd_file,
ssh_sftpd_file_api,
- ssh_subsystem_sup,
+ ssh_connection_sup,
ssh_tcpip_forward_client,
ssh_tcpip_forward_srv,
ssh_tcpip_forward_acceptor_sup,
@@ -51,7 +51,7 @@
ssh_acceptor,
ssh_channel_sup,
ssh_connection_handler,
- ssh_subsystem_sup,
+ ssh_connection_sup,
ssh_system_sup
]},
{default_filter, rm} %% rm | filter
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 714d4390f1e8..052f5efa8842 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -248,7 +248,7 @@ continue_connect(Socket, Options0, NegTimeout) ->
port = SockPort,
profile = ?GET_OPT(profile,Options)
},
- ssh_system_sup:start_subsystem(client, Address, Socket, Options).
+ ssh_system_sup:start_connection(client, Address, Socket, Options).
%%--------------------------------------------------------------------
-spec close(ConnectionRef) -> ok | {error,term()} when
@@ -343,7 +343,7 @@ daemon(Socket, UserOptions) ->
profile = ?GET_OPT(profile,Options0)
},
Options = ?PUT_INTERNAL_OPT({connected_socket, Socket}, Options0),
- case ssh_system_sup:start_subsystem(server, Address, Socket, Options) of
+ case ssh_system_sup:start_connection(server, Address, Socket, Options) of
{ok,Pid} ->
{ok,Pid};
{error, {already_started, _}} ->
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index 00587eecbae1..54bebd12d34c 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -187,7 +187,7 @@ handle_connection(Address, Port, _Peer, Options, Socket, _MaxSessions, _NumSessi
handle_connection(Address, Port, Options0, Socket) ->
Options = ?PUT_INTERNAL_OPT([{user_pid, self()}
], Options0),
- ssh_system_sup:start_subsystem(server,
+ ssh_system_sup:start_connection(server,
#address{address = Address,
port = Port,
profile = ?GET_OPT(profile,Options)
@@ -243,7 +243,7 @@ handle_error(Reason, ToAddress, ToPort, FromAddress, FromPort) ->
%%%----------------------------------------------------------------
number_of_connections(SysSupPid) ->
- lists:foldl(fun({_Ref,_Pid,supervisor,[ssh_subsystem_sup]}, N) -> N+1;
+ lists:foldl(fun({_Ref,_Pid,supervisor,[ssh_connection_sup]}, N) -> N+1;
(_, N) -> N
end, 0, supervisor:which_children(SysSupPid)).
diff --git a/lib/ssh/src/ssh_connect.hrl b/lib/ssh/src/ssh_connect.hrl
index 3bd53d59126a..4c6fdaefd4c3 100644
--- a/lib/ssh/src/ssh_connect.hrl
+++ b/lib/ssh/src/ssh_connect.hrl
@@ -269,5 +269,5 @@
suggest_window_size,
suggest_packet_size,
exec,
- sub_system_supervisor
+ connection_supervisor
}).
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index 34e97ba6ca1f..40096e1227c4 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -606,7 +606,7 @@ handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip",
suggest_window_size = WinSz,
suggest_packet_size = PktSz,
options = Options,
- sub_system_supervisor = SubSysSup
+ connection_supervisor = ConnectionSup
} = C,
client, _SSH) ->
{ReplyMsg, NextChId} =
@@ -614,7 +614,7 @@ handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip",
{ok, {ConnectToHost,ConnectToPort}} ->
case gen_tcp:connect(ConnectToHost, ConnectToPort, [{active,false}, binary]) of
{ok,Sock} ->
- {ok,Pid} = ssh_subsystem_sup:start_channel(client, SubSysSup, self(),
+ {ok,Pid} = ssh_connection_sup:start_channel(client, ConnectionSup, self(),
ssh_tcpip_forward_client, ChId,
[Sock], undefined, Options),
ssh_client_channel:cache_update(Cache,
@@ -664,7 +664,7 @@ handle_msg(#ssh_msg_channel_open{channel_type = "direct-tcpip",
suggest_window_size = WinSz,
suggest_packet_size = PktSz,
options = Options,
- sub_system_supervisor = SubSysSup
+ connection_supervisor = ConnectionSup
} = C,
server, _SSH) ->
{ReplyMsg, NextChId} =
@@ -680,7 +680,7 @@ handle_msg(#ssh_msg_channel_open{channel_type = "direct-tcpip",
case gen_tcp:connect(binary_to_list(HostToConnect), PortToConnect,
[{active,false}, binary]) of
{ok,Sock} ->
- {ok,Pid} = ssh_subsystem_sup:start_channel(server, SubSysSup, self(),
+ {ok,Pid} = ssh_connection_sup:start_channel(server, ConnectionSup, self(),
ssh_tcpip_forward_srv, ChId,
[Sock], undefined, Options),
ssh_client_channel:cache_update(Cache,
@@ -912,8 +912,8 @@ handle_msg(#ssh_msg_global_request{name = <<"tcpip-forward">>,
{[{connection_reply, request_failure_msg()}], Connection};
true ->
- SubSysSup = ?GET_INTERNAL_OPT(subsystem_sup, Opts),
- FwdSup = ssh_subsystem_sup:tcpip_fwd_supervisor(SubSysSup),
+ ConnectionSup = ?GET_INTERNAL_OPT(connection_sup, Opts),
+ FwdSup = ssh_connection_sup:tcpip_fwd_supervisor(ConnectionSup),
ConnPid = self(),
case ssh_tcpip_forward_acceptor:supervised_start(FwdSup,
{ListenAddrStr, ListenPort},
@@ -1127,22 +1127,22 @@ setup_session(#connection{channel_cache = Cache,
start_cli(#connection{options = Options,
cli_spec = CliSpec,
exec = Exec,
- sub_system_supervisor = SubSysSup}, ChannelId) ->
+ connection_supervisor = ConnectionSup}, ChannelId) ->
case CliSpec of
no_cli ->
{error, cli_disabled};
{CbModule, Args} ->
- ssh_subsystem_sup:start_channel(server, SubSysSup, self(), CbModule, ChannelId, Args, Exec, Options)
+ ssh_connection_sup:start_channel(server, ConnectionSup, self(), CbModule, ChannelId, Args, Exec, Options)
end.
start_subsystem(BinName, #connection{options = Options,
- sub_system_supervisor = SubSysSup},
+ connection_supervisor = ConnectionSup},
#channel{local_id = ChannelId}, _ReplyMsg) ->
Name = binary_to_list(BinName),
case check_subsystem(Name, Options) of
{Callback, Opts} when is_atom(Callback), Callback =/= none ->
- ssh_subsystem_sup:start_channel(server, SubSysSup, self(), Callback, ChannelId, Opts, undefined, Options);
+ ssh_connection_sup:start_channel(server, ConnectionSup, self(), Callback, ChannelId, Opts, undefined, Options);
{none, _} ->
{error, bad_subsystem};
{_, _} ->
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 93fd84c63d7f..162ceccfd594 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -110,7 +110,7 @@ start_link(Role, Id, Socket, Options) ->
%% Announce the ConnectionRef to the system supervisor so it could
%% 1) initiate the socket handover, and
%% 2) be returned to whoever called for example ssh:connect; the Pid
- %% returned from this function is "consumed" by the subsystem
+ %% returned from this function is "consumed" by the connection
%% supervisor.
?GET_INTERNAL_OPT(user_pid,Options) ! {new_connection_ref, Id, Pid},
{ok, Pid};
@@ -195,8 +195,8 @@ open_channel(ConnectionHandler,
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
start_channel(ConnectionHandler, CallbackModule, ChannelId, Args, Exec) ->
- {ok, {SubSysSup,Role,Opts}} = call(ConnectionHandler, get_misc),
- ssh_subsystem_sup:start_channel(Role, SubSysSup,
+ {ok, {ConnectionSup,Role,Opts}} = call(ConnectionHandler, get_misc),
+ ssh_connection_sup:start_channel(Role, ConnectionSup,
ConnectionHandler, CallbackModule, ChannelId,
Args, Exec, Opts).
@@ -435,7 +435,7 @@ init_connection_record(Role, Socket, Opts) ->
suggest_packet_size = PktSz,
requests = [],
options = Opts,
- sub_system_supervisor = ?GET_INTERNAL_OPT(subsystem_sup, Opts)
+ connection_supervisor = ?GET_INTERNAL_OPT(connection_sup, Opts)
},
case Role of
server ->
@@ -1002,8 +1002,8 @@ handle_event({call,From}, {eof, ChannelId}, StateName, D0)
handle_event({call,From}, get_misc, StateName,
#data{connection_state = #connection{options = Opts}} = D) when ?CONNECTED(StateName) ->
- SubSysSup = ?GET_INTERNAL_OPT(subsystem_sup, Opts),
- Reply = {ok, {SubSysSup, ?role(StateName), Opts}},
+ ConnectionSup = ?GET_INTERNAL_OPT(connection_sup, Opts),
+ Reply = {ok, {ConnectionSup, ?role(StateName), Opts}},
{keep_state, D, [{reply,From,Reply}]};
handle_event({call,From},
@@ -1266,9 +1266,9 @@ handle_event(info, check_cache, _, D) ->
handle_event(info, {fwd_connect_received, Sock, ChId, ChanCB}, StateName, #data{connection_state = Connection}) ->
#connection{options = Options,
channel_cache = Cache,
- sub_system_supervisor = SubSysSup} = Connection,
+ connection_supervisor = ConnectionSup} = Connection,
Channel = ssh_client_channel:cache_lookup(Cache, ChId),
- {ok,Pid} = ssh_subsystem_sup:start_channel(?role(StateName), SubSysSup, self(), ChanCB, ChId, [Sock], undefined, Options),
+ {ok,Pid} = ssh_connection_sup:start_channel(?role(StateName), ConnectionSup, self(), ChanCB, ChId, [Sock], undefined, Options),
ssh_client_channel:cache_update(Cache, Channel#channel{user=Pid}),
gen_tcp:controlling_process(Sock, Pid),
inet:setopts(Sock, [{active,once}]),
@@ -1277,8 +1277,8 @@ handle_event(info, {fwd_connect_received, Sock, ChId, ChanCB}, StateName, #data{
handle_event({call,From},
{handle_direct_tcpip, ListenHost, ListenPort, ConnectToHost, ConnectToPort, _Timeout},
_StateName,
- #data{connection_state = #connection{sub_system_supervisor=SubSysSup}}) ->
- case ssh_tcpip_forward_acceptor:supervised_start(ssh_subsystem_sup:tcpip_fwd_supervisor(SubSysSup),
+ #data{connection_state = #connection{connection_supervisor=ConnectionSup}}) ->
+ case ssh_tcpip_forward_acceptor:supervised_start(ssh_connection_sup:tcpip_fwd_supervisor(ConnectionSup),
{ListenHost, ListenPort},
{ConnectToHost, ConnectToPort},
"direct-tcpip", ssh_tcpip_forward_client,
diff --git a/lib/ssh/src/ssh_subsystem_sup.erl b/lib/ssh/src/ssh_connection_sup.erl
similarity index 63%
rename from lib/ssh/src/ssh_subsystem_sup.erl
rename to lib/ssh/src/ssh_connection_sup.erl
index 2eb61c6236bd..2774e4a7a44e 100644
--- a/lib/ssh/src/ssh_subsystem_sup.erl
+++ b/lib/ssh/src/ssh_connection_sup.erl
@@ -19,10 +19,10 @@
%%
%%
%%----------------------------------------------------------------------
-%% Purpose: The ssh subsystem supervisor
+%% Purpose: The ssh connection supervisor
%%----------------------------------------------------------------------
--module(ssh_subsystem_sup).
+-module(ssh_connection_sup).
-behaviour(supervisor).
@@ -51,51 +51,46 @@ start_channel(Role, SupPid, ConnRef, Callback, Id, Args, Exec, Opts) ->
ChannelSup = channel_supervisor(SupPid),
ssh_channel_sup:start_child(Role, ChannelSup, ConnRef, Callback, Id, Args, Exec, Opts).
-tcpip_fwd_supervisor(SubSysSup) ->
- find_child(tcpip_forward_acceptor_sup, SubSysSup).
+tcpip_fwd_supervisor(ConnectionSup) ->
+ find_child(tcpip_forward_acceptor_sup, ConnectionSup).
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
init([Role, Id, Socket, Options]) ->
- SubSysSup = self(),
+ ConnectionSup = self(),
SupFlags = #{strategy => one_for_all,
auto_shutdown => any_significant,
intensity => 0,
- period => 3600
- },
- ChildSpecs = [#{id => connection,
- restart => temporary,
- type => worker,
- significant => true,
- start => {ssh_connection_handler,
- start_link,
- [Role, Id, Socket,
- ?PUT_INTERNAL_OPT([
- {subsystem_sup, SubSysSup}
- ], Options)
- ]
- }
- },
- #{id => channel_sup,
- restart => temporary,
- type => supervisor,
- start => {ssh_channel_sup, start_link, [Options]}
- },
+ period => 3600},
+ ChildSpecs =
+ [#{id => connection,
+ restart => temporary,
+ type => worker,
+ significant => true,
+ start => {ssh_connection_handler,
+ start_link,
+ [Role, Id, Socket,
+ ?PUT_INTERNAL_OPT([{connection_sup, ConnectionSup}], Options)]}
+ },
+ #{id => channel_sup,
+ restart => temporary,
+ type => supervisor,
+ start => {ssh_channel_sup, start_link, [Options]}
+ },
- #{id => tcpip_forward_acceptor_sup,
- restart => temporary,
- type => supervisor,
- start => {ssh_tcpip_forward_acceptor_sup, start_link, []}
- }
- ],
+ #{id => tcpip_forward_acceptor_sup,
+ restart => temporary,
+ type => supervisor,
+ start => {ssh_tcpip_forward_acceptor_sup, start_link, []}
+ }],
{ok, {SupFlags,ChildSpecs}}.
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
-channel_supervisor(SubSysSup) -> find_child(channel_sup, SubSysSup).
+channel_supervisor(ConnectionSup) -> find_child(channel_sup, ConnectionSup).
find_child(Id, Sup) when is_pid(Sup) ->
try
diff --git a/lib/ssh/src/ssh_info.erl b/lib/ssh/src/ssh_info.erl
index 625d8109e1b7..365357b4d566 100644
--- a/lib/ssh/src/ssh_info.erl
+++ b/lib/ssh/src/ssh_info.erl
@@ -132,7 +132,7 @@ format_sup(server, {{{ssh_system_sup,LocalAddress},Pid,supervisor,[ssh_system_su
io_lib:nl() % Separate system supervisors by an empty line
];
format_sup(client,
- {{Ref,SubSysSup,supervisor,[ssh_subsystem_sup]}, _SubSysSpec,
+ {{Ref,ConnSup,supervisor,[ssh_connection_sup]}, _ConnSupSpec,
[{{connection,ConnPid,worker,[ssh_connection_handler]}, _ConnSpec}
| Children]
},
@@ -142,7 +142,7 @@ format_sup(client,
"~sConnectionRef=~s, subsys_sup=~s~n",
[indent(Indent), local_addr(ConnPid),
indent(Indent), peer_addr(ConnPid), peer_version(client,ConnPid),
- indent(Indent), print_pid(ConnPid), print_pid(SubSysSup)
+ indent(Indent), print_pid(ConnPid), print_pid(ConnSup)
]),
walk_tree(client,
[{H,{connref,ConnPid},Cs} || {H,_,Cs} <- Children],
@@ -150,15 +150,15 @@ format_sup(client,
io_lib:nl() % Separate sub system supervisors by an empty line
];
format_sup(server,
- {{Ref,SubSysSup,supervisor,[ssh_subsystem_sup]}, _SubSysSpec,
- [{{connection,ConnPid,worker,[ssh_connection_handler]}, _ConnSpec}
+ {{Ref,ConnSup,supervisor,[ssh_connection_sup]}, _ConnSupSpec,
+ [{{connection,ConnPid,worker,[ssh_connection_handler]}, _ConnSpec}
| Children]
},
Indent) when is_reference(Ref) ->
[io_lib:format("~sRemote: ~s (Version: ~s)~n"
"~sConnectionRef=~s, subsys_sup=~s~n",
[indent(Indent), peer_addr(ConnPid), peer_version(server,ConnPid),
- indent(Indent), print_pid(ConnPid), print_pid(SubSysSup)
+ indent(Indent), print_pid(ConnPid), print_pid(ConnSup)
]),
walk_tree(server,
[{H,{connref,ConnPid},Cs} || {H,_,Cs} <- Children],
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index 799f262eef31..8e0bc75df7ca 100644
--- a/lib/ssh/src/ssh_system_sup.erl
+++ b/lib/ssh/src/ssh_system_sup.erl
@@ -35,7 +35,7 @@
stop_listener/1,
stop_system/1,
start_system/2,
- start_subsystem/4,
+ start_connection/4,
get_daemon_listen_address/1,
addresses/1,
get_options/2,
@@ -92,25 +92,25 @@ get_daemon_listen_address(SystemSup) ->
end.
%%%----------------------------------------------------------------
-%%% Start the subsystem child. It is a significant child of the system
+%%% Start the connection child. It is a significant child of the system
%%% supervisor (callback = this module) for server and non-significant
%%% child of sshc_sup for client
-start_subsystem(Role = client, _, Socket, Options) ->
- do_start_subsystem(Role, sup(client), false, Socket, Options);
-start_subsystem(Role = server, Address=#address{}, Socket, Options) ->
+start_connection(Role = client, _, Socket, Options) ->
+ do_start_connection(Role, sup(client), false, Socket, Options);
+start_connection(Role = server, Address=#address{}, Socket, Options) ->
case get_system_sup(Address, Options) of
{ok, SysPid} ->
- do_start_subsystem(Role, SysPid, true, Socket, Options);
+ do_start_connection(Role, SysPid, true, Socket, Options);
Others ->
Others
end.
-do_start_subsystem(Role, SupPid, Significant, Socket, Options0) ->
+do_start_connection(Role, SupPid, Significant, Socket, Options0) ->
Id = make_ref(),
Options = ?PUT_INTERNAL_OPT([{user_pid, self()}], Options0),
case supervisor:start_child(SupPid,
#{id => Id,
- start => {ssh_subsystem_sup, start_link,
+ start => {ssh_connection_sup, start_link,
[Role,Id,Socket,Options]
},
restart => temporary,
@@ -118,7 +118,7 @@ do_start_subsystem(Role, SupPid, Significant, Socket, Options0) ->
type => supervisor
})
of
- {ok,_SubSysPid} ->
+ {ok,_ConnectionSupPid} ->
try
receive
{new_connection_ref, Id, ConnPid} ->
diff --git a/lib/ssh/test/ssh.cover b/lib/ssh/test/ssh.cover
index daf6c723b9b9..c4cac8daf5be 100644
--- a/lib/ssh/test/ssh.cover
+++ b/lib/ssh/test/ssh.cover
@@ -7,7 +7,7 @@
%% %% Supervisors
%% ssh_acceptor_sup, ssh_channel_sup,
- %% sshc_sup, sshd_sup, ssh_subsystem_sup, ssh_sup,
+ %% sshc_sup, sshd_sup, ssh_connection_sup, ssh_sup,
%% ssh_system_sup, ssh_tcpip_forward_acceptor_sup,
%% Test and/or info modules:
diff --git a/lib/ssh/test/ssh_limited.cover b/lib/ssh/test/ssh_limited.cover
index 29c0121ae1ff..64904c9ce737 100644
--- a/lib/ssh/test/ssh_limited.cover
+++ b/lib/ssh/test/ssh_limited.cover
@@ -9,7 +9,7 @@
%% Supervisors
ssh_acceptor_sup, ssh_channel_sup,
- sshc_sup, sshd_sup, ssh_subsystem_sup, ssh_sup,
+ sshc_sup, sshd_sup, ssh_connection_sup, ssh_sup,
ssh_system_sup, ssh_tcpip_forward_acceptor_sup,
%% Test and/or info modules:
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index 666ac76f6334..7a99976e3131 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -1177,7 +1177,7 @@ find_handshake_parent([{{ssh_acceptor_sup,{address,_,Port,_}},
{Parents,Handshakers} = lists:unzip(ParentHandshakers),
find_handshake_parent(T, Port, {AccP++Parents, AccC, AccH++Handshakers});
-find_handshake_parent([{_Ref,PidS,supervisor,[ssh_subsystem_sup]}|T], Port, {AccP,AccC,AccH}) ->
+find_handshake_parent([{_Ref,PidS,supervisor,[ssh_connection_sup]}|T], Port, {AccP,AccC,AccH}) ->
Connections =
[Pid || {connection,Pid,worker,[ssh_connection_handler]} <- supervisor:which_children(PidS)],
find_handshake_parent(T, Port, {AccP, AccC++Connections, AccH});
diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl
index 9dc9f74fc60e..d76ce9edf6d5 100644
--- a/lib/ssh/test/ssh_sup_SUITE.erl
+++ b/lib/ssh/test/ssh_sup_SUITE.erl
@@ -52,10 +52,13 @@
-define(SSHC_SUP(Pid), {sshc_sup, Pid, supervisor, [supervisor]}).
-define(SSHD_SUP(Pid), {sshd_sup, Pid, supervisor, [supervisor]}).
--define(SYSTEM_SUP(Pid,Address), {{ssh_system_sup, Address}, Pid, supervisor,[ssh_system_sup]}).
--define(SUB_SYSTEM_SUP(Pid), {_,Pid, supervisor,[ssh_subsystem_sup]}).
--define(ACCEPTOR_SUP(Pid,Address), {{ssh_acceptor_sup,Address},Pid,supervisor,[ssh_acceptor_sup]}).
--define(ACCEPTOR_WORKER(Pid,Address), {{ssh_acceptor_sup,Address},Pid,worker,[ssh_acceptor]}).
+-define(SYSTEM_SUP(Pid,Address),
+ {{ssh_system_sup, Address}, Pid, supervisor,[ssh_system_sup]}).
+-define(CONNECTION_SUP(Pid), {_,Pid, supervisor,[ssh_connection_sup]}).
+-define(ACCEPTOR_SUP(Pid,Address),
+ {{ssh_acceptor_sup,Address},Pid,supervisor,[ssh_acceptor_sup]}).
+-define(ACCEPTOR_WORKER(Pid,Address),
+ {{ssh_acceptor_sup,Address},Pid,worker,[ssh_acceptor]}).
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
@@ -135,23 +138,23 @@ sshc_subtree(Config) when is_list(Config) ->
{user, ?USER},
{password, ?PASSWD},
{user_dir, UserDir}]),
- ?wait_match([?SUB_SYSTEM_SUP(SubSysSup)],
+ ?wait_match([?CONNECTION_SUP(ConnectionSup)],
supervisor:which_children(sshc_sup),
- [SubSysSup]),
- check_sshc_system_tree(SubSysSup, Pid1, Config),
+ [ConnectionSup]),
+ check_sshc_system_tree(ConnectionSup, Pid1, Config),
Pid2 = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
{save_accepted_host, false},
{user_interaction, false},
{user, ?USER},
{password, ?PASSWD},
{user_dir, UserDir}]),
- ?wait_match([?SUB_SYSTEM_SUP(_),
- ?SUB_SYSTEM_SUP(_)
+ ?wait_match([?CONNECTION_SUP(_),
+ ?CONNECTION_SUP(_)
],
supervisor:which_children(sshc_sup)),
ssh:close(Pid1),
- ?wait_match([?SUB_SYSTEM_SUP(_)
+ ?wait_match([?CONNECTION_SUP(_)
],
supervisor:which_children(sshc_sup)),
ssh:close(Pid2),
@@ -305,8 +308,8 @@ shell_channel_tree(Config) ->
{user_interaction, true},
{user_dir, UserDir}]),
- [SubSysSup,_ChPid|_] = Sups0 = chk_empty_con_daemon(Daemon),
-
+ [ConnectionSup,_ChPid|_] = Sups0 = chk_empty_con_daemon(Daemon),
+
{ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
ok = ssh_connection:shell(ConnectionRef,ChannelId0),
success = ssh_connection:ptty_alloc(ConnectionRef, ChannelId0, [{pty_opts,[{onlcr,1}]}]),
@@ -315,7 +318,7 @@ shell_channel_tree(Config) ->
{_,ChSup,supervisor,[ssh_channel_sup]},
{connection,_,worker,[ssh_connection_handler]}
],
- supervisor:which_children(SubSysSup),
+ supervisor:which_children(ConnectionSup),
[ChSup]),
?wait_match([{_,GroupPid,worker,[ssh_server_channel]}
],
@@ -332,9 +335,9 @@ shell_channel_tree(Config) ->
{ssh_cm,ConnectionRef, {data, ChannelId0, 0, <<"TimeoutShell started!",Rest/binary>>}} ->
ct:log("TimeoutShell started. Rest = ~p", [Rest]),
receive
- %%---- wait for the subsystem to terminate
+ %%---- wait for the connection to terminate
{ssh_cm,ConnectionRef,{closed,ChannelId0}} ->
- ct:log("Subsystem terminated",[]),
+ ct:log("Connection terminated",[]),
case {chk_empty_con_daemon(Daemon),
process_info(GroupPid),
process_info(ShellPid)} of
@@ -365,23 +368,23 @@ shell_channel_tree(Config) ->
end.
chk_empty_con_daemon(Daemon) ->
- ?wait_match([?SUB_SYSTEM_SUP(SubSysSup),
+ ?wait_match([?CONNECTION_SUP(ConnectionSup),
?ACCEPTOR_SUP(AccSup,_)
],
supervisor:which_children(Daemon),
- [SubSysSup,AccSup]),
+ [ConnectionSup,AccSup]),
?wait_match([{_,FwdAccSup, supervisor,[ssh_tcpip_forward_acceptor_sup]},
{_,ChSup,supervisor,[ssh_channel_sup]},
{connection,ServerConnPid,worker,[ssh_connection_handler]}
],
- supervisor:which_children(SubSysSup),
+ supervisor:which_children(ConnectionSup),
[ChSup,FwdAccSup,ServerConnPid]),
?wait_match([], supervisor:which_children(FwdAccSup)),
?wait_match([], supervisor:which_children(ChSup)),
?wait_match([?ACCEPTOR_WORKER(_,_)],
supervisor:which_children(AccSup),
[]),
- [SubSysSup, ChSup, ServerConnPid, AccSup, FwdAccSup].
+ [ConnectionSup, ChSup, ServerConnPid, AccSup, FwdAccSup].
%%-------------------------------------------------------------------------
%% Help functions
@@ -389,22 +392,18 @@ chk_empty_con_daemon(Daemon) ->
check_sshd_system_tree(Daemon, Host, Port, Config) ->
UserDir = proplists:get_value(userdir, Config),
ClientConn = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
- {user_interaction, false},
- {user, ?USER},
- {password, ?PASSWD},
- {user_dir, UserDir}]),
-
- ?wait_match([?SUB_SYSTEM_SUP(SubSysSup),
- ?ACCEPTOR_SUP(AccSup,_)
- ],
+ {user_interaction, false},
+ {user, ?USER},
+ {password, ?PASSWD},
+ {user_dir, UserDir}]),
+ ?wait_match([?CONNECTION_SUP(ConnectionSup),
+ ?ACCEPTOR_SUP(AccSup,_)],
supervisor:which_children(Daemon),
- [SubSysSup,AccSup]),
-
+ [ConnectionSup,AccSup]),
?wait_match([{_,FwdAccSup, supervisor,[ssh_tcpip_forward_acceptor_sup]},
{_,_,supervisor,[ssh_channel_sup]},
- {connection,ServerConn,worker,[ssh_connection_handler]}
- ],
- supervisor:which_children(SubSysSup),
+ {connection,ServerConn,worker,[ssh_connection_handler]}],
+ supervisor:which_children(ConnectionSup),
[FwdAccSup,ServerConn]),
?wait_match([], supervisor:which_children(FwdAccSup)),
@@ -415,9 +414,8 @@ check_sshd_system_tree(Daemon, Host, Port, Config) ->
{ok,PidC} = ssh_sftp:start_channel(ClientConn),
?wait_match([{_,FwdAccSup, supervisor,[ssh_tcpip_forward_acceptor_sup]},
{_,ChSup,supervisor,[ssh_channel_sup]},
- {connection,ServerConn,worker,[ssh_connection_handler]}
- ],
- supervisor:which_children(SubSysSup),
+ {connection,ServerConn,worker,[ssh_connection_handler]}],
+ supervisor:which_children(ConnectionSup),
[ChSup,ServerConn]),
?wait_match([{_,PidS,worker,[ssh_server_channel]}],
@@ -429,15 +427,15 @@ check_sshd_system_tree(Daemon, Host, Port, Config) ->
ssh:close(ClientConn).
-check_sshc_system_tree(SubSysSup, Connection, _Config) ->
- ?wait_match([?SUB_SYSTEM_SUP(SubSysSup)],
+check_sshc_system_tree(ConnectionSup, Connection, _Config) ->
+ ?wait_match([?CONNECTION_SUP(ConnectionSup)],
supervisor:which_children(sshc_sup),
- [SubSysSup]),
+ [ConnectionSup]),
?wait_match([{_,FwdAccSup, supervisor,[ssh_tcpip_forward_acceptor_sup]},
{_,_,supervisor,[ssh_channel_sup]},
{connection,Connection,worker,[ssh_connection_handler]}
],
- supervisor:which_children(SubSysSup),
+ supervisor:which_children(ConnectionSup),
[FwdAccSup]),
?wait_match([], supervisor:which_children(FwdAccSup)),
@@ -446,7 +444,7 @@ check_sshc_system_tree(SubSysSup, Connection, _Config) ->
{_,ChSup,supervisor, [ssh_channel_sup]},
{connection,Connection,worker,[ssh_connection_handler]}
],
- supervisor:which_children(SubSysSup),
+ supervisor:which_children(ConnectionSup),
[ChSup,FwdAccSup]),
?wait_match([{_,ChPid1,worker,[ssh_client_channel]}
@@ -459,7 +457,7 @@ check_sshc_system_tree(SubSysSup, Connection, _Config) ->
{_,ChSup,supervisor, [ssh_channel_sup]},
{connection,Connection,worker,[ssh_connection_handler]}
],
- supervisor:which_children(SubSysSup),
+ supervisor:which_children(ConnectionSup),
[ChSup,FwdAccSup]),
?wait_match([{_,ChPid2,worker,[ssh_client_channel]},
@@ -474,7 +472,7 @@ check_sshc_system_tree(SubSysSup, Connection, _Config) ->
{_,ChSup,supervisor, [ssh_channel_sup]},
{connection,Connection,worker,[ssh_connection_handler]}
],
- supervisor:which_children(SubSysSup),
+ supervisor:which_children(ConnectionSup),
[ChSup,FwdAccSup]),
?wait_match([{_,ChPid2,worker,[ssh_client_channel]}
@@ -488,7 +486,7 @@ check_sshc_system_tree(SubSysSup, Connection, _Config) ->
{_,ChSup,supervisor, [ssh_channel_sup]},
{connection,Connection,worker,[ssh_connection_handler]}
],
- supervisor:which_children(SubSysSup),
+ supervisor:which_children(ConnectionSup),
[ChSup,FwdAccSup]),
?wait_match([], supervisor:which_children(ChSup)),
From 519b1e601f1172d6a8d29b4e1ce26f4d26fe44bb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20H=C3=B6gberg?=
Date: Fri, 20 Sep 2024 16:36:58 +0200
Subject: [PATCH 025/217] beam_ssa_opt: Intersect CSE candidates on failure
path
---
lib/compiler/src/beam_ssa_opt.erl | 18 +++++++++---------
lib/compiler/test/beam_ssa_SUITE.erl | 22 ++++++++++++++++++++++
2 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/lib/compiler/src/beam_ssa_opt.erl b/lib/compiler/src/beam_ssa_opt.erl
index fca1e08877aa..a6dfc0ddb384 100644
--- a/lib/compiler/src/beam_ssa_opt.erl
+++ b/lib/compiler/src/beam_ssa_opt.erl
@@ -1089,18 +1089,18 @@ cse_successors_1([L|Ls], Es0, M) ->
end;
cse_successors_1([], _, M) -> M.
-cse_successor_fail(Fail, Src, Es0, M) ->
+cse_successor_fail(Fail, Src, LHS0, M) ->
case M of
- #{Fail := Es1} when map_size(Es1) =:= 0 ->
+ #{Fail := RHS} when map_size(RHS) =:= 0 ->
M;
- #{Fail := Es1} ->
- Es = #{Var => Val || Var := Val <- Es0,
- is_map_key(Var, Es1),
- Val =/= Src},
- M#{Fail := Es};
+ #{Fail := RHS} ->
+ LHS = #{Var => Val || Var := Val <- LHS0,
+ is_map_key(Var, RHS),
+ Val =/= Src},
+ M#{Fail := cse_intersection(LHS, RHS)};
#{} ->
- Es = #{Var => Val || Var := Val <- Es0, Val =/= Src},
- M#{Fail => Es}
+ LHS = #{Var => Val || Var := Val <- LHS0, Val =/= Src},
+ M#{Fail => LHS}
end.
%% Calculate the intersection of the two maps. Both keys and values
diff --git a/lib/compiler/test/beam_ssa_SUITE.erl b/lib/compiler/test/beam_ssa_SUITE.erl
index 49a15b4be777..e28868f64ba3 100644
--- a/lib/compiler/test/beam_ssa_SUITE.erl
+++ b/lib/compiler/test/beam_ssa_SUITE.erl
@@ -942,6 +942,8 @@ grab_bag(_Config) ->
{reply,{ok,foo_bar},#{page_title := foo_bar}} =
grab_bag_23(id(#{page_title => unset})),
+ ok = grab_bag_24(),
+
ok.
grab_bag_1() ->
@@ -1243,6 +1245,26 @@ grab_bag_23(#{page_title := unset} = State1) ->
end},
State2}.
+
+-record(test, {a,b,c}).
+-record(test_a, {a}).
+
+%% GH-8818: The CSE pass in beam_ssa_opt failed to intersect candidates on
+%% the failure path, crashing the type optimization pass.
+grab_bag_24() ->
+ {'EXIT', _} = catch do_grab_bag_24(id(0), id(0), id(0), id(0)),
+ ok.
+
+do_grab_bag_24(A, B, C, D) ->
+ A#test.a,
+ {E, F} = ext:ernal(D#test_a.a),
+ if
+ D#test_a.a == 0 andalso (B < E * A#test.a) orelse (B > F * A#test.a) ->
+ false;
+ (C =:= A#test.b) orelse (C =:= A#test.a) ->
+ true
+ end.
+
redundant_br(_Config) ->
{false,{x,y,z}} = redundant_br_1(id({x,y,z})),
{true,[[a,b,c]]} = redundant_br_1(id([[[a,b,c]]])),
From f9013fad5a1121535e882be9a3d4713637110ec7 Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin
Date: Fri, 13 Sep 2024 14:22:06 +0200
Subject: [PATCH 026/217] ssl: Convey alert information to passive socket
operations recv and setopts
If a TLS-1.3 server fails client certification the alert might arrive
in the connection state and even after data has been sent. Make sure
the alert information will be available in error reason returned from
passive socket API functions recv and setopt.
Backport of 25f3c524809b6f2909d925205df2dc9532464c14
---
lib/ssl/src/ssl_connection.hrl | 3 +-
lib/ssl/src/ssl_gen_statem.erl | 62 ++++++++++++++----
lib/ssl/src/tls_gen_connection.erl | 7 ++
lib/ssl/test/tls_1_3_version_SUITE.erl | 90 +++++++++++++++++++++++++-
4 files changed, 146 insertions(+), 16 deletions(-)
diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl
index c8295f339fbd..5efdccfdfd77 100644
--- a/lib/ssl/src/ssl_connection.hrl
+++ b/lib/ssl/src/ssl_connection.hrl
@@ -31,6 +31,7 @@
-include("ssl_handshake.hrl").
-include("ssl_srp.hrl").
-include("ssl_cipher.hrl").
+-include("ssl_alert.hrl").
-include_lib("public_key/include/public_key.hrl").
-record(static_env, {
@@ -96,7 +97,7 @@
user_application :: {Monitor::reference(), User::pid()},
downgrade :: {NewController::pid(), From::gen_statem:from()} | 'undefined',
socket_terminated = false ::boolean(),
- socket_tls_closed = false ::boolean(),
+ socket_tls_closed = false ::boolean() | #alert{},
negotiated_version :: ssl_record:ssl_version() | 'undefined',
erl_dist_handle = undefined :: erlang:dist_handle() | 'undefined',
cert_key_alts = undefined :: #{eddsa => list(),
diff --git a/lib/ssl/src/ssl_gen_statem.erl b/lib/ssl/src/ssl_gen_statem.erl
index eed0025ad7ce..f795e7c24c1d 100644
--- a/lib/ssl/src/ssl_gen_statem.erl
+++ b/lib/ssl/src/ssl_gen_statem.erl
@@ -584,11 +584,10 @@ config_error(_Type, _Event, _State) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
connection({call, RecvFrom}, {recv, N, Timeout},
- #state{static_env = #static_env{protocol_cb = Connection},
- socket_options =
+ #state{socket_options =
#socket_options{active = false}} = State0) ->
passive_receive(State0#state{bytes_to_read = N,
- start_or_recv_from = RecvFrom}, ?FUNCTION_NAME, Connection,
+ start_or_recv_from = RecvFrom}, ?FUNCTION_NAME,
[{{timeout, recv}, Timeout, timeout}]);
connection({call, From}, peer_certificate,
#state{session = #session{peer_certificate = Cert}} = State) ->
@@ -613,6 +612,18 @@ connection({call, From}, negotiated_protocol,
negotiated_protocol = undefined}} = State) ->
hibernate_after(?FUNCTION_NAME, State,
[{reply, From, {ok, SelectedProtocol}}]);
+connection({call, From},
+ {close,{_NewController, _Timeout}},
+ #state{static_env = #static_env{role = Role,
+ socket = Socket,
+ trackers = Trackers,
+ transport_cb = Transport,
+ protocol_cb = Connection},
+ connection_env = #connection_env{socket_tls_closed = #alert{} = Alert}
+ } = State) ->
+ Pids = Connection:pids(State),
+ alert_user(Pids, Transport, Trackers, Socket, From, Alert, Role, connection, Connection),
+ {stop, {shutdown, normal}, State};
connection({call, From},
{close,{NewController, Timeout}},
#state{connection_states = ConnectionStates,
@@ -663,9 +674,8 @@ connection(cast, {dist_handshake_complete, DHandle},
Connection:next_event(connection, Record, State);
connection(info, Msg, #state{static_env = #static_env{protocol_cb = Connection}} = State) ->
Connection:handle_info(Msg, ?FUNCTION_NAME, State);
-connection(internal, {recv, RecvFrom}, #state{start_or_recv_from = RecvFrom,
- static_env = #static_env{protocol_cb = Connection}} = State) ->
- passive_receive(State, ?FUNCTION_NAME, Connection, []);
+connection(internal, {recv, RecvFrom}, #state{start_or_recv_from = RecvFrom} = State) ->
+ passive_receive(State, ?FUNCTION_NAME, []);
connection(Type, Msg, State) ->
handle_common_event(Type, Msg, ?FUNCTION_NAME, State).
@@ -844,7 +854,7 @@ handle_info({ErrorTag, Socket, econnaborted}, StateName,
maybe_invalidate_session(Version, Type, Role, Host, Port, Session),
Pids = Connection:pids(State),
- alert_user(Pids, Transport, Trackers,Socket,
+ alert_user(Pids, Transport, Trackers, Socket,
StartFrom, ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), Role, StateName, Connection),
{stop, {shutdown, normal}, State};
@@ -925,10 +935,23 @@ read_application_data(Data,
user_data_buffer = {Front,BufferSize,Rear}}}
end
end.
+
+passive_receive(#state{static_env = #static_env{role = Role,
+ socket = Socket,
+ trackers = Trackers,
+ transport_cb = Transport,
+ protocol_cb = Connection},
+ start_or_recv_from = RecvFrom,
+ connection_env = #connection_env{socket_tls_closed = #alert{} = Alert}} = State,
+ StateName, _) ->
+ Pids = Connection:pids(State),
+ alert_user(Pids, Transport, Trackers, Socket, RecvFrom, Alert, Role, StateName, Connection),
+ {stop, {shutdown, normal}, State};
passive_receive(#state{user_data_buffer = {Front,BufferSize,Rear},
%% Assert! Erl distribution uses active sockets
+ static_env = #static_env{protocol_cb = Connection},
connection_env = #connection_env{erl_dist_handle = undefined}}
- = State0, StateName, Connection, StartTimerAction) ->
+ = State0, StateName, StartTimerAction) ->
case BufferSize of
0 ->
Connection:next_event(StateName, no_record, State0, StartTimerAction);
@@ -1396,14 +1419,27 @@ no_records(Extensions) ->
handle_active_option(false, connection = StateName, To, Reply, State) ->
hibernate_after(StateName, State, [{reply, To, Reply}]);
-handle_active_option(_, connection = StateName, To, Reply, #state{static_env = #static_env{role = Role},
- connection_env = #connection_env{socket_tls_closed = true},
- user_data_buffer = {_,0,_}} = State) ->
+handle_active_option(_, connection = StateName, To, Reply,
+ #state{static_env = #static_env{role = Role},
+ connection_env = #connection_env{socket_tls_closed = true},
+ user_data_buffer = {_,0,_}} = State) ->
Alert = ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY, all_data_delivered),
handle_normal_shutdown(Alert#alert{role = Role}, StateName, State),
{stop_and_reply,{shutdown, peer_close}, [{reply, To, Reply}]};
-handle_active_option(_, connection = StateName0, To, Reply, #state{static_env = #static_env{protocol_cb = Connection},
- user_data_buffer = {_,0,_}} = State0) ->
+handle_active_option(_, connection = StateName, To, _Reply,
+ #state{static_env = #static_env{role = Role,
+ socket = Socket,
+ trackers = Trackers,
+ transport_cb = Transport,
+ protocol_cb = Connection},
+ connection_env = #connection_env{socket_tls_closed = Alert = #alert{}},
+ user_data_buffer = {_,0,_}} = State) ->
+ Pids = Connection:pids(State),
+ alert_user(Pids, Transport, Trackers, Socket, To, Alert, Role, StateName, Connection),
+ {stop, {shutdown, normal}, State};
+handle_active_option(_, connection = StateName0, To, Reply,
+ #state{static_env = #static_env{protocol_cb = Connection},
+ user_data_buffer = {_,0,_}} = State0) ->
case Connection:next_event(StateName0, no_record, State0) of
{next_state, StateName, State} ->
hibernate_after(StateName, State, [{reply, To, Reply}]);
diff --git a/lib/ssl/src/tls_gen_connection.erl b/lib/ssl/src/tls_gen_connection.erl
index 940666f104ef..bfdc8a4f2f5c 100644
--- a/lib/ssl/src/tls_gen_connection.erl
+++ b/lib/ssl/src/tls_gen_connection.erl
@@ -872,7 +872,14 @@ handle_alerts([#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} | _Alerts],
{next_state, connection = StateName, #state{connection_env = CEnv,
socket_options = #socket_options{active = false},
start_or_recv_from = From} = State}) when From == undefined ->
+ %% Linger to allow recv and setopts to possibly fetch data not yet delivered to user to be fetched
{next_state, StateName, State#state{connection_env = CEnv#connection_env{socket_tls_closed = true}}};
+handle_alerts([#alert{level = ?FATAL} = Alert | _Alerts],
+ {next_state, connection = StateName, #state{connection_env = CEnv,
+ socket_options = #socket_options{active = false},
+ start_or_recv_from = From} = State}) when From == undefined ->
+ %% Linger to allow recv and setopts to retrieve alert reason
+ {next_state, StateName, State#state{connection_env = CEnv#connection_env{socket_tls_closed = Alert}}};
handle_alerts([Alert | Alerts], {next_state, StateName, State}) ->
handle_alerts(Alerts, ssl_gen_statem:handle_alert(Alert, StateName, State));
handle_alerts([Alert | Alerts], {next_state, StateName, State, _Actions}) ->
diff --git a/lib/ssl/test/tls_1_3_version_SUITE.erl b/lib/ssl/test/tls_1_3_version_SUITE.erl
index 8a3ff288f75a..5b6b40305fa2 100644
--- a/lib/ssl/test/tls_1_3_version_SUITE.erl
+++ b/lib/ssl/test/tls_1_3_version_SUITE.erl
@@ -57,7 +57,11 @@
middle_box_tls12_enabled_client/0,
middle_box_tls12_enabled_client/1,
middle_box_client_tls_v2_session_reused/0,
- middle_box_client_tls_v2_session_reused/1
+ middle_box_client_tls_v2_session_reused/1,
+ client_cert_fail_alert_active/0,
+ client_cert_fail_alert_active/1,
+ client_cert_fail_alert_passive/0,
+ client_cert_fail_alert_passive/1
]).
@@ -90,7 +94,9 @@ tls_1_3_1_2_tests() ->
tls12_client_tls_server,
middle_box_tls13_client,
middle_box_tls12_enabled_client,
- middle_box_client_tls_v2_session_reused
+ middle_box_client_tls_v2_session_reused,
+ client_cert_fail_alert_active,
+ client_cert_fail_alert_passive
].
legacy_tests() ->
[tls_client_tls10_server,
@@ -329,6 +335,60 @@ middle_box_client_tls_v2_session_reused(Config) when is_list(Config) ->
{reuse_session, {SessionId, SessData}} | ClientOpts]}]),
{ok,[{session_id, SessionId}]} = ssl:connection_information(CSock1, [session_id]).
+
+client_cert_fail_alert_active() ->
+ [{doc, "Check that we receive alert message"}].
+client_cert_fail_alert_active(Config) when is_list(Config) ->
+ ssl:clear_pem_cache(),
+ {_ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ ClientOpts0 = ssl_test_lib:ssl_options(extra_client, client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(extra_server, server_cert_opts, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ NewClientCertFile = filename:join(PrivDir, "client_invalid_cert.pem"),
+
+ create_bad_client_certfile(NewClientCertFile, ClientOpts0),
+
+ ClientOpts = [{active, true},
+ {verify, verify_peer},
+ {certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts0)],
+ ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}| ServerOpts0],
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {ok, Socket} = ssl:connect(Hostname, Port, ClientOpts),
+ receive
+ {Server, {error, {tls_alert, {unknown_ca, _}}}} ->
+ receive
+ {ssl_error, Socket, {tls_alert, {unknown_ca, _}}} ->
+ ok
+ after 500 ->
+ ct:fail(no_acticv_msg)
+ end
+ end.
+
+client_cert_fail_alert_passive() ->
+ [{doc, "Check that recv or setopts return alert"}].
+client_cert_fail_alert_passive(Config) when is_list(Config) ->
+ ssl:clear_pem_cache(),
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ ClientOpts0 = ssl_test_lib:ssl_options(extra_client, client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(extra_server, server_cert_opts, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ NewClientCertFile = filename:join(PrivDir, "client_invalid_cert.pem"),
+
+ create_bad_client_certfile(NewClientCertFile, ClientOpts0),
+
+ ClientOpts = [{active, false},
+ {verify, verify_peer},
+ {certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts0)],
+ ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}| ServerOpts0],
+ alert_passive(ServerOpts, ClientOpts, recv,
+ ServerNode, Hostname),
+ alert_passive(ServerOpts, ClientOpts, setopts,
+ ServerNode, Hostname).
+
%%--------------------------------------------------------------------
%% Internal functions and callbacks -----------------------------------
%%--------------------------------------------------------------------
@@ -359,4 +419,30 @@ check_session_id(Socket, Expected) ->
{nok, {{expected, Expected}, {got, SessionId}}}
end.
+alert_passive(ServerOpts, ClientOpts, Function,
+ ServerNode, Hostname) ->
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {ok, Socket} = ssl:connect(Hostname, Port, ClientOpts),
+ ct:sleep(500),
+ case Function of
+ recv ->
+ {error, {tls_alert, {unknown_ca,_}}} = ssl:recv(Socket, 0);
+ setopts ->
+ {error, {tls_alert, {unknown_ca,_}}} = ssl:setopts(Socket, [{active, once}])
+ end.
+create_bad_client_certfile(NewClientCertFile, ClientOpts0) ->
+ KeyFile = proplists:get_value(keyfile, ClientOpts0),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
+ ClientCertFile = proplists:get_value(certfile, ClientOpts0),
+
+ [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile),
+ ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp),
+ ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate,
+ NewClientDerCert = public_key:pkix_sign(ClientOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]).
From 299be8d249b8d2e44169bed409b9867d0542bc72 Mon Sep 17 00:00:00 2001
From: Konrad Pietrzak
Date: Thu, 4 Jul 2024 11:39:33 +0200
Subject: [PATCH 027/217] OTP-19158 httpc enable options for async request
---
lib/inets/src/http_client/httpc.erl | 29 +++++-------
lib/inets/src/http_client/httpc_handler.erl | 43 +++++++++++++++--
lib/inets/src/http_client/httpc_internal.hrl | 3 +-
lib/inets/src/http_client/httpc_request.erl | 50 ++++++++++----------
lib/inets/test/httpc_SUITE.erl | 13 ++++-
5 files changed, 92 insertions(+), 46 deletions(-)
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index d9ea9c76e32a..0ac74f14f348 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -1204,7 +1204,8 @@ handle_request(Method, Url,
socket_opts = SocketOpts,
started = Started,
unix_socket = UnixSocket,
- ipv6_host_with_brackets = BracketedHost},
+ ipv6_host_with_brackets = BracketedHost,
+ request_options = Options},
case httpc_manager:request(Request, profile_name(Profile)) of
{ok, RequestId} ->
handle_answer(RequestId, Sync, Options);
@@ -1267,22 +1268,16 @@ handle_answer(RequestId, false, _) ->
{ok, RequestId};
handle_answer(RequestId, true, Options) ->
receive
- {http, {RequestId, saved_to_file}} ->
- {ok, saved_to_file};
- {http, {RequestId, {_,_,_} = Result}} ->
- return_answer(Options, Result);
- {http, {RequestId, {error, Reason}}} ->
- {error, Reason}
- end.
-
-return_answer(Options, {StatusLine, Headers, BinBody}) ->
- Body = maybe_format_body(BinBody, Options),
- case proplists:get_value(full_result, Options, true) of
- true ->
- {ok, {StatusLine, Headers, Body}};
- false ->
- {_, Status, _} = StatusLine,
- {ok, {Status, Body}}
+ {http, {RequestId, {ok, saved_to_file}}} ->
+ {ok, saved_to_file};
+ {http, {RequestId, {error, Reason}}} ->
+ {error, Reason};
+ {http, {RequestId, {ok, {StatusLine,Headers,BinBody}}}} ->
+ Body = maybe_format_body(BinBody, Options),
+ {ok, {StatusLine, Headers, Body}};
+ {http, {RequestId, {ok, {StatusCode,BinBody}}}} ->
+ Body = maybe_format_body(BinBody, Options),
+ {ok, {StatusCode, Body}}
end.
maybe_format_body(BinBody, Options) ->
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index ca3a46ccd909..ad8694c9f2d6 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -1319,11 +1319,12 @@ handle_server_closing(State = #state{headers = Headers}) ->
false -> State
end.
-answer_request(#request{id = RequestId, from = From} = Request, Msg,
+answer_request(#request{id = RequestId, from = From, request_options = Options} = Request, Msg,
#state{session = Session,
timers = Timers,
- profile_name = ProfileName} = State) ->
- httpc_response:send(From, Msg),
+ profile_name = ProfileName} = State) ->
+ Answer = format_answer(Msg, Options),
+ httpc_response:send(From, Answer),
RequestTimers = Timers#timers.request_timers,
TimerRef =
proplists:get_value(RequestId, RequestTimers, undefined),
@@ -1717,6 +1718,42 @@ format_address({[$[|T], Port}) ->
format_address(HostPort) ->
HostPort.
+format_answer(Res0, Options) ->
+ FullResult = proplists:get_value(full_result, Options, true),
+ Sync = proplists:get_value(sync, Options, true),
+ do_format_answer(Res0, FullResult, Sync).
+do_format_answer({Ref, StatusLine}, _, Sync) when is_atom(StatusLine) ->
+ case Sync of
+ true ->
+ {Ref, {ok, StatusLine}};
+ _ ->
+ {Ref, StatusLine}
+ end;
+do_format_answer({Ref, StatusLine, Headers}, _, Sync) when is_atom(StatusLine) ->
+ case Sync of
+ true ->
+ {Ref, {ok, {StatusLine, Headers}}};
+ _ ->
+ {Ref, StatusLine, Headers}
+ end;
+do_format_answer({Ref, {StatusLine, Headers, BinBody}}, true, Sync) ->
+ case Sync of
+ true ->
+ {Ref, {ok, {StatusLine, Headers, BinBody}}};
+ _ ->
+ {Ref, {StatusLine, Headers, BinBody}}
+ end;
+do_format_answer({Ref, {StatusLine, _, BinBody}}, false, Sync) ->
+ {_, Status, _} = StatusLine,
+ case Sync of
+ true ->
+ {Ref, {ok, {Status, BinBody}}};
+ _ ->
+ {Ref, {Status, BinBody}}
+ end;
+do_format_answer({Ref, {error, _Reason} = Error}, _, _) ->
+ {Ref, Error}.
+
clobber_and_retry(#state{session = #session{id = Id,
type = Type},
profile_name = ProfileName,
diff --git a/lib/inets/src/http_client/httpc_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl
index 344b6a262029..9114fda3352b 100644
--- a/lib/inets/src/http_client/httpc_internal.hrl
+++ b/lib/inets/src/http_client/httpc_internal.hrl
@@ -117,7 +117,8 @@
timer :: undefined | reference(),
socket_opts, % undefined | [socket_option()]
unix_socket, % undefined | string()
- ipv6_host_with_brackets % boolean()
+ ipv6_host_with_brackets, % boolean()
+ request_options :: undefined | proplists:proplist()
}
).
-type request() :: #request{}.
diff --git a/lib/inets/src/http_client/httpc_request.erl b/lib/inets/src/http_client/httpc_request.erl
index fc48adec44ed..23c7156c0230 100644
--- a/lib/inets/src/http_client/httpc_request.erl
+++ b/lib/inets/src/http_client/httpc_request.erl
@@ -55,31 +55,33 @@ send(SendAddr, #session{socket = Socket, socket_type = SocketType},
send(SendAddr, #session{socket = Socket, socket_type = SocketType}, Request) ->
send(SendAddr, Socket, SocketType, Request).
-send(SendAddr, Socket, SocketType,
- #request{method = Method,
- path = Path,
- pquery = Query,
- headers = Headers,
- content = Content,
- address = Address,
- abs_uri = AbsUri,
- headers_as_is = HeadersAsIs,
- settings = HttpOptions,
- userinfo = UserInfo}) ->
+send(SendAddr, Socket, SocketType,
+ #request{method = Method,
+ path = Path,
+ pquery = Query,
+ headers = Headers,
+ content = Content,
+ address = Address,
+ abs_uri = AbsUri,
+ headers_as_is = HeadersAsIs,
+ settings = HttpOptions,
+ userinfo = UserInfo,
+ request_options = Options}) ->
- ?hcrt("send",
- [{send_addr, SendAddr},
- {socket, Socket},
- {method, Method},
- {path, Path},
- {pquery, Query},
- {headers, Headers},
- {content, Content},
- {address, Address},
- {abs_uri, AbsUri},
- {headers_as_is, HeadersAsIs},
- {settings, HttpOptions},
- {userinfo, UserInfo}]),
+ ?hcrt("send",
+ [{send_addr, SendAddr},
+ {socket, Socket},
+ {method, Method},
+ {path, Path},
+ {pquery, Query},
+ {headers, Headers},
+ {content, Content},
+ {address, Address},
+ {abs_uri, AbsUri},
+ {headers_as_is, HeadersAsIs},
+ {settings, HttpOptions},
+ {userinfo, UserInfo},
+ {request_options, Options}]),
TmpHdrs = handle_user_info(UserInfo, Headers),
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index a76cf8a45a7f..a3149e7f269b 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -570,7 +570,18 @@ async(Config) when is_list(Config) ->
ct:fail(Msg)
end,
inets_test_lib:check_body(binary_to_list(Body)),
-
+ %% Check full result false option for async request
+ {ok, RequestId2} =
+ httpc:request(get, Request, [?SSL_NO_VERIFY], [{sync, false},
+ {full_result, false}], ?profile(Config)),
+ Body2 =
+ receive
+ {http, {RequestId2, {200, BinBody2}}} ->
+ BinBody2;
+ {http, Msg2} ->
+ ct:fail(Msg2)
+ end,
+ inets_test_lib:check_body(binary_to_list(Body2)),
{ok, NewRequestId} =
httpc:request(get, Request, [?SSL_NO_VERIFY], [{sync, false}]),
ok = httpc:cancel_request(NewRequestId).
From c47436b27b4a467f385b46671093da8ab280bbc5 Mon Sep 17 00:00:00 2001
From: Konrad Pietrzak
Date: Fri, 6 Sep 2024 14:01:56 +0200
Subject: [PATCH 028/217] OTP-19221 httpc timeout on handle_answer
---
lib/inets/src/http_client/httpc.erl | 56 +++++++++++----
lib/inets/src/http_client/httpc_handler.erl | 15 ++--
lib/inets/src/http_client/httpc_request.erl | 50 +++++++-------
lib/inets/src/http_client/httpc_response.erl | 2 +-
lib/inets/test/httpc_SUITE.erl | 72 ++++++++++++++------
5 files changed, 127 insertions(+), 68 deletions(-)
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index 0ac74f14f348..ce9123d2e7a6 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -376,6 +376,9 @@ Options details:
- **`t:pid/0`** - Messages are sent to this process in the format
`{http, ReplyInfo}`.
+ - **`alias/0`** - Messages are sent to this special reference in the format
+ `{http, ReplyInfo}`.
+
- **`function/1`** - Information is delivered to the receiver through calls to
the provided fun `Receiver(ReplyInfo)`.
@@ -1205,14 +1208,15 @@ handle_request(Method, Url,
started = Started,
unix_socket = UnixSocket,
ipv6_host_with_brackets = BracketedHost,
- request_options = Options},
- case httpc_manager:request(Request, profile_name(Profile)) of
- {ok, RequestId} ->
- handle_answer(RequestId, Sync, Options);
- {error, Reason} ->
- {error, Reason}
- end
- end
+ request_options = Options},
+ case httpc_manager:request(Request, profile_name(Profile)) of
+ {ok, RequestId} ->
+ handle_answer(RequestId, Receiver, Sync, Options,
+ element(#http_options.timeout, HTTPOptions));
+ {error, Reason} ->
+ {error, Reason}
+ end
+ end
catch
error:{noproc, _} ->
{error, {not_started, Profile}};
@@ -1264,20 +1268,41 @@ mk_chunkify_fun(ProcessBody) ->
end.
-handle_answer(RequestId, false, _) ->
+handle_answer(RequestId, _, false, _, _) ->
{ok, RequestId};
-handle_answer(RequestId, true, Options) ->
+handle_answer(RequestId, ClientAlias, true, Options, Timeout) ->
receive
{http, {RequestId, {ok, saved_to_file}}} ->
+ true = unalias(ClientAlias),
{ok, saved_to_file};
{http, {RequestId, {error, Reason}}} ->
+ true = unalias(ClientAlias),
{error, Reason};
- {http, {RequestId, {ok, {StatusLine,Headers,BinBody}}}} ->
+ {http, {RequestId, {ok, {StatusLine, Headers, BinBody}}}} ->
+ true = unalias(ClientAlias),
Body = maybe_format_body(BinBody, Options),
{ok, {StatusLine, Headers, Body}};
- {http, {RequestId, {ok, {StatusCode,BinBody}}}} ->
+ {http, {RequestId, {ok, {StatusCode, BinBody}}}} ->
+ true = unalias(ClientAlias),
Body = maybe_format_body(BinBody, Options),
{ok, {StatusCode, Body}}
+ after Timeout ->
+ cancel_request(RequestId),
+ true = unalias(ClientAlias),
+ receive
+ {http, {RequestId, {ok, saved_to_file}}} ->
+ {ok, saved_to_file};
+ {http, {RequestId, {error, Reason}}} ->
+ {error, Reason};
+ {http, {RequestId, {ok, {StatusLine, Headers, BinBody}}}} ->
+ Body = maybe_format_body(BinBody, Options),
+ {ok, {StatusLine, Headers, Body}};
+ {http, {RequestId, {ok, {StatusCode, BinBody}}}} ->
+ Body = maybe_format_body(BinBody, Options),
+ {ok, {StatusCode, Body}}
+ after 0 ->
+ {error, timeout}
+ end
end.
maybe_format_body(BinBody, Options) ->
@@ -1474,6 +1499,8 @@ request_options_defaults() ->
ok;
(Value) when is_function(Value, 1) ->
ok;
+ (Value) when is_reference(Value) ->
+ ok;
(_) ->
error
end,
@@ -1495,7 +1522,7 @@ request_options_defaults() ->
{body_format, string, VerifyBodyFormat},
{full_result, true, VerifyFullResult},
{headers_as_is, false, VerifyHeaderAsIs},
- {receiver, self(), VerifyReceiver},
+ {receiver, alias(), VerifyReceiver},
{socket_opts, undefined, VerifySocketOpts},
{ipv6_host_with_brackets, false, VerifyBrackets}
].
@@ -1549,6 +1576,7 @@ request_options([{Key, DefaultVal, Verify} | Defaults], Options, Acc) ->
BodyFormat :: string | binary,
SocketOpt :: term(),
Receiver :: pid()
+ | reference()
| fun((term()) -> term())
| { ReceiverModule::atom()
, ReceiverFunction::atom()
@@ -1559,6 +1587,8 @@ request_options_sanity_check(Opts) ->
case proplists:get_value(receiver, Opts) of
Pid when is_pid(Pid) andalso (Pid =:= self()) ->
ok;
+ Reference when is_reference(Reference) ->
+ ok;
BadReceiver ->
throw({error, {bad_options_combo,
[{sync, true}, {receiver, BadReceiver}]}})
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index ad8694c9f2d6..4a4fedc14985 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -482,7 +482,6 @@ do_handle_info({Proto, _Socket, Data},
when (Proto =:= tcp) orelse
(Proto =:= ssl) orelse
(Proto =:= httpc_handler) ->
-
try Module:Function([Data | Args]) of
{ok, Result} ->
handle_http_msg(Result, State);
@@ -1320,9 +1319,9 @@ handle_server_closing(State = #state{headers = Headers}) ->
end.
answer_request(#request{id = RequestId, from = From, request_options = Options} = Request, Msg,
- #state{session = Session,
- timers = Timers,
- profile_name = ProfileName} = State) ->
+ #state{session = Session,
+ timers = Timers,
+ profile_name = ProfileName} = State) ->
Answer = format_answer(Msg, Options),
httpc_response:send(From, Answer),
RequestTimers = Timers#timers.request_timers,
@@ -1718,10 +1717,10 @@ format_address({[$[|T], Port}) ->
format_address(HostPort) ->
HostPort.
-format_answer(Res0, Options) ->
+format_answer(Res, Options) ->
FullResult = proplists:get_value(full_result, Options, true),
Sync = proplists:get_value(sync, Options, true),
- do_format_answer(Res0, FullResult, Sync).
+ do_format_answer(Res, FullResult, Sync).
do_format_answer({Ref, StatusLine}, _, Sync) when is_atom(StatusLine) ->
case Sync of
true ->
@@ -1742,9 +1741,9 @@ do_format_answer({Ref, {StatusLine, Headers, BinBody}}, true, Sync) ->
{Ref, {ok, {StatusLine, Headers, BinBody}}};
_ ->
{Ref, {StatusLine, Headers, BinBody}}
- end;
+ end;
do_format_answer({Ref, {StatusLine, _, BinBody}}, false, Sync) ->
- {_, Status, _} = StatusLine,
+ {_, Status, _} = StatusLine,
case Sync of
true ->
{Ref, {ok, {Status, BinBody}}};
diff --git a/lib/inets/src/http_client/httpc_request.erl b/lib/inets/src/http_client/httpc_request.erl
index 23c7156c0230..364be6e85645 100644
--- a/lib/inets/src/http_client/httpc_request.erl
+++ b/lib/inets/src/http_client/httpc_request.erl
@@ -56,32 +56,32 @@ send(SendAddr, #session{socket = Socket, socket_type = SocketType}, Request) ->
send(SendAddr, Socket, SocketType, Request).
send(SendAddr, Socket, SocketType,
- #request{method = Method,
- path = Path,
- pquery = Query,
- headers = Headers,
- content = Content,
- address = Address,
- abs_uri = AbsUri,
- headers_as_is = HeadersAsIs,
- settings = HttpOptions,
- userinfo = UserInfo,
- request_options = Options}) ->
-
+ #request{method = Method,
+ path = Path,
+ pquery = Query,
+ headers = Headers,
+ content = Content,
+ address = Address,
+ abs_uri = AbsUri,
+ headers_as_is = HeadersAsIs,
+ settings = HttpOptions,
+ userinfo = UserInfo,
+ request_options = Options}) ->
+
?hcrt("send",
- [{send_addr, SendAddr},
- {socket, Socket},
- {method, Method},
- {path, Path},
- {pquery, Query},
- {headers, Headers},
- {content, Content},
- {address, Address},
- {abs_uri, AbsUri},
- {headers_as_is, HeadersAsIs},
- {settings, HttpOptions},
- {userinfo, UserInfo},
- {request_options, Options}]),
+ [{send_addr, SendAddr},
+ {socket, Socket},
+ {method, Method},
+ {path, Path},
+ {pquery, Query},
+ {headers, Headers},
+ {content, Content},
+ {address, Address},
+ {abs_uri, AbsUri},
+ {headers_as_is, HeadersAsIs},
+ {settings, HttpOptions},
+ {userinfo, UserInfo},
+ {request_options, Options}]),
TmpHdrs = handle_user_info(UserInfo, Headers),
diff --git a/lib/inets/src/http_client/httpc_response.erl b/lib/inets/src/http_client/httpc_response.erl
index 1dd0bdec66cb..9ebea9bdbc68 100644
--- a/lib/inets/src/http_client/httpc_response.erl
+++ b/lib/inets/src/http_client/httpc_response.erl
@@ -151,7 +151,7 @@ result(Response = {{_,Code,_}, _, _}, Request) when (Code div 100) =:= 5 ->
result(Response, Request) ->
transparent(Response, Request).
-send(Receiver, Msg) when is_pid(Receiver) ->
+send(Receiver, Msg) when is_pid(Receiver); is_reference(Receiver) ->
Receiver ! {http, Msg};
send(Receiver, Msg) when is_function(Receiver) ->
(catch Receiver(Msg));
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index a3149e7f269b..bd62de906215 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -342,6 +342,9 @@ init_per_testcase(Name, Config) when Name == pipeline; Name == persistent_connec
{max_pipeline_length, 3} | GivenOptions], Name),
[{profile, Name} | Config];
+init_per_testcase(async, Config) ->
+ {ok,Pid} = inets:start(httpc, [{profile, async}], stand_alone),
+ [{httpc_pid, Pid} | Config];
init_per_testcase(Case, Config) ->
{ok, _Pid} = inets:start(httpc, [{profile, Case}]),
GivenOptions = proplists:get_value(httpc_options, Config, []),
@@ -367,7 +370,9 @@ end_per_testcase(Case, Config)
ok
end,
inets:stop(httpc, ?config(profile, Config));
-
+end_per_testcase(async, Config) ->
+ Pid = proplists:get_value(httpc_pid, Config),
+ inets:stop(httpc, Pid);
end_per_testcase(_Case, Config) ->
inets:stop(httpc, ?config(profile, Config)).
@@ -559,21 +564,22 @@ async() ->
[{doc, "Test an asynchrony http request."}].
async(Config) when is_list(Config) ->
Request = {url(group_name(Config), "/dummy.html", Config), []},
-
+ HttpcPid = proplists:get_value(httpc_pid, Config),
{ok, RequestId} =
- httpc:request(get, Request, [?SSL_NO_VERIFY], [{sync, false}], ?profile(Config)),
+ httpc:request(get, Request, [?SSL_NO_VERIFY], [{sync, false}], ?profile(Config)),
Body =
- receive
- {http, {RequestId, {{_, 200, _}, _, BinBody}}} ->
- BinBody;
- {http, Msg} ->
- ct:fail(Msg)
- end,
+ receive
+ {http, {RequestId, {{_, 200, _}, _, BinBody}}} ->
+ BinBody;
+ {http, Msg} ->
+ ct:fail(Msg)
+ end,
inets_test_lib:check_body(binary_to_list(Body)),
+
%% Check full result false option for async request
{ok, RequestId2} =
httpc:request(get, Request, [?SSL_NO_VERIFY], [{sync, false},
- {full_result, false}], ?profile(Config)),
+ {full_result, false}]),
Body2 =
receive
{http, {RequestId2, {200, BinBody2}}} ->
@@ -582,6 +588,19 @@ async(Config) when is_list(Config) ->
ct:fail(Msg2)
end,
inets_test_lib:check_body(binary_to_list(Body2)),
+
+ %% Check receiver alias() option for async request with stand_alone httpc
+ {ok, RequestId3} =
+ httpc:request(get, Request, [?SSL_NO_VERIFY], [{sync, false},
+ {receiver, alias()}], HttpcPid),
+ Body3 =
+ receive
+ {http, {RequestId3, {{_, 200, _}, _, BinBody3}}} ->
+ BinBody3;
+ {http, Msg3} ->
+ ct:fail(Msg3)
+ end,
+ inets_test_lib:check_body(binary_to_list(Body3)),
{ok, NewRequestId} =
httpc:request(get, Request, [?SSL_NO_VERIFY], [{sync, false}]),
ok = httpc:cancel_request(NewRequestId).
@@ -1703,19 +1722,30 @@ timeout_memory_leak(Config) when is_list(Config) ->
{ok, Host} = inet:gethostname(),
Request = {?URL_START ++ Host ++ ":" ++ integer_to_list(Port) ++ "/dummy.html", []},
Profile = ?config(profile, Config),
+ WaitForCancelRequestToFinish =
+ fun F(Handlers = [_ | _]) when is_list(Handlers) -> ct:fail({unexpected_handlers, Handlers});
+ F(Handlers) when is_list(Handlers) -> ok;
+ F(N) when is_integer(N) ->
+ Info = httpc:info(Profile),
+ ct:log("Info: ~p", [Info]),
+ {value, {handlers, Handlers}} =
+ lists:keysearch(handlers, 1, Info),
+ case Handlers of
+ [] ->
+ ok;
+ _ ->
+ ct:sleep(1)
+ end,
+ case N of
+ 0 ->
+ F(Handlers);
+ _ ->
+ F(N-1)
+ end
+ end,
case httpc:request(get, Request, [{connect_timeout, 500}, {timeout, 1}], [{sync, true}], Profile) of
{error, timeout} ->
- %% And now we check the size of the handler db
- Info = httpc:info(Profile),
- ct:log("Info: ~p", [Info]),
- {value, {handlers, Handlers}} =
- lists:keysearch(handlers, 1, Info),
- case Handlers of
- [] ->
- ok;
- _ ->
- ct:fail({unexpected_handlers, Handlers})
- end;
+ WaitForCancelRequestToFinish(5);
Unexpected ->
ct:fail({unexpected, Unexpected})
end.
From 68b63ddd74baf9e663962b656bfd9c375e2d1453 Mon Sep 17 00:00:00 2001
From: Jakub Witczak
Date: Wed, 26 Jun 2024 16:54:21 +0200
Subject: [PATCH 029/217] ssh: GH-8223 'EXIT' issue testcases
Co-authored-by: Maria Scott
Co-authored-by: Jan Uhlig
---
lib/ssh/test/ssh_connection_SUITE.erl | 57 +++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl
index b8384ffe2177..a6919ae3df3f 100644
--- a/lib/ssh/test/ssh_connection_SUITE.erl
+++ b/lib/ssh/test/ssh_connection_SUITE.erl
@@ -107,6 +107,8 @@
start_shell_sock_exec_fun/1,
start_subsystem_on_closed_channel/1,
stop_listener/1,
+ trap_exit_connect/1,
+ trap_exit_daemon/1,
ssh_exec_echo/2 % called as an MFA
]).
@@ -134,6 +136,8 @@ all() ->
start_shell,
new_shell_dumb_term,
new_shell_xterm_term,
+ trap_exit_connect,
+ trap_exit_daemon,
start_shell_pty,
start_shell_exec,
start_shell_exec_fun,
@@ -1331,6 +1335,59 @@ do_start_shell_exec_fun(Fun, Command, Expect, ExpectType, ReceiveFun, Config) ->
ssh:close(ConnectionRef),
ssh:stop_daemon(Pid).
+%%--------------------------------------------------------------------
+%% Issue GH-8223
+trap_exit_connect(Config) when is_list(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ UserDir = filename:join(PrivDir, nopubkey),
+ file:make_dir(UserDir),
+ SysDir = proplists:get_value(data_dir, Config),
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, UserDir},
+ {password, "morot"}]),
+ %% Fake an EXIT message
+ ExitMsg = {'EXIT', self(), make_ref()},
+ self() ! ExitMsg,
+
+ {ok, ConnectionRef} = ssh:connect(Host, Port, [{silently_accept_hosts, true},
+ {save_accepted_host, false},
+ {user, "foo"},
+ {password, "morot"},
+ {user_interaction, true},
+ {user_dir, UserDir}]),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid),
+
+ %% Ensure the EXIT message is still there
+ receive
+ ExitMsg -> ok
+ after 0 ->
+ ct:fail("No EXIT message")
+ end.
+
+%%--------------------------------------------------------------------
+%% Issue GH-8223
+trap_exit_daemon(Config) when is_list(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ UserDir = filename:join(PrivDir, nopubkey),
+ file:make_dir(UserDir),
+ SysDir = proplists:get_value(data_dir, Config),
+
+ %% Fake an EXIT message
+ ExitMsg = {'EXIT', self(), make_ref()},
+ self() ! ExitMsg,
+
+ {ok, DaemonRef} = ssh:daemon(0, [{system_dir, SysDir},
+ {user_dir, UserDir}]),
+ ssh:stop_daemon(DaemonRef),
+
+ %% Ensure the EXIT message is still there
+ receive
+ ExitMsg -> ok
+ after 0 ->
+ ct:fail("No EXIT message")
+ end.
+
%%--------------------------------------------------------------------
start_shell_sock_exec_fun(Config) when is_list(Config) ->
PrivDir = proplists:get_value(priv_dir, Config),
From d72d80d4d53743285e5ba5fd387db0fa6a9d089f Mon Sep 17 00:00:00 2001
From: Jakub Witczak
Date: Thu, 19 Sep 2024 14:23:32 +0200
Subject: [PATCH 030/217] ssh: code formatting
---
lib/ssh/src/ssh_acceptor.erl | 24 ++++++++++--------------
1 file changed, 10 insertions(+), 14 deletions(-)
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index 1831e32f6cd4..fcd37445cce6 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -87,7 +87,6 @@ acceptor_init(Parent, SystemSup,
proc_lib:init_ack(Parent, {ok, self()}),
request_ownership(LSock, SockOwner),
acceptor_loop(Port, Address, Opts, LSock, AcceptTimeout, SystemSup);
-
{error,_Error} ->
%% Not open, a restart
%% Allow gen_tcp:listen to fail 4 times if eaddrinuse (It is a bug fix):
@@ -100,7 +99,6 @@ acceptor_init(Parent, SystemSup,
proc_lib:init_fail(Parent, {error,Error}, {exit, normal})
end
end;
-
undefined ->
%% No listening socket (nor fd option) was provided; open a listening socket:
case try_listen(Port, Opts, 4) of
@@ -112,7 +110,6 @@ acceptor_init(Parent, SystemSup,
end
end.
-
try_listen(Port, Opts, NtriesLeft) ->
try_listen(Port, Opts, 1, NtriesLeft).
@@ -125,7 +122,6 @@ try_listen(Port, Opts, N, Nmax) ->
Other
end.
-
request_ownership(LSock, SockOwner) ->
SockOwner ! {request_control,LSock,self()},
receive
@@ -141,7 +137,8 @@ acceptor_loop(Port, Address, Opts, ListenSocket, AcceptTimeout, SystemSup) ->
MaxSessions = ?GET_OPT(max_sessions, Opts),
NumSessions = number_of_connections(SystemSup),
ParallelLogin = ?GET_OPT(parallel_login, Opts),
- case handle_connection(Address, Port, PeerName, Opts, Socket, MaxSessions, NumSessions, ParallelLogin) of
+ case handle_connection(Address, Port, PeerName, Opts, Socket,
+ MaxSessions, NumSessions, ParallelLogin) of
{error,Error} ->
catch close(Socket, Opts),
handle_error(Error, Address, Port, PeerName);
@@ -158,18 +155,19 @@ acceptor_loop(Port, Address, Opts, ListenSocket, AcceptTimeout, SystemSup) ->
?MODULE:acceptor_loop(Port, Address, Opts, ListenSocket, AcceptTimeout, SystemSup).
%%%----------------------------------------------------------------
-handle_connection(_Address, _Port, _Peer, _Options, _Socket, MaxSessions, NumSessions, _ParallelLogin)
+handle_connection(_Address, _Port, _Peer, _Options, _Socket,
+ MaxSessions, NumSessions, _ParallelLogin)
when NumSessions >= MaxSessions->
{error,{max_sessions,MaxSessions}};
-
-handle_connection(_Address, _Port, {error,Error}, _Options, _Socket, _MaxSessions, _NumSessions, _ParallelLogin) ->
+handle_connection(_Address, _Port, {error,Error}, _Options, _Socket,
+ _MaxSessions, _NumSessions, _ParallelLogin) ->
{error,Error};
-
-handle_connection(Address, Port, _Peer, Options, Socket, _MaxSessions, _NumSessions, ParallelLogin)
+handle_connection(Address, Port, _Peer, Options, Socket,
+ _MaxSessions, _NumSessions, ParallelLogin)
when ParallelLogin == false ->
handle_connection(Address, Port, Options, Socket);
-
-handle_connection(Address, Port, _Peer, Options, Socket, _MaxSessions, _NumSessions, ParallelLogin)
+handle_connection(Address, Port, _Peer, Options, Socket,
+ _MaxSessions, _NumSessions, ParallelLogin)
when ParallelLogin == true ->
Ref = make_ref(),
Pid = spawn_link(
@@ -186,8 +184,6 @@ handle_connection(Address, Port, _Peer, Options, Socket, _MaxSessions, _NumSessi
Pid ! {start,Ref},
ok.
-
-
handle_connection(Address, Port, Options0, Socket) ->
Options = ?PUT_INTERNAL_OPT([{user_pid, self()}
], Options0),
From fb0cda4c48a9a2ba092dca76379ddf5e19e40386 Mon Sep 17 00:00:00 2001
From: Jakub Witczak
Date: Thu, 19 Sep 2024 14:23:45 +0200
Subject: [PATCH 031/217] ssh: missing subsys_sup to connection_sup rename
---
lib/ssh/src/ssh_info.erl | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/ssh/src/ssh_info.erl b/lib/ssh/src/ssh_info.erl
index 10c3a0e07c89..e2f9d2ad2604 100644
--- a/lib/ssh/src/ssh_info.erl
+++ b/lib/ssh/src/ssh_info.erl
@@ -140,7 +140,7 @@ format_sup(client,
Indent) when is_reference(Ref) ->
[io_lib:format("~sLocal: ~s~n"
"~sRemote: ~s (Version: ~s)~n"
- "~sConnectionRef=~s, subsys_sup=~s~n",
+ "~sConnectionRef=~s, connection_sup=~s~n",
[indent(Indent), local_addr(ConnPid),
indent(Indent), peer_addr(ConnPid), peer_version(client,ConnPid),
indent(Indent), print_pid(ConnPid), print_pid(ConnSup)
@@ -157,7 +157,7 @@ format_sup(server,
},
Indent) when is_reference(Ref) ->
[io_lib:format("~sRemote: ~s (Version: ~s)~n"
- "~sConnectionRef=~s, subsys_sup=~s~n",
+ "~sConnectionRef=~s, connection_sup=~s~n",
[indent(Indent), peer_addr(ConnPid), peer_version(server,ConnPid),
indent(Indent), print_pid(ConnPid), print_pid(ConnSup)
]),
From 69774e766137b821f8facfad7349a7b2f36b31fc Mon Sep 17 00:00:00 2001
From: Jakub Witczak
Date: Thu, 19 Sep 2024 15:48:01 +0200
Subject: [PATCH 032/217] ssh: don't receive EXIT message on client side
---
lib/ssh/src/ssh_connection_handler.erl | 49 +++++++++++++++++---------
lib/ssh/test/ssh_protocol_SUITE.erl | 15 +++++---
2 files changed, 43 insertions(+), 21 deletions(-)
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 1c25e171ba5b..6502fed79849 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -120,12 +120,13 @@ start_link(Role, Id, Socket, Options) ->
Others
end.
-
-takeover(ConnPid, client, Socket, Options) ->
- group_leader(group_leader(), ConnPid),
- takeover(ConnPid, common, Socket, Options);
-
-takeover(ConnPid, _, Socket, Options) ->
+takeover(ConnPid, Role, Socket, Options) ->
+ case Role of
+ client ->
+ group_leader(group_leader(), ConnPid);
+ _ ->
+ ok
+ end,
{_, Callback, _} = ?GET_OPT(transport, Options),
case Callback:controlling_process(Socket, ConnPid) of
ok ->
@@ -135,7 +136,7 @@ takeover(ConnPid, _, Socket, Options) ->
Options,
?GET_OPT(negotiation_timeout, Options)
),
- handshake(ConnPid, Ref, NegTimeout);
+ handshake(ConnPid, Role, Ref, NegTimeout);
{error, Reason} ->
{error, Reason}
end.
@@ -490,25 +491,41 @@ init_ssh_record(Role, Socket, PeerAddr, Opts) ->
}
end.
-
-handshake(Pid, Ref, Timeout) ->
+handshake(ConnPid, server, Ref, Timeout) ->
receive
- {Pid, ssh_connected} ->
+ {ConnPid, ssh_connected} ->
erlang:demonitor(Ref, [flush]),
- {ok, Pid};
- {Pid, {not_connected, Reason}} ->
+ {ok, ConnPid};
+ {ConnPid, {not_connected, Reason}} ->
erlang:demonitor(Ref, [flush]),
{error, Reason};
- {'DOWN', Ref, process, Pid, {shutdown, Reason}} ->
+ {'DOWN', Ref, process, ConnPid, {shutdown, Reason}} ->
{error, Reason};
- {'DOWN', Ref, process, Pid, Reason} ->
+ {'DOWN', Ref, process, ConnPid, Reason} ->
{error, Reason};
{'EXIT',_,Reason} ->
- stop(Pid),
+ stop(ConnPid),
{error, {exit,Reason}}
after Timeout ->
erlang:demonitor(Ref, [flush]),
- ssh_connection_handler:stop(Pid),
+ ssh_connection_handler:stop(ConnPid),
+ {error, timeout}
+ end;
+handshake(ConnPid, client, Ref, Timeout) ->
+ receive
+ {ConnPid, ssh_connected} ->
+ erlang:demonitor(Ref, [flush]),
+ {ok, ConnPid};
+ {ConnPid, {not_connected, Reason}} ->
+ erlang:demonitor(Ref, [flush]),
+ {error, Reason};
+ {'DOWN', Ref, process, ConnPid, {shutdown, Reason}} ->
+ {error, Reason};
+ {'DOWN', Ref, process, ConnPid, Reason} ->
+ {error, Reason}
+ after Timeout ->
+ erlang:demonitor(Ref, [flush]),
+ ssh_connection_handler:stop(ConnPid),
{error, timeout}
end.
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index 425d78f20b4e..7b8d4e9767be 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -1250,18 +1250,23 @@ find_handshake_parent([{{ssh_acceptor_sup,{address,_,Port,_}},
Port, {AccP,AccC,AccH}) ->
ParentHandshakers =
[{PidW,PidH} ||
- {{ssh_acceptor_sup,{address,_,Port1,_}}, PidW, worker, [ssh_acceptor]} <-
- supervisor:which_children(PidS),
+ {{ssh_acceptor_sup,{address,_,Port1,_}}, PidW, worker,
+ [ssh_acceptor]} <- supervisor:which_children(PidS),
Port1 == Port,
PidH <- element(2, process_info(PidW,links)),
is_pid(PidH),
- process_info(PidH,current_function) == {current_function,{ssh_connection_handler,handshake,3}}],
+ process_info(PidH,current_function) ==
+ {current_function,
+ {ssh_connection_handler,handshake,4}}],
{Parents,Handshakers} = lists:unzip(ParentHandshakers),
find_handshake_parent(T, Port, {AccP++Parents, AccC, AccH++Handshakers});
-find_handshake_parent([{_Ref,PidS,supervisor,[ssh_connection_sup]}|T], Port, {AccP,AccC,AccH}) ->
+find_handshake_parent([{_Ref,PidS,supervisor,[ssh_connection_sup]}|T],
+ Port, {AccP,AccC,AccH}) ->
Connections =
- [Pid || {connection,Pid,worker,[ssh_connection_handler]} <- supervisor:which_children(PidS)],
+ [Pid ||
+ {connection,Pid,worker,[ssh_connection_handler]} <-
+ supervisor:which_children(PidS)],
find_handshake_parent(T, Port, {AccP, AccC++Connections, AccH});
find_handshake_parent([_|T], Port, Acc) ->
From f36d1c8a52b973a6af40f56829a6f02999c1670e Mon Sep 17 00:00:00 2001
From: Jakub Witczak
Date: Fri, 20 Sep 2024 14:54:42 +0200
Subject: [PATCH 033/217] ssh: fix Opts creation in ssh_acceptor:listen
This was [{active, false}, {reuseaddr,true} | ?GET_OPT(socket_options,
Options)] in ssh_acceptor, which is wrong. For one, it would prevent
the usage of option inet_backend since this option must be the first
in the list. For another, in options given to gen_tcp or ssl, the last
option wins, such that if for example {active, true} was in the list
of given socket options, it would be set to {active, true} despite the
tacked-on {active, false}.
Co-authored-by: Maria Scott
Co-authored-by: Jan Uhlig
---
lib/ssh/src/ssh_acceptor.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index fcd37445cce6..a558a888d2c2 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -48,7 +48,7 @@ start_link(SystemSup, Address, Options) ->
%%%----------------------------------------------------------------
listen(Port, Options) ->
{_, Callback, _} = ?GET_OPT(transport, Options),
- SockOpts = [{active, false}, {reuseaddr,true} | ?GET_OPT(socket_options, Options)],
+ SockOpts = ?GET_OPT(socket_options, Options) ++ [{active, false}, {reuseaddr,true}],
case Callback:listen(Port, SockOpts) of
{error, nxdomain} ->
Callback:listen(Port, lists:delete(inet6, SockOpts));
From 8c60e465fc7c3e1c8777dcb27d81958e2d4e2d6b Mon Sep 17 00:00:00 2001
From: Jakub Witczak
Date: Wed, 25 Sep 2024 08:02:05 +0200
Subject: [PATCH 034/217] common_test: update jquery
- jQuery update to 3.7.1
---
lib/common_test/priv/jquery-latest.js | 156 +-------------------------
1 file changed, 2 insertions(+), 154 deletions(-)
diff --git a/lib/common_test/priv/jquery-latest.js b/lib/common_test/priv/jquery-latest.js
index ac7e7009dc9f..7f37b5d99122 100644
--- a/lib/common_test/priv/jquery-latest.js
+++ b/lib/common_test/priv/jquery-latest.js
@@ -1,154 +1,2 @@
-/*!
- * jQuery JavaScript Library v1.4.2
- * http://jquery.com/
- *
- * Copyright 2010, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * Includes Sizzle.js
- * http://sizzlejs.com/
- * Copyright 2010, The Dojo Foundation
- * Released under the MIT, BSD, and GPL Licenses.
- *
- * Date: Sat Feb 13 22:33:48 2010 -0500
- */
-(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
-Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
-(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
-a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
-"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
-function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;ba ";
-var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
-parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
-false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML=" ";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
-s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
-applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
-else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
-a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
-w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
-cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
-c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
-a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
-function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
-k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
-C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type=
-e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
-f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
-if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
-e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
-"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
-d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
-e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
-t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
-g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
-CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
-g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
-text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
-setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
-h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
-"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
-h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l ";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
-q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=" ";
-if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="
";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
-(function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
-function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
-{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
-"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
-d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
-a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
-1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"+d+">"},F={option:[1,""," "],legend:[1,""," "],thead:[1,""],tr:[2,""],td:[3,""],col:[2,""],area:[1,""," "],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
-c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
-wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
-prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
-this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
-return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
-""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
-return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
-""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
-c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
-c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
-function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
-Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
-"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
-a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
-a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/